ES6+ 箭头函数
1. 前言
ES6 规定了可以使用 “箭头” =>
来定义一个函数,语法更加简洁。它没有自己的 this
、arguments
、super
或 new.target
,箭头函数表达式更适用于那些本来需要匿名函数的地方,但它不能用作构造函数。
2. this 指向
var title = "全局标题";
var imooc = {
title: "网 ES6 Wiki",
getTitle : function(){
console.log(this.title);
}
};
imooc.getTitle(); // 网 ES6 Wiki
var bar = imooc.getTitle;
bar(); // 全局标题
通过上面的小例子的打印结果可以看出 this
的问题,说明 this
的指向是不固定的。
这里简单说明一下 this
的指向,this
指向的是调用它的对象。例子中的 this
是在 getTitle 的函数中的,执行 imooc.getTitle()
这个方法时,调用它的对象是 imooc
,所以 this 的指向是 imooc
。
之后把 imooc.getTitle
方法赋给 bar
,这里要注意的是,只是把地址赋值给了 bar
,并没有调用。 而 bar
是全局对象 window
下的方法,所以在执行 bar
方法时,调用它的是 Window 对象,所以这里打印的结果是 window 下的 title——“全局标题”。
TIPS: 上面的示例只是简单的
this
指向问题,还有很多更加复杂的,在面试中经常会被问到,所以还不清楚的同学可以去研究一下this
的问题。
ES6 为了规避这样的问题,提出了箭头函数的解决方案,在箭头函数中没有自己的 this
指向,所有的 this 指向都指向它的上一层 this
,这样规定就比较容易理解了。下面看使用箭头函数下的 this
指向:
var title = "全局标题";
var imooc = {
title: "网 ES6 Wiki",
getTitle : () => {
console.log(this.title);
}
};
imooc.getTitle(); // 全局标题
var bar = imooc.getTitle;
bar(); // 全局标题
上面的打印结果可以看出来,所有的 this
指向都指向了 window 对象下的 title,本身的 imooc 对象下没有了 this
,它的上一层就是 window。
3. 语法详解
3.1 基本语法
3.2 有返回值
var sum = (num1, num2) => num1 + num2;
当传递的参数只有一个时,圆括号也可以省略:
var sum = num => num + ;
下面看个使用 map 求和的例子:
// ES5
[,,].map(function (x) {
return x * x;
});
// 等同于ES6
[,,].map(x => x * x);
对比 ES5 可以看出箭头函数的简洁表达,更加准确明了。
3.3 返回值是对象
如果函数体返回对象字面量表达式,可以省略大括号,使用圆括号的形式包裹对象。
var getimooc = () => ({a: , b: });
getimooc() // {a: 1, b: 2}
3.4 默认参数
var sum = (num1, num2 = ) => num1 + num2;
console.log(sum()) // 3
3.5 剩余参数
下面是剩余参数的例子:
var fun = (param1, param2, ...rest) => {
console.log(param1)
console.log(param2)
console.log(rest)
};
fun(, , , , );
// 1
// 2
// [3, 4, 5]
4. 没有 this
箭头函数不会创建自己的 this
,它只会从自己的作用域链的上一层继承 this
,setTimeout
会改变 this
的指向,看下面的示例:
// 在构造函数中
function Person(){
this.age = ;
setTimeout(function(){
console.log(this);
}, )
}
var p = new Person(); // Window: {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
function Person(){
this.age = ;
setTimeout(() => {
console.log(this);
}, );
}
var p = new Person(); // Person: {age: 0}
第一个例子中的 setTimeout
的回调函数使用 function
来定义的,从打印的结果可以看出 this
的指向是 window
对象也就是全局作用域。而第二个示例中 setTimeout
的回调函数使用箭头函数来定义,打印的结果可以看到,this
的指向是 Person
.
一个实例: 定义为一个构造函数 Person
,在函数中定义一个 imooc 对象,使用 function
关键字和箭头函数的方式给 imooc 上添加 getValue
方法,最后返回 imooc 对象,这时候我们来观察 getValue
内的 this
指向问题。
function Person(){
var imooc = {};
imooc.num = ;
imooc.getValue = () => {
console.log(this)
}
return imooc;
}
var p = new Person();
p.getValue()
// person {}
上面的示例中,构造函数中 imooc.getValue
方法使用的是箭头函数定义的,所以 getValue
方法不会有 this 的指向,它会根据作用域链向上查找到 Person
构造函数,所以这里的 this
的指向是 Person
。
function Person(){
var imooc = {};
imooc.num = ;
imooc.getValue = function() {
console.log(this)
}
return imooc;
}
var p = new Person();
p.getValue()
// {num: 10, getValue: ƒ} this指向的是 p 的返回值
上面的示例中,构造函数中 imooc.getValue
方法是使用 function
定义的,所以 getValue
中 this 的指向是动态的,指向调用它的那个对象。在 new Person()
时,会返回 imooc 对象赋给实例 ,在使用 p 去调用 getValue()
时 this
的指向就是 p 实例。
总结: 箭头函数的 this 永远指向的是父级作用域。
5. 不绑定 arguments
var fun = function() {
console.log(arguments)
};
fun(,,); // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
var fun = () => {
console.log(arguments)
};
fun(,,); // Uncaught ReferenceError: arguments is not defined
function foo(...args) {
console.log(args)
}
foo(); // [1]
foo(, , ); // [1, 2, 3]
6. 其他注意点
6.1 不能用作构造器
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
6.2 没有 prototype 属性
var Foo = () => {};
console.log(Foo.prototype); // undefined
6.3 不能使用 yield 命令
7. 小结
本节主要讲解了 ES6 的箭头函数,总结了以下几点: