目录
# 前言
箭头函数和普通函数相比有什么区别?这是一道高频面试题。箭头函数用起来很香,但许多人对它的理解还不够深入,很容易就被考倒。认真看完这篇文章,相信你会有一个更清晰的认知。
# 定义方式
# 普通函数
定义普通函数的方式通常有函数声明和函数表达式:
// 函数声明
function test() {}
// 函数表达式
const test = function() {};
# 箭头函数
箭头函数是普通函数的语法糖,书写要更加简洁:
const test = () => {};
# this 指向
# 普通函数
严格模式下,this 指向 undefined:
'use strict';
function test() {
console.log(this); // undefined
}
非严格模式下,this 指向 window:
function test() {
console.log(this); // window
}
谁调用函数,函数内部的 this 就指向谁:
const obj = {
x: 1,
fn: function() {
console.log(this); // obj
},
};
obj.fn();
普通函数中的 this 指向是动态的:
function fn() {
console.log(this); // obj
}
const obj = {
x: 1,
};
const fn1 = fn.bind(obj);
fn1();
上栗中,fn 函数中的 this 本应指向 window,后面我们通过 bind 方法将函数的 this 指向改变为了 obj 对象,所以打印出 obj。
可以看出,普通函数的 this 指向可以通过 bind、call、apply 等方法进行改变,this 指向是动态的。
# 箭头函数
无论是严格模式还是非严格模式下,this 始终指向 window:
'use strict';
const test = () => {
console.log(this); // window
};
const test = () => {
console.log(this); // window
};
箭头函数没有自己的执行上下文,this 指向是在定义函数时就被确定下来的,箭头函数中的 this,永远指向外层作用域中最接近自己的普通函数的 this:
const obj = {
x: 1,
fn: function() {
console.log(this); // obj
const test = () => {
console.log(this); // obj
};
test();
},
};
obj.fn();
上栗中,普通函数 fn 作为 obj 的属性被调用,谁调用普通函数,那么函数中的 this 就指向谁,所以 fn 的 this 指向 obj。 fn 函数内部有一个箭头函数 test,test 没有自己的 this,它的 this 指向外层作用域中最接近自己的普通函数的 this,所以 test 中的 this 也指向 obj。 箭头函数会忽略任何形式的 this 指向的改变,箭头函数的 this 指向是静态的:
const obj = {
x: 1,
};
const fn = () => {
console.log(this); // window
};
const fn1 = fn.bind(obj);
fn1();
bind、call、apply 等方法无法改变箭头函数的 this 指向。
# 构造函数
# 普通函数
通过 new 关键字调用普通函数(作为构造函数),this 指向被创建出来的对象实例:
function fn(name, age) {
this.name = name;
this.age = age;
console.log(this); // {name: '吴彦祖', age: 18}
}
new fn('吴彦祖', 18);
# 箭头函数
箭头函数不能当做构造函数来使用:
const test = () => {};
new test(); // error: test is not a constructor
# arguments 对象
# 普通函数
在普通函数中,arguments 是类数组对象,保存着函数执行时传入的参数:
function fn(x, y) {
console.log(arguments); // {0: 1, 1: 2, length: 2}
}
fn(1, 2);
# 箭头函数
箭头函数没有 arguments:
const test = (x, y) => {
console.log(arguments); // error: arguments is not defined
};
test(1, 2);
# 补充
- 箭头函数没有 prototype 属性
- 箭头函数不能当做 Generator 函数,不能使用 yield 关键字
- 箭头函数不能被 new 关键字调用,不具有 new.target
