一、引言
置信大家对ES6的箭头函数都不生疏,咱们也会在日常开发的过程中常常应用到它,然而箭头函数有哪些值得咱们去留神的点呢?
二、箭头函数的几个应用留神点
1.函数体内的this对象,就是定义时所在的对象,而不是应用时所在的对象
咱们都晓得,一般的函数外面的this是指向运行时的作用域的,然而箭头函数则不然,箭头函数中的this是绑定定义时所在的作用域的。
- 一般函数
function foo() { setTimeout(function() { console.log('id:', this.id); }, 100);}var id = 21;foo.call({ id: 42 }); //id: 21
- 箭头函数
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100);}var id = 21;foo.call({ id: 42 }); //id: 42
由下面两个例子可见,setTimeout外面的回调函数运行的时候的作用域是window,然而this定义的时候的作用域是函数foo。所以,如果是一般函数,执行时this应该指向全局对象window,这是应该输入21。然而,箭头函数导致this总是指向函数定义失效时所在的对象,所以输入42.
利用箭头函数的这个特点,咱们能够应用箭头函数使this指向固定化,这种个性很有利于封装回调函数。上面是一个例子,DOM事件的回调函数封装在一个对象外面。
var handler = { id: '123456', init: function() { document.addEventListener('click', event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); }};
下面代码的init办法中,应用了箭头函数,这导致这个箭头函数外面的this,总是指向handler对象。否则,回调函数运行时,this.doSomething这一行会报错,因为此时this指向document对象。
很多小伙伴会感到很奇怪,为什么箭头函数的this不会因为函数运行时作用域的扭转而扭转?
其实理论的起因是箭头函数基本没有本人的this,导致外部的this就是外层代码块的this。
所以,箭头函数转成ES5的代码如下:
// ES6function foo() { setTimeout(() => { console.log('id:', this.id); //其实这里的this就是应用了外层作用域的this }, 100);}// ES5function foo() { var _this = this; //将外层作用域的this复制给一个变量 setTimeout(function () { console.log('id:', _this.id); }, 100);}
2.不能够当作构造函数,也就是说,不能应用new命令,否则会抛出一个谬误
下面第一点说到:箭头函数没有本人的this,所以天经地义箭头函数也不能够当作构造函数。
上面尝试应用箭头函数作为构造函数:
var fun = (id, name) => { this.id = id; this.name = name; this.showName = () => { console.log(this.name); }};let obj = new fun(1, "hdl"); //TypeError: fun is not a constructorobj.showName();
果然,报错了,说fun不是一个构造函数,这也反过来印证了第一点,箭头函数没有this。
3.不能够应用arguments对象,该对象在函数体内不存在。如果要用,能够用rest参数代替。
function func1(a, b) { console.log(arguments);}let func2 = (a, b) => { console.log(arguments); //arguments is not defined}func1(1, 2);func2(1, 2);
如果非要打印函数参数,能够在箭头函数中应用rest参数代替arguments对象.
function func1(a, b) { console.log(arguments);}let func2 = (...rest) => { console.log(rest); //[1, 2]}func1(1, 2);func2(1, 2);
4.没有new.target
new.target是ES6新引入的属性,一般函数如果通过new调用,new.target会返回该函数的援用。
function Cat() { console.log(new.target); }let cat = new Cat(); // ƒ Cat() { console.log(new.target); }
此属性次要用于确定构造函数是否为new调用的。
在箭头函数里应用new.target会报错。
// 一般函数let a = function() { console.log(new.target);}a(); // undefined// 箭头函数let b = () => { console.log(new.target); // 报错:Uncaught SyntaxError: new.target expression is not allowed here};b();
5.没有原型和super
因为不能通过 new 关键字调用,不能作为构造函数,所以箭头函数不存在 prototype 这个属性。
let func = () => {};console.log(func.prototype) // undefined
箭头函数没有原型,故也不能通过 super 来拜访原型的属性,所以箭头函数也是没有 super 的。同this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。
6.call/apply/bind办法无奈扭转箭头函数中this的指向
这个也很容易了解,call()、apply()、bind()办法的独特特点是能够扭转this的指向,用来动静批改函数执行时this的指向。但因为箭头函数的this定义时就曾经确定了且不会扭转。所以这三个办法永远也扭转不了箭头函数this的指向。
var name = 'global name';var obj = { name: 'huangdonglu'}// 箭头函数定义在全局作用域let func = () => { console.log(this.name);};func(); // global name// this的指向不会扭转,永远指向Window对象,放到到window下的全局变量func.call(obj); // global namefunc.apply(obj); // global namefunc.bind(obj)(); // global name
7.箭头函数的解析程序绝对考前
尽管箭头函数中的箭头不是运算符,但箭头函数具备与惯例函数不同的非凡运算符优先级解析规定。
let a = false || function() {}; // oklet b = false || () => {}; // SyntaxError: Malformed arrow function parameter listlet c = false || (() => {}); // ok
8.箭头函数不反对重名参数
function foo(a, a) { console.log(a, arguments); // 2 Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]}var boo = (a, a) => { // 间接报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context console.log(a);};foo(1, 2);boo(1, 2);
9.不能够应用yield命令,因而箭头函数不能用作 Generator 函数。
三、箭头函数不实用场景
咱们都晓得,箭头函数比一般的函数要简洁很多,然而箭头函数也不是任何场景都能够实用的。
1.第一个场合是定义对象的办法,且该办法外部包含this。
- 对象外面的函数应用箭头函数
const cat = { lives: 9, jumps : () => { this.lives--; }};cat.jumps();console.log(cat.lives); //9
- 对象外面的办法应用一般办法
const cat = { lives: 9, jumps() { this.lives--; }};cat.jumps();console.log(cat.lives); //8
下面代码中,cat.jumps()办法是一个箭头函数,这是谬误的。调用cat.jumps()时,如果是一般函数,该办法外部的this指向cat;如果写成下面那样的箭头函数,使得this指向全局对象,因而不会失去预期后果。这是因为对象不形成独自的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
2.须要动静this时,也不应该应用动静函数。
var btn = document.getElementById('btn');btn.addEventListener('click', () => { console.log(this);});
因为btn的监听函数是一个箭头函数,导致外面的this就是全局对象,而不合乎咱们想操作按钮自身的需要。如果改成一般函数,this就会动静指向被点击的按钮对象。
除了下面这两点外,还总结了一下几点:
- 不应被用在定义对象的办法上
- 具备动静上下文的回调函数,也不应应用箭头函数
- 不能利用在构造函数中
- 防止在 prototype 上应用
- 防止在须要 arguments 上应用
四、总结
就先总结下面这么多了,感激@阮一峰 阮老师的文章:箭头函数应用留神点,最近也在浏览NICHOLAS的《深刻了解ES6》,心愿能对ES6更加的相熟,也心愿大家可能对本文加以补充和斧正。