这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
箭头函数
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。
例
const materials = ['Hydrogen', 'Helium', 'Lithium', 'Beryllium']
console.log(materials.map((material) => material.length))
// expected output: Array [8, 6, 7, 9]
基础语法
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
//相当于:(param1, param2, …, paramN) =>{ return expression; }
// 当只有一个参数时,圆括号是可选的:
(singleParam) => { statements }
singleParam => { statements }
// 没有参数的函数应该写成一对圆括号。
() => { statements }
高级语法
//加括号的函数体返回对象字面量表达式:
params => ({foo: bar})
//支持剩余参数和默认参数
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
//同样支持参数列表解构
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
引入箭头函数主要有两个方面的作用:更简短的函数而且不绑定 this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的 this 与封闭函数中的this值相同:
function Person() {
this.age = 0
setInterval(() => {
this.age++ // |this| 正确地指向 p 实例
}, 1000)
}
var p = new Person()
通过call和apply调用
由于 箭头函数没有自己的 this 指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定 this),他们的第一个参数会被忽略。
var adder = {
base : 1,
add : function(a) {
var f = v => v + this.base;
return f(a);
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2
使用箭头函数作为方法
箭头函数作为方法时,由于没有定义this绑定,方法里指向里上一个作用链的作用域。下面是例子中指向的是全局作用域。
//使用箭头函数作为方法
var obj = {
a: 1,
b: () => {
console.log(this.a, this)
},
c: function () {
console.log(this.a, this)
},
}
//obj.b() //undefined {}
//上面是在node环境下运行的,在浏览器环境下运行会输出:undefined,window
//obj.c() //1 {a:1.b:[Function:b],c:[Function:c]}
Object.defineProperty(obj, 'b', {
get: () => {
console.log(this.a, typeof this.a, this)
return this.a++
},
})
//obj.b //undefined 'undefined' {}
//箭头函数不能用作构造器,和new一起用会报错
/*(var Foo = () => {}
var f = new Foo()*/
//箭头函数也没有prototype属性,同样报错
//箭头函数不能用作函数生成器。
还有几点注意:
- 箭头函数返回子面量对象时要加括号(这是因为花括号({} )里面的代码被解析为一系列语句(即 foo 被认为是一个标签,而非对象字面量的组成部分)。)
- 箭头函数的作用域注意,是局部作用域
// 常规写法
var greeting = () => {
let now = new Date()
return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined 标准的let作用域
// 参数括号内定义的变量是局部变量(默认参数)
var greeting = (now = new Date()) =>
'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined
// 对比:函数体内{}不使用var定义的变量是全局变量
var greeting = () => {
now = new Date()
return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // Fri Dec 22 2017 10:01:00 GMT+0800 (中国标准时间)
// 对比:函数体内{} 用var定义的变量是局部变量
var greeting = () => {
var now = new Date()
return 'Good' + (now.getHours() > 17 ? ' evening.' : ' day.')
}
greeting() //"Good day."
console.log(now) // ReferenceError: now is not defined
上面是 MDN 的例子。
- 同样的箭头函数还可以使用闭包和递归
箭头函数与匿名函数的区别
-
this 指向区别
- 箭头函数根据所在的环境(我在哪个环境中,this 就指向谁),Arrow functions bind the parent context。按照词法作用域绑定 this
- 匿名函数中 this 指向 window
使用箭头函数注意几点
-
1、函数体内的 this 对象就是定义时所在的对象,而不是使用时所在对象;
-
2、不可以当作构造函数使用,也就是不能用 new 命令实例化一个对象,否则会抛出一个错误;
-
3、不可以使用 arguments 对象,该对象在函数体内不存在,如果要用的话,可以用 rest 参数代替;
-
4、不可以使用 yield 命令,箭头函数不能用作 Generator 函数;