做者:扉扉 (沪江web前端开发工程师)
本文原创翻译,有不当的地方欢迎指出。转载请指明出处。javascript
看到你天天使用的编程语言在不断进化是一件使人开心的事情 。从错误中学习,找到更好的实现方式,创造新的语法特性,语言就这样一步一步地实现了版本更新。前端
这正是近几年Javascript身上发生的事情 ,ECMAScript6 引入了: 箭头函数,类以及其它特性,真的太棒了!java
其中一个很是好用的箭头函数,有许多文件介绍了了这个漂亮的语法糖,还具备透明上下文的做用(原文为 context transparency), 若是你对于ES6还不熟悉,请先阅读箭头函数的一些入门文章。web
凡事都有两面性,新的特性每每也会带来新的困扰, 好比对箭头函数的误用。编程
这篇文章经过实际使用场景带你了解在一些特定状况下究竟是应该使用传统的函数,仍是该使用更简洁的箭头函数。dom
在javascript中,方法能够作为一个对象的属性,当调用这个方法时, this 指向这个方法所属的对象;编程语言
既然箭头函数只是一个语法糖,那咱们来尝试一下使用箭头函数作为一个对象的方法会发生什么:函数
var calculate = { array: [1, 2, 3], sum: () => { console.log(this === window); // => true return this.array.reduce((result, item) => result + item); } }; console.log(this === window); // => true // Throws"TypeError: Cannot read property 'reduce' of undefined" calculate.sum();
calculate.sum使用箭头函数来定义,可是调用 calculate.sum() 时出现了异常。由于当执行sum的时候上下文仍然是window,这是由于箭头函数已经绑定了window作为上下文。学习
执行this.array 等同于 window.array ,固然是 undefinedthis
解决办法就是不要在对象的方法上使用箭头函数短语法,这样this关键字会在调用时决定,而不是早早绑定在闭合的上下文中, 让咱们看一下具体代码:
var calculate = { array: [1, 2, 3], sum() { console.log(this === calculate); // => true return this.array.reduce((result, item) => result + item); } }; calculate.sum(); // => 6
对象原型
一样的规则也适用于给对象prototype原型上定义方法:
function MyCat(name) { this.catName = name; } MyCat.prototype.sayCatName = () => { console.log(this === window); // => true returnthis.catName; }; var cat = new MyCat('Mew'); cat.sayCatName(); // => undefined
使用传统方式便可正常工做:
function MyCat(name) { this.catName = name; } MyCat.prototype.sayCatName = function() { console.log(this === cat); // => true returnthis.catName; }; var cat = new MyCat('Mew'); cat.sayCatName(); // => 'Mew'
this是js中很是强大的特色,他让函数能够根据其调用方式动态的改变上下文,而后箭头函数直接在声明时就绑定了this对象,因此再也不是动态的。
在客户端,在dom元素上绑定事件监听函数是很是广泛的行为,在dom事件被触发时,回调函数中的this指向该dom,可当咱们使用箭头函数时:
button.addEventListener('click', () => { console.log(this === window); // => true this.innerHTML = 'Clicked button'; });
由于这个回调的箭头函数是在全局上下文中被定义的,因此他的this是window。因此当this是由目标对象决定时,咱们应该使用函数表达式:
button.addEventListener('click', function() { console.log(this === button); // => true this.innerHTML = 'Clicked button'; });
当函数作为构造函数执行时 new MyFunction(),this指向新建立的对象实例:
this instanceOf MyFunction === true
须要注意的是,构造函数不能使用箭头函数,若是这样作会抛出异常。
由于使用箭头函数后this会指定闭合的当前上下文,而当函数作为构造器的时候,this又会指向生成的实例, 这个形成歧义。
var Message = (text) => { this.text = text; }; // Throws "TypeError: Message is not a constructor" var helloMessage = new Message('Hello World!');
咱们都知道使用函数表达式便可正常:
var Message = function(text) { this.text = text; }; var helloMessage = new Message('Hello World!'); console.log(helloMessage.text); // => 'Hello World!'
箭头函数可让语句写的很是的简洁,参数只有一个时能够省略(),函数体只有一句话能够省略{},若是返回值是一个表达式还甚至还能够省略return!
个人大学老师曾给咱们布置了一道有趣的做业: 使用C语言来编写一个计算字符串长度的函数,函数要尽量的短,这是一个很好的方法去学习一门新的语言。
不过在真实生活中,代码要被其它开发者阅读,超短的语法有时会让你的同事陷入难以理解中。上代码:
let double = multiply(2); double(3); // => 6 multiply(2, 3); // =>6
这个函数的做用就是当只有一个参数 a 时,返回接受一个参数 b 返回 a * b 的函数,接收两个参数时直接返回乘积,这个函数能够很好的工做而且看起很简洁,可是从第一眼看去并非很好理解。
为了让这个函数更好的让人理解,咱们能够为这个箭头函数加一对花括号,并加上 return 语句,或者直接使用函数表达式:
function multiply(a, b){ if (b === undefined) { return function(b){ return a * b; } } return a * b; } letdouble = multiply(2); double(3); // => 6 multiply(2, 3);// => 6
怎么样是否是好理解多了?
如何平衡简洁与易理解也是使用箭头函数须要注意的地方。
毫无疑问,箭头函数是一个很棒的特性。之前咱们使用bind()函数或者须要固定上下文的地方如今使用箭头函数会让代码更加简洁。
但有一些状况下,使用箭头函数也有一些不便利。在须要动态上下文的地方不能使用箭头函数,使用构造函数建立对象时不能使用箭头函数等等。除去文中列举不适合使用的状况下,尽情地使用箭头函数吧。
iKcamp原创新书《移动Web前端高效开发实战》已在亚马逊、京东、当当开售。