面试备战录

0 阅读4分钟

1、var、const、let 区别

答:var、const、let是 js 中声明变量的三种方式,它们在作用域、变量提升、是否可重复声明、是否可修改等方面有着明显的区别;

  • 块级作用域:在{}内(包括 for、if、while、函数体内)定义的变量在{}取不到;
  • 函数作用域:在函数内部定义的变量,在函数外部取不到;
  • 变量提升:在代码执行前,JS 引擎会把变量的声明提前到作用域顶部,但不会提升赋值;
  • 重复声明:在同一个作用域内,用同一个名字声明变量超过一次;
  • 可修改:这里指定义的变量是否能被再次赋值;
  • 作用域链:内层的代码块可以访问外层块(或全局)声明的变量。
// 函数作用域 和 块级作用域
function foo() {
  if (true) {
    var a = 1; // 函数作用域
    let b = 2; // if{}内 块级作用域
  }
  console.log(a); // 2
  console.log(b); // 报错
}
  • const:块级作用域、提升变量、不能重复声明、不可修改、未声明前不能访问;
// 未声明前不能访问
console.log(a); // 会报错,Cannot access 'a' before initialization
const a = 1;
// 不能重复声明
const a = 1; // 会报错, Identifier 'a' has already been declared
// 不能修改
const a = 3;
  • let:块级作用域、提升变量、不能重复声明、可修改、未声明前不能访问;
  • var:函数作用域、提升变量、可以重复声明、可修改、未声明前能访问(为 undefined)、自动挂载到全局对象 window。

注:对象的 {} 不是作用域

2、箭头函数与普通函数的区别

  • this指向不同:
    • 普通函数:普通函数的this指向的是调用者对象;使用call / apply / bind也可以改变 this 指向。
     const obj = {
    name: '张三',
    say() {
      console.log(this.name); // 张三
    }
    };
    obj.say(); // 这里的this指向的就是 obj
    function foo() {
    let name = '张三';
    console.log(this.name); // undefined 由于let定义的变量不会挂载到window上所以 window上没有name属性
    }
    foo(); // 这里相当于 window.foo(),this指向的就是 window
    
    // 注意这里就算使用var定义name打印出来的也是 undefined
    function foo() {
      var name = '张三';
      // name = '张三'; 这里如果直接写 name = '张三';是 隐式地往 window 对象上挂了一个全局变量(不建议)
      console.log(name); // ✅ 输出 '张三'
      console.log(this.name); // undefined,这里 var 声明的变量是作用于函数作用域,而不会挂在 window 上。
    }
    foo();
    
    • 箭头函数:箭头函数没有自己的this,它的this继承至初始时他的环境决定。
    const obj = {
      // 对象字面量的花括号不是作用域,不影响箭头函数 this 的继承
      name: '大人',
      say: () => {
        console.log(this.name); // 这里this 指向初始时它的环境也就是 window
      }
    };
    obj.say(); // 输出 undefined
    
    • 箭头函数不能作为构造函数(不能用 new 调用),箭头函数没有自己的 this,没办法改变 this 指向;也 prototype 属性没办法新对象的__prototype__赋值;
    • 箭头函数没有 arguments 参数,普通函数有,但是可以使用 ...args 获取;
    function fn() {
      console.log(arguments); // 类数组对象 { '0': 1, '1': 2, '2': 3 }
     }
     fn(1, 2, 3); // 输出 Arguments(3) [1, 2, 3]
    
     const fn1 = (...args) => {
       console.log(args); // 数组 [ 1, 2, 3 ]
     };
     fn1(1, 2, 3);
    
    • 箭头函数不能使用 this/super/new.target 这些关键字,适用于函数内部逻辑更“轻量”的场景,比如 map、filter、事件处理器中的 this 绑定等;
    • 箭头函数语法相对简洁。

3、async await 作用

答:asyncawait 是 ES2017(ES8)引入的用于处理异步操作的语法糖。

  • 回调地狱:多个异步操作依赖前一个的结果,层层嵌套回调函数。
  • async:用来声明一个函数是异步的,函数内部可以使用 await。这个函数返回一个 Promise,无论函数内部返回的是什么,都会被包装成 Promise。
  • await: 只能在 async 函数内部使用用来等待一个 Promise 对象的结果,暂停函数执行,直到 Promise 解决(resolve)或拒绝(reject),让异步操作写起来像同步操作。

4、ES6 的新特性

  • let / const:块级作用域变量声明
  • 箭头函数()=>{}:简洁语法,this 绑定
  • 模板字符串:${} 插值,支持多行
  • 解构赋值:快速提取对象/数组值
  • 默认参数:函数参数默认值function(type=1){}
  • 展开运算符 ...:拷贝、合并、剩余参数
  • Promise:支持异步编程
  • class:类的语法糖
  • 模块化import/export:支持模块导入导出