Javascript面试题 - 中级

75 阅读4分钟

1. 执行上下文

1.1 什么是执行上下文

执行上下文描述了代码在执行期所处的环境,当代码执行时,就会创建一个执行上下文,包含了执行代码所需的信息。

  • 全局执行上下文(包含window对象和this对象)
  • 函数执行上下文(包含参数和arguments对象、局部变量、函数作用域链和this)

1.2 生命周期

  • 创建阶段
    • 创建变量对象
    • 创建作用域链
    • 确定 this
  • 执行阶段
    • 变量赋值
    • 运行代码
  • 销毁阶段
    • 执行上下文被弹栈

2. 作用域和作用域链

2.1 什么是作用域

作用域定义了变量和函数的可访问性

  • 全局作用域:在任何地方都可被访问
  • 函数作用域:函数内部的变量只能被函数内部和内部函数访问

2.1 什么是作用域链

  • 内部函数可访问函数自身上下文和外部函数上下文,直至全局执行上下文的过程,叫做作用域链;
  • 作用域链是在函数定义的时候确认的。

3. 闭包

  • 函数在声明的时候就确定了其作用域链,因此函数即使是在函数外部执行,依然可以访问在声明期间确定的作用域,这种现象就叫做闭包;
  • 闭包的缺点:在外部函数执行完毕之后,其内部变量引用因为闭包的存在,因此不会被垃圾回收,可能造成内存泄漏;
  • 避免内存泄漏:
    • 手动移除对引用的移除;
    • 避免不必要的全局变量
    • 避免循环引用

4. 原型和原型链

  • js中的每个对象其构造函数都有一个原型对象储存着共享属性和方法,由该构造函数实现的对象都有一个内部引用指向其构造函数的原型对象;
  • 原型链就是由原型对象连接而成的链式结构,访问对象属性和方法时候,js引擎会先在对象自身上寻找是否有属性和方法,自身找不到后会原型链逐层向上寻找,直到原型链顶端(Object.prototype)为止。

5. 继承

5.1 构造函数借用继承

  • 缺点:每次实例化对象时候会重新生成方法,无法实现方法公共的问题

5.2 原型链继承

  • 缺点:
    • 属性会被所有实例共享,因此可能会被污染;
    • 无法向父类构造函数传递参数。

5.3 组合继承

  • 结合构造函数继承和原型链继承
  • 缺点:
    • 通过子类原型添加父类实例对象的方法实现原型链的化会造成子类实例化对象父类构造函数指向两次(一次是构造函数call, 第二次是原型对象指向父类实例);
    • 通过子类原型指向父类原型会造成父类原型被污染。

5.4 原型式继承

  • 通过 Object.create 实例化
  • 缺点:
    • 有原型链的缺点

5.5 寄生组合式继承

结合组合继承和原型式继承的一个方式

  • 通过借用构造函数继承不可共享的属性;
  • 通过原型链和原型式方法实现继承共享的属性和方法。

6. 事件循环

事件循环是一种js调度异步(事件处理、用户交互、网络请求和定时器等)操作的机制。

  1. js引擎执行代码,全局上下文压入调用栈中;
  2. 同步任务按顺序执行
  3. 遇到异步任务,js将任务交给相应的web API执行,并继续执行调用栈的任务;
  4. 异步任务完成之后的回调会放到任务队列中;
  5. 事件循环不断检查调用栈是否为空,如果为空,就从异步队列中取出一个任务回调压入到调用栈执行;
  6. 然后重复上述流程,确保所有任务运行。

7. 宏任务和微任务

  • 在事件循环中,任务分为宏任务和微任务;
  • 宏任务完成之后,会先去执行微任务队列中的任务,然后进行其他的宏任务。

7.1 宏任务

  • setTimeout
  • setInterval
  • I/O 操作
  • UI 渲染

7.2 微任务

  • Promise的回调函数
  • MutationObserver

8. 异步编程

  • 回调函数
  • Promise
  • async/await
  • Generator函数
  • 事件驱动

9. 内存

  • js中的内存分成栈、堆和池;
  • 栈中放的是基本数据,堆中放的是引用数据,池是常量池。

10. 垃圾回收

10.1 垃圾回收机制

js中的垃圾回收机制是自动化的,不需要开发者显示的去释放内存。

  • 引用计数法
    • 缺点:无法解决循环引用的问题
  • 标记清除法