ES6 系列之箭头函数

简介: 我们先来回顾下箭头函数的基本语法。

1.png


回顾


我们先来回顾下箭头函数的基本语法。


ES6 增加了箭头函数:


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}
复制代码


很多时候,你可能想不到要这样用,所以再来举个例子,比如在 React 与 Immutable 的技术选型中,我们处理一个事件会这样做:


handleEvent = () => {
  this.setState({
    data: this.state.data.set("key", "value")
  })
};
复制代码


其实就可以简化为:


handleEvent = () => {
  this.setState(({data}) => ({
    data: data.set("key", "value")
  }))
};
复制代码


比较


本篇我们重点比较一下箭头函数与普通函数。


主要区别包括:


1.没有 this


箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。


这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。


模拟一个实际开发中的例子:


我们的需求是点击一个按钮,改变该按钮的背景色。


为了方便开发,我们抽离一个 Button 组件,当需要使用的时候,直接:


// 传入元素 id 值即可绑定该元素点击时改变背景色的事件
new Button("button")
复制代码


HTML 代码如下:


<button id="button">点击变色</button>
复制代码


JavaScript 代码如下:


function Button(id) {
    this.element = document.querySelector("#" + id);
    this.bindEvent();
}
Button.prototype.bindEvent = function() {
    this.element.addEventListener("click", this.setBgColor, false);
};
Button.prototype.setBgColor = function() {
    this.element.style.backgroundColor = '#1abc9c'
};
var button = new Button("button");
复制代码


看着好像没有问题,结果却是报错 Uncaught TypeError: Cannot read property 'style' of undefined


这是因为当使用 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 是指向实例对象的,这样就可以调用其他的函数。


利用 ES5,我们一般会这样做:


Button.prototype.bindEvent = function() {
    this.element.addEventListener("click", this.setBgColor.bind(this), false);
};
复制代码


为避免 addEventListener 的影响,使用 bind 强制绑定 setBgColor() 的 this 为实例对象

使用 ES6,我们可以更好的解决这个问题:


Button.prototype.bindEvent = function() {
    this.element.addEventListener("click", event => this.setBgColor(event), 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


箭头函数没有自己的 arguments 对象,这不一定是件坏事,因为箭头函数可以访问外围函数的 arguments 对象:


function constant() {
    return () => arguments[0]
}
var result = constant(1);
console.log(result()); // 1
复制代码


那如果我们就是要访问箭头函数的参数呢?


你可以通过命名参数或者 rest 参数的形式访问参数:


let nums = (...nums) => nums;
复制代码


3. 不能通过 new 关键字调用


JavaScript 函数有两个内部方法:[[Call]] 和 [[Construct]]。


当通过 new 调用函数时,执行 [[Construct]] 方法,创建一个实例对象,然后再执行函数体,将 this 绑定到实例上。


当直接调用的时候,执行 [[Call]] 方法,直接执行函数体。


箭头函数并没有 [[Construct]] 方法,不能被用作构造函数,如果通过 new 的方式调用,会报错。


var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
复制代码


4. 没有 new.target


因为不能使用 new 调用,所以也没有 new.target 值。


关于 new.target,可以参考 es6.ruanyifeng.com/#docs/class…


5. 没有原型


由于不能使用 new 调用箭头函数,所以也没有构建原型的需求,于是箭头函数也不存在 prototype 这个属性。


var Foo = () => {};
console.log(Foo.prototype); // undefined
复制代码


6. 没有 super


连原型都没有,自然也不能通过 super 来访问原型的属性,所以箭头函数也是没有 super 的,不过跟 this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。


总结


最后,关于箭头函数,引用 MDN 的介绍就是:


An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.


翻译过来就是:


箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数(non-method functions),并且它们不能用作构造函数。


那么什么是 non-method functions 呢?


我们先来看看 method 的定义:


A method is a function which is a property of an object.


对象属性中的函数就被称之为 method,那么 non-mehtod 就是指不被用作对象属性中的函数了,可是为什么说箭头函数更适合 non-method 呢?


让我们来看一个例子就明白了:


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 {...}
复制代码


自执行函数


自执行函数的形式为:


(function(){
    console.log(1)
})()
复制代码


或者


(function(){
    console.log(1)
}())
复制代码


利用箭头简化自执行函数的写法:


(() => {
    console.log(1)
})()
复制代码


但是注意:使用以下这种写法却会报错:


(() => {
    console.log(1)
}())
复制代码


为什么会报错呢?嘿嘿,如果你知道,可以告诉我~


ES6 系列


ES6 系列目录地址:github.com/mqyqingfeng…


ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。


如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。



目录
相关文章
|
6月前
ES6之箭头函数
ES6之箭头函数
|
10天前
|
JavaScript
哪些场景适合使用 ES6 的箭头函数?
总之,当需要简洁地定义函数、处理回调函数、避免 `this` 指向问题以及进行函数式编程等场景时,ES6的箭头函数都是一个很好的选择。但需要注意的是,箭头函数也有一些限制,如不能作为构造函数使用等,在使用时需要根据具体情况进行选择。
|
18天前
|
安全 JavaScript 前端开发
es6 箭头函数
【10月更文挑战第26天】ES6箭头函数为JavaScript开发者提供了一种更简洁、更直观的函数定义方式,同时其独特的`this`绑定和无`arguments`对象等特性也使得在一些特定场景下的代码编写更加方便和安全,但在使用时也需要注意其与普通函数的区别,以确保正确地使用和理解箭头函数。
103 62
|
22天前
|
自然语言处理
ES6 中箭头函数和普通函数区别
【10月更文挑战第19天】这些仅是对箭头函数和普通函数区别的一些主要方面进行的详细阐述,实际应用中可能还会有更多具体的细节和情况需要进一步探讨和理解。可以根据自己的需求进一步深入研究和实践,以更好地掌握它们在不同场景下的应用。
30 2
ES6学习(4)箭头函数
ES6学习(4)箭头函数
|
6月前
|
网络架构
ES6箭头函数的特性
ES6箭头函数的特性
|
6月前
|
小程序
es6学习笔记(四)箭头函数
es6学习笔记(四)箭头函数
|
6月前
Es6箭头函数
Es6箭头函数
63 0
|
前端开发
ES6系列笔记-箭头函数
ES6系列笔记-箭头函数
29 1