html+css+js面试题

1 js的预解析问题

题目

function fn(a,c){
  console.log(a); //function a()
  var a =123;
  console.log(a); //变量的值123
  console.log(c); //function c()
  function a(){}
  if(false){
    var d = 678;
  }
  console.log(d); // 没有声明 undefined
  console.log(b); // undefined
  var b = function(){}
  console.log(b);// function (){}
  function c(){}
  console.log(c); // function c(){}
}
fn(1,2);

这道题考察的是js变量的预解析。
步骤是:

  1. 创建ao对象
  2. 找形参和变量声明 作为ao对象的属性名 值是undefined
  3. 实参和形参统一
  4. 找到函数声明 覆盖变量的声明

对于问题来说第一步 创建ao对象

ao:{
}

找形参和变量声明 作为ao对象的属性名 值是undefined

ao:{
	a: undefined,
	c: undefined,
	b: undefined,
	d: undefined
}

实参和形参统一 传入的参数是1和2 所以把a c的值换成传入的值

ao:{
	a: 1,
	c: 2,
	b: undefined,
	d: undefined
}

最后 找到函数声明 覆盖变量的声明

ao:{
	a: function(){}, 
	c: function(){},
	b: undefined,
	d: undefined
}

2 有关this的问题

在函数中中直接使用

function get (content){
	console.log(content)
}
get('hello')

get.call(window,'hello')

get(‘hello’) 的写法 本质上来说是get.call(window,‘hello’)的语法糖

函数作为对象的方法被使用(谁调用我 我就指向谁)

var person ={
	name='',
	run(){
		console.log(this.name+'在跑步');
	}
}
person.run();
person.run.call(pserson)

面试题

var name =222
var a ={
  name:111,
  say(){
    console.log(this.name);
  }
}

var fun = a.say
fun() //222 属于第一种情况函数直接调用 fun.call(window)
a.say() //111 属于第二种情况 a.say.call(a)

var b ={
  name: 333,
  say(fun){
    fun() //本质上和 fun接收a.say再通过fun()执行类似
  }
}

b.say(a.say); //222 属于第一种情况函数直接调用 fun.call(window)
b.say = a.say
b.say() //333 属于第二种情况 b.say.call(b)

3 箭头函数中的this

  • 箭头函数的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。

  • 箭头函数中,this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

  • 建箭头函数的this是定义函数的时候绑定

    var x = 11;
    var obj ={
    	x: 22,
    	say: ()=>{
    		console.log(this.x); //这里的外层指的并不是obj
    	{
    }
    obj.say(); // 11
    
  • 所谓的定义时候绑定,就是this是继承自父执行上下文中的this,比如这里的箭头函数中的this.x,箭头函数本身与say平级,也就是箭头函数本身所在的对象为obj,而obj的父执行上下文就是window,因此这里的this.x实际上表示的是window.x ,因此输出的是11。

    var obj = {
    	birth:1990,
    	getAge: function (){
    		var b = this.birth; 
    		var fn = () => new Date().getFullYear() - this.birth; 
    		return fn();
    	}
    }
    obj.getAge();
    
  • 例子中箭头函数本身是在getAge方法中定义的,因此,getAge方法的父执行上下文是obj,因此这里的this指向则为obj对象

4 深拷贝 浅拷贝

深拷贝浅拷贝与赋值的区别

  • 当我们把一个对象赋值给一个新的变量时,赋值的其实是对对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储内存的内容,因此,两个对象是联动的。
  • 浅拷贝:重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享一块内存,会互相影响、
  • 深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。

浅拷贝的实现方式

  • Object.assign()
  • lodash 里面的 _.clone
  • …展开运算符
  • Array.prototype.concat
  • Array.proptype.slice

深拷贝的实现

  • JSON.parse(JSON.stringify())
  • 递归操作
  • cloneDeep

5 防抖函数

当持续触发事件 一定时间内没有再触发事件 事件处理函数才会执行一次
如果设定的时间到来之前 又一次触发了事件 就重新开始延时

连续输入的时候不会输出,当一秒以上为输入时,打印输入结果

const input = document.getElementById('input');
let timer ;
input.addEventListener('keyup',(e)=>{
  clearTimeout(timer);
  timer = setTimeout(() => {
      console.log(e.target.value);
  }, 1000);
})

采用闭包的方式实现

const input = document.getElementById('input');
let timer ;
const deounce=(delay)=>{
  let timer;
  return (value)=>{
    clearTimeout(timer)
    timer = setTimeout(() => {
      console.log(value);
    }, delay);
    
  }
}
const getV = deounce(1000)
input.addEventListener('keyup',(e)=>{
  getV(e.target.value)
}) 

6 节流函数

当持续触发事件的时候,保证一段时间内,只调用一次事件处理函数,一段时间内只做一件事
经典的案例就是鼠标不断点击,规定在n秒内多次点击只有一次生效

{
  const btn = document.getElementById('button');
  const jiuliu = (delay) =>{
    let timer;
    return (backcall)=>{
      if(!timer){
        timer = setTimeout(() => {
          backcall();
          timer=null
        }, delay);
      }
    }
  }
  const a = jiuliu(2000)
  btn.addEventListener('click',()=>{
    a(()=>{
      console.log(Math.random());
    })
  })
}

上面的例子就是用闭包形成的节流函数,两秒内只会触发一次函数

7 js作用域

作用域的深层次理解
执行器的上下文

  • 当函数代码执行的前期 会创建一个执行期上下文的内部对象AO(作用域)
  • 这个内部的对象是预编译的时候创建出来的 因为当函数被调用的时候 会先进行预编译
  • 在全局代码的前期会创建一个执行器的上下文的对象GO
    函数作用域预编译
  • 创建ao对象 AO{}
  • 找形参和变量声明 将变量和形参名 当做AO对象的属性名值为undefined
  • 形参实参想统一
  • 在函数体里面找函数声明 值赋予函数体
    全局作用域的预编译
  • 创建 GO对象
  • 找变量声明 将变量名作为GO对象的属性名 值是undefined
  • 找函数声明 值赋予函数体

8 arguments是什么

接收参数

function a() {
  console.log(arguments);
}

a(1,2,3);

在这里插入图片描述
是一个伪数组 可以通过[…]展开符的方式转换为真正的数组
箭头函数没有arguments

9那些操作会造成内存泄漏

  • 闭包
  • 意外的全局变量
  • 没有清除的定时器
  • 脱离dom的引用

10 手写map

const array = [1,2,3];

function map(arr,callback) {
  let newArr = []
  for(let i =0 ;i<arr.length;i++){
    newArr = [...newArr,callback(arr[i],i)]
  }
  return newArr;
}

const a = map(array,(value,index)=>{
  return value*2
})
console.log(a);

11 单例模式

定义: 只有一个实例 可以全局访问
主要解决: 一个全局使用的类,频繁的创建和销毁
何时使用:当你想控制实例的数目,节省系统化资源的使用
如何实现:判断系统是否已经有这个单利 如果有则返回 没有则创建
单利模式的优点:内存中只要一个实例 减少了内存的开销 尤其是频繁的创建和销毁实例(比如说是首页页面的缓存)
使用场景 : 全局的缓存 弹窗
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值