箭头函数特点
this指向
普通函数 this 永远指向函数的调用者。(注意匿名函数)
箭头函数中,this指向的是定义时所在的对象,而不是使用时所在的对象。箭头函数中不会创建自己的this,而是会从自己作用域链的上一层继承this。
function Timer() {
this.s1 = 0;
this.s2 = 0;
setInterval(() => this.s1++, 1000); // 箭头函数没有自己的this,会从自己作用域链的上一层继承this。此时this指向Timer
setInterval(function () {
this.s2++; // 在普通函数中,此时this指向window
}, 1000);
}
let timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100); // 3.1秒后输出s1: 3
setTimeout(() => console.log('s2: ', timer.s2), 3100); // 3.1秒后输出s2: 0
const Person = {
'name': 'kingx',
'age': 18,
'sayHello': function () { // sayHello()函数中的this会指向函数的调用体,即Person本身
setTimeout(() => {
console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
}, 1000);
}
};
Person.sayHello(); // 我叫kingx,我今年18岁!
const Person2 = {
'name': 'little bear',
'age': 18,
'sayHello': () => { // sayHello()函数中的this会指向外层作用域,而Person2的父作用域就是全局作用域window
setTimeout(() => {
console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
}, 1000);
}
};
Person2.sayHello(); // 我叫undefined,我今年undefined岁!
不支持call()、apply()
原因:调用call()函数与apply()函数可以改变一个函数的执行主体,即改变被调用函数中this的指向。但是箭头函数却不能达到这一点,因为箭头函数并没有自己的this,而是继承父作用域中的this。
let adder = {
base: 1,
add: function (a) {
var f = (v) => v + this.base
return f(a)
},
addThruCall: function (a) {
var b = {
base: 2,
}
var f = (v) => v + this.base
return f.call(b, a) // 并不会改变箭头函数f中this的指向,this仍然指向adder,而且会接收参数a,b没有任何作用被忽略掉
},
}
console.log(adder.add(1)) // 2
console.log(adder.addThruCall(1)) // 2
不绑定arguments
在普通的function()函数中,可以通过arguments对象来获取到实际传入的参数值。
但是在箭头函数中,却无法做到这一点,同样也就无法使用caller和callee属性。
const fn = () => {
console.log(arguments);
};
fn(1, 2); // Uncaught ReferenceError: arguments is not defined
虽然无法通过arguments来获取实参,但是可以借助rest运算符(…)来达到这个目的。
const fn = (...args) => {
console.log(args);
};
fn(1, 2); // [1, 2]
支持嵌套
const pipeline = (...funcs) => (val) => funcs.reduce((a, b) => b(a), val) // 返回一个函数
const plus1 = (a) => a + 1
const mult2 = (a) => a * 2
const addThenMult = pipeline(plus1, mult2)
addThenMult(5) // 相当于pipeline(plus1, mult2)(5) 12
箭头函数不适用场景
不适合作为对象的函数
如果使用箭头函数定义对象字面量的函数,那么其中的this将会指向外层作用域,并不会指向对象本身,因此箭头函数并不适合作为对象的函数。
const Person2 = {
'name': 'little bear',
'age': 18,
'sayHello': () => { // sayHello()函数中的this会指向外层作用域,而Person2的父作用域就是全局作用域window
setTimeout(() => {
console.log('我叫' + this.name + ',我今年' + this.age + '岁!')
}, 1000);
}
};
Person2.sayHello(); // 我叫undefined,我今年undefined岁!
不能作为构造函数,不能使用new操作符
构造函数是通过new操作符生成对象实例的,生成实例的过程也是通过构造函数给实例绑定this的过程,而箭头函数没有自己的this。因此不能使用箭头函数作为构造函数,也就不能通过new操作符来调用箭头函数。
// 普通函数
function Person(name) {
this.name = name;
}
var p = new Person('kingx'); // 正常
// 箭头函数
let Person = (name) => {
this.name = name
};
let p = new Person('kingx'); // Uncaught TypeError: Person is not a constructor
没有prototype属性
因为在箭头函数中是没有this的,也就不存在自己的作用域,因此箭头函数是没有prototype属性的。
let a = () => {
return 1;
};
function b(){
return 2;
}
console.log(a.prototype); // undefined
console.log(b.prototype); // {constructor: ƒ}
不能将原型函数定义成箭头函数
在给构造函数添加原型函数时,如果使用箭头函数,其中的this会指向全局作用域window,而并不会指向构造函数,因此并不会访问到构造函数本身,也就无法访问到实例属性,这就失去了作为原型函数的意义。
function Person(name) {
this.name = name
}
Person.prototype.sayHello = () => {
console.log(this); // window
console.log(this.name); // undefined
};
let p1 = new Person('kingx');
p1.sayHello();