先来看看箭头函数的基本语法:
let func = value => value;
// 相当于
let func = function (value) {
return value;
};
如果需要给函数传入多个参数:
let func = (value, num) => value * num;
如果函数的代码块需要多条语句:
let func = (value, num) => {
return value * num
};
如果需要直接返回一个对象:
let func = (value, num) => ({total: value * num})
与变量解构结合:
let func = ({value, num}) => ({total: value * num})
// 使用
var result = func({
value: 10,
num: 10
})
console.log(result); // {total: 100}
比较
比较一下箭头函数与普通函数的区别:
1. 没有this
2. 没有 arguments
3. 不能通过new 关键字调用
4. 没有new.target
5. 没有原型
6. 没有 super
1. 没有this
箭头函数没有this,所以需要通过查找作用域链来确定this的值。
这就意味着箭头函数被非箭头函数包含,this绑定的就是最近一层非箭头函数的this
模拟一个例子:
点击一个按钮,改变该按钮的背景色
为了方便开发, 我们抽离了一个Button组件,当需要使用的时候,直接可以用下面代码调用:
// 传入元素 id 值即可绑定该元素点击时改变背景色的事件
new Button("button")
HTML代码如下:
<button id="button">点击变色</button>
js代码如下:
// 箭头函数没有this,所以需要通过查找作用域链来确定this的值
function Button(id) {
this.element = document.querySelector("#" + id);
this.bindEvent();
}
Button.prototype.bindEvent = function() {
this.element.addEventListener("click", this.setBgColor, false);
// this.element.addEventListener("click", this.setBgColor.bind(this), false); // es5的解决办法
// this.element.addEventListener("click", (e) => {this.setBgColor(e)}, false);
};
Button.prototype.setBgColor = function() {
console.log(this);
this.element.style.backgroundColor = '#1abc9c'
};
var button = new Button("button");
点击按钮报错了
image.png
看着好像没有问题, 结果却是报错。
打印一下代码里的this
image.png
这是因为当使用addEventListener() 为一个元素注册事件的时候, 事件函数里的this值是该元素的引用, 所以如果我们在setBgColor中 console.log(this), this指向的是按钮元素, 那this.element就是undefined了,所以报错了
既然this都指向了按钮元素, 那我们直接修改setBgColor函数为
Button.prototype.setBgColor = function() {
this.style.backgroundColor = '#1abc9c'
};
问题确实可以解决了, 但是在实际的开发中,可能会在setBgColor中还调用其他的函数, 比如写成这种:
Button.prototype.setBgColor = function() {
this.setElementColor();
this.setOtherElementColor();
};
所以还是希望setBgColor中的this是指向实例对象的, 这样就可以调用其他的函数,
可以利用bind显式绑定setBgColor()的this为实例对象
Button.prototype.bindEvent = function() {
this.element.addEventListener("click", this.setBgColor.bind(this), false);
};
现在用ES6, 可以更好的解决这个问题:
this.element.addEventListener("click", (e) => {this.setBgColor(e)}, false);
由于箭头函数没有this, 所以会向外层查找this的值, 即bindEvent中的this, 此时this指向实例对象,所以可以正确的调用this.setBgColor方法, 而this.setBgColor中的this也会正确指向实例对象。
在这里再额外提一点, 就是注意bindEvent和setBgColor在这里使用的是普通函数的形式,而非箭头函数, 如果我们改成箭头函数, 会导致函数里的this指向window(非严格模式下)
最后,因为箭头函数没有this, 所以也不能用call(), apply(), bind()这些方法改变this指向,
var value = 1;
var result = (() => this.value).bind({value: 2})();
console.log(result); // 1
2. 没有arguments
箭头函数没有自己的arguemnts, 不过箭头函数可以访问外围函数的arguments对象
constant = () => {
console.log(arguments);
}
var result = constant(1);
console.log(result());
image.png
function constant() {
return () => arguments[0]
}
var result = constant(1);
console.log(result()); // 1
image.png
此时的箭头函数访问的是外围函数constant的arguments
那如果我们就是要访问箭头函数的参数呢?
可以通过命名参数或者rest参数的形式访问参数
let nums = (...nums) => console.log(nums);
nums(1,2,3)
image.png
3. 不能通过new关键字调用
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
箭头函数没有[[Construct]]方法,不能被用作构造函数,如果通过new的方式调用,会报错。
因为JavaScript函数有两个内部方法: [[Call]] 和 [[Construct]],
当通过new 调用函数时, 执行 [[Construct]]方法,创建一个实例对象,然后再执行函数体, 将this绑定到实例上。
当直接调用的时候, 执行[[Call]] 方法,直接执行函数体。
4. 没有new.target
因为不能使用new调用,所以也没有new.target值
5. 没有原型
由于不能使用new调用箭头函数, 所以也没有构建原型的需求,于是箭头函数也不存在prototype这个属性
var Foo = () => {};
console.log(Foo.prototype); // undefined
6. 没有super
连原型都没有,自然也不能通过super来访问原型的属性,所以箭头函数也是没有super的,不过很this,arguments,new.targer由于,这些值由外围最近一层非箭头函数决定。
总结
箭头函数表达式的语法比函数表达式更端,并且不绑定自己的this,arguments, super或new.target. 这些函数表达式最适合用于非方法函数,并且它们不能用作构造函数。
那什么是非方法函数?
对象属性中的函数被称为方法, 那么非方法函数就是指不被用作对象属性中的函数了。
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b();
// undefined Window
obj.c();
// 10, Object {...}
自执行函数
自执行函数形式为:
最后改成
((() => {
console.log(1)
})()) // 1
网友评论