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 作用
答:async
和 await
是 ES2017(ES8)引入的用于处理异步操作的语法糖。
- 回调地狱:多个异步操作依赖前一个的结果,层层嵌套回调函数。
- async:用来声明一个函数是异步的,函数内部可以使用
await
。这个函数返回一个 Promise,无论函数内部返回的是什么,都会被包装成 Promise。 - await: 只能在 async 函数内部使用用来等待一个 Promise 对象的结果,暂停函数执行,直到 Promise 解决(resolve)或拒绝(reject),让异步操作写起来像同步操作。
4、ES6 的新特性
- let / const:块级作用域变量声明
- 箭头函数
()=>{}
:简洁语法,this 绑定 - 模板字符串:
${}
插值,支持多行 - 解构赋值:快速提取对象/数组值
- 默认参数:函数参数默认值
function(type=1){}
- 展开运算符
...
:拷贝、合并、剩余参数 - Promise:支持异步编程
- class:类的语法糖
- 模块化
import/export
:支持模块导入导出