前端面试要点(一):JavaScript

266 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

前言

在面试和复习过程中总结的一些前端知识点,记录下来,风格较简洁,尽量涵盖内容要点和简单例子。本文是前端面试系列第一篇:JavaScript 相关知识点,持续更新...

一、解释一下原型链

  • 每个函数都有 prototype 属性,该属性指向原型;
  • 每个对象都有 __proto__[[prototype]] 属性,指向了创建该对象的构造函数的原型;
  • __proto__ 将对象连接起来组成了原型链;
  • 原型链的意义是便于继承。

二、列举 es5 实现继承的两种方法

  1. 原型链:对象去寻找自己的属性的时候,先在自己的当前对象上寻找,如果没有,就去自己的原型链上寻找,一直顺着原型链向上寻找直到找到 null;

  2. Object.create:其实就是原型继承的变种:

    let child = Object.create(father)

三、谈谈对作用域的理解

作用域分为三类:

  1. 全局作用域:任何地方都能访问到,如最外层变量、未定义直接赋值的变量、window 的属性;
  2. 函数作用域:声明在函数内部的变量,只在函数内部可访问;
  3. 块级作用域:通过 let 和 const 声明,块级作用域限制在一对花括号内部;

ES6 之前 JavaScript 没有块级作用域;

作用域链

当调用一个函数时,以当前函数的作用域作为开头,从内向外一层一层的把函数作用域链在一起,形成作用域链

作用域执行上下文 的区别:

  • 执行上下文在运行时确定,随时可能改变
  • 作用域在定义时就确定,并且不会改变

四、闭包的原理和意义

  • 原理: 一般情况下,函数在调用完成之后,它的执行上下文环境会被销毁,但是闭包的核心内容就是阻止这样的事情发生,它会把需要用到的变量保存在堆上。
  • 意义
    1. 延长变量的生命周期
    2. 创建私有环境,相当于 es6 的 class

五、this的指向

函数中的 this 的值取决于函数调用的模式:

  • 当函数作为对象的方法时,this 的值为该对象;
  • 匿名函数或不处于任何对象中的函数,this 指向 window;
  • 使用 new 调用的函数,this 将会被绑定到新构造的对象;
  • apply 或 call 方法调用时, this 指向第一个参数。

六、什么是立即执行函数

立即执行函数 就是立即调用的匿名函数,形如:

(function() {
    ...
})()

目的 是为了隔离函数作用域,防止变量定义外泄,相当于在 es5 中模拟 es6 的块级作用域。

七、instanceof 的原理

通过判断对象的原型链中是不是能找到类型的 prototype

八、call 和 apply 的作用和区别

  • 作用是相同的,callapply 都是为了 改变 this 的指向
  • 传参的方式 不同:
    1. call 可以接收一个参数列表:
    function.call(thisArg, arg1, arg2, ...)
    
    1. apply 只接受一个参数数组:
    function.apply(thisArg , [ argsArray])
    

九、柯里化

柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。

参考:juejin.cn/post/684490…

十、v8 垃圾回收机制

GC 算法采用了 分代式 垃圾回收机制,V8 将内存(堆)分为 新生代老生代 两部分。

  • 在新生代空间中,内存空间分为两部分,分别为 From 空间To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。
  • 经历过一次新生代算法的对象会被移到老生代内存中,老生代采用 标记整理清除 算法。在这个阶段中,会遍历堆中所有的对象,然后标记活的对象,在标记完成后,整理活的对象放在一块连续的内存,最后销毁所有没有被标记的对象。先整理再清除的好处是在整理对象时就可覆盖掉一些垃圾,最后清除时可以减少一些垃圾。

十一、0.1+0.2 为什么不等于 0.3

这是浮点数精度问题,因为 JS 采用 IEEE 754 双精度版本(64 位),六十四位中符号位占一位,整数位占十一位,其余五十二位都为小数位,二进制相加后转化为十进制为 0.30000000000000004

十二、new 操作符做了什么

  1. 创建一个空对象
  2. 将空对象的 __proto__ 指向构造函数的 prototype
  3. 绑定 this,执行构造函数
  4. 返回新对象

十三、谈谈事件循环机制

  • js 是单线程的,但是浏览器是多线程的。
  • 事件循环就是在事件驱动模式中来管理和执行事件的一套流程。
  • js 是没有事件循环这个概念的,事件循环是针对浏览器的,当然 node 环境也有事件循环。
  • 事件触发的异步任务暂时存在队列中,等待 js 同步任务执行完后从队列中取出事件处理,事件循环机制决定什么时候取,优先取哪个任务。
  • js 的同步任务存放在执行栈中,由 js 主线程处理,遇到异步任务交给其它线程处理,当同步任务完成后,会从队列中取出已完成的异步任务的回调加入到执行栈中,再遇到异步任务又交给其它线程,如此循环。
  • 任务队列又分为微任务队列和宏任务队列,微任务的优先级高于宏任务。

十四、Map 和 Object 的区别;Map 和 WeakMap 的区别

Map 和 Object 的区别:

  • Object 的键只能是 String 和 Symbol,Map 的键可以是任意类型的数据;
  • Map 初始时没有任何键,Object 初始时会有一些原型链上的键;

WeakMap 是 ES6 中新增的一种集合类型,叫做“弱映射”:

  • WeakMap 只接受对象作为键名;
  • WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收,因此不可遍历;

十五、Promise 原理

  • Promise 是 ES6 新增的语法,解决了回调地狱的问题。
  • 可以把 Promise 看成一个状态机。初始是 pending 状态,可以通过函数 resolve 和 reject ,将状态转变为 resolved 或者 rejected 状态,状态一旦改变就不能再次变化。
  • then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。

十六、ES6 相关

  • var 的弊端:变量提升、变量覆盖、没有块级作用域
  • const 声明之后必须赋值
  • 解构快速交换两个变量的值:
    [a, b] = [b, a]
    
  • 快速给数组去重:
    const arr2 = [...new Set(arr1)]