首先:我们先考虑一下这个箭头函数没有自己的this
,arguments
,super
或>首先:我们先考虑一下这个箭头函数没有自己的
this,
arguments,
super或
new.target`是什么意思?带着问题去看下面的内容会更事半功倍。
一、语法
1.基础语法
(参数1, 参数2, …, 参数N) => { 函数声明 }
//相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
(参数1, 参数2, …, 参数N) => 表达式(单一)
// 当只有一个参数时,圆括号是可选的:
(单一参数) => {函数声明}
单一参数 => {函数声明}
// 没有参数的函数应该写成一对圆括号。
() => {函数声明}
2.高级语法
//加括号的函数体返回对象字面表达式:
参数=> ({foo: bar})
//支持剩余参数和默认参数
(参数1, 参数2, ...rest) => {函数声明}
(参数1 = 默认值1,参数2, …, 参数N = 默认值N) => {函数声明}
//同样支持参数列表解构
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
二、没有自己的this
,不绑定this
我们先看一下下面的代码,
const Person = {
'name': 'little bear',
'age': 18,
'sayHello': function() {
setTimeout(function() {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
}
console.log(Person.sayHello()) //我叫我今年undefined岁!
打印的结果是undefined
,知道是什么原因吗?当然,setTimeout
方法里面的this
指向的是window
,所以是undefined
,sayhello方法中的this
才是指向Person的,如果按照下面的方式将sayHello中的this
赋值给封闭变量self,就可以正确打印结果了
const Person1 = {
'name': 'little bear',
'age': 18,
'sayHello': function() {
var self = this;
setTimeout(function() {
console.log('我叫' + self.name + '我今年' + self.age + '岁!')
}, 1000)
}
}
console.log(Person1.sayHello());//我叫little bear我今年18岁!
我们再看一下下面的代码,想想打印的结果是什么呢?
const Person3 = {
'name': 'little bear',
'age': 18,
sayHello() {
setTimeout(() => {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
}
console.log(Person3.sayHello());//我叫little bear我今年18岁!
这个结果是否如你所料呢?
我们再看看下面的代码就应该好理解了
const Person5 = {
'name': 'little bear',
'age': 18,
sayHello: () => {
setTimeout(() => {
console.log('我叫' + this.name + '我今年' + this.age + '岁!')
}, 1000)
}
}
Person5.sayHello();//我叫我今年undefined岁!
封闭函数的this
指向的是外部对象window
,setTimeout
继承上一层this
,所以也是指向的window
;
通过 call 或 apply 调用
首先我们回顾一下 call
跟 apply
他们各自的定义:
- apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
- call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
它们的共同之处:
都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象”。
它们的不同之处:
- apply:最多只能有两个参数——新this对象和一个数组argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里。如果argArray不是一个有效的数组或arguments对象,那么将导致一个TypeError。如果没有提供argArray和thisObj任何一个参数,那么Global对象将被用作thisObj,并且无法被传递任何参数。
- call:它可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表。这个方法主要用在js对象各方法相互调用的时候,使当前this实例指针保持一致,或者在特殊情况下需要改变this指针。如果没有提供thisObj参数,那么 Global 对象被用作thisObj。
我们先来看一下下面的代码,思考一下打印的结果,
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(而不是3 ——译者注)
结果:
三、不绑定arguments
我们都知道函数内部,argument
是一个作为函数输入的值-原始数据或对象
var arguments = [5, 6, 7];
function person1(a, b, c) {
console.log(arguments);
}
person1(1, 2);//arguments[1,2]
var arr1 = () => { return arguments; }
console.log(arr1());//[5,6,7]
var arr2 = (a) => { return arguments; }
console.log(arr2(1));//[5,6,7]
从上就可以看出,一般的函数是绑定了Arguments
对象,而箭头函数没有绑定
看下面的代码箭头函数中的arguments
只是引用了封闭作用域内的arguments
var arguments = [1, 2, 3];
var arr = () => arguments[0];
arr(); // 1
function foo(n) {
var f = () => arguments[0] + n; // 隐式绑定 foo 函数的 arguments 对象. arguments[0] 是 n
return f();
}
foo(1); // 2
四、使用 new 操作符
箭头函数不能用作构造器,和 new一起用会抛出错误。
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
五、使用prototype属性
箭头函数没有prototype属性。
var Foo = () => {};
console.log(Foo.prototype); // undefined
六、使用 yield 关键字
yield
关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作生成器。