箭头函数
es6语法
// ES6语法const fn = v => v;一. 特点
1. 语法简介
箭头函数省去了function关键字,用=>代替function,圆括号代表参数部分,当只有一个参数时,圆括号可省略,当只有一行返回语句时,return和花括号{}都可以省略。
// 求两数之和const fn = (a, b) => {return a + b;}; // 等价于 const fn = (a, b) => a + b;
// 求一个数组各项之和const sum = [1, 2, 3, 4, 5].reduce((x, y) => x + y, 0); // 15
// 将数组中的元素按从小到大顺序排序const array = [2, 4, 1, 5, 9, 7].sort((x, y) => x - y); // [1, 2, 4, 5, 7, 9]
// 过滤数组中为偶数的数字const array = [0, 1, 2, 3, 4, 5, 6].filter(x => x % 2 === 0); // [0, 2, 4, 6]2. 不绑定this
箭头函数体内的this永远指向的是定义时所在的对象,而不是调用时所在的对象。
function Fn() { this.s1 = 0; this.s2 = 0;
// 箭头函数 setInterval(() => this.s1++, 1000);
// 普通函数 setInterval(function() { this.s2++; }, 1000);}
var fn = new Fn();setTimeout(() => console.log('s1= ', fn.s1), 3100); // 3.1秒后输出s1= 3setTimeout(() => console.log('s2= ', fn.s2), 3100); // 3.1秒后输出s2= 0上面代码中,Fn函数内部设置了两个定时器,分别使用了箭头函数和普通函数。
箭头函数中的this指向定义时所在的作用域(即Fn函数),this.s1++是处在箭头函数中,这里的this就是fn,所以fn.s1的值为3。
而普通函数中的this指向运行时所在的作用域(即全局对象window),this.s2++实际等于window.s2++,fn.s2一次都没有更新,因而得到的是0。
所以,从严格意义上讲,箭头函数中不会创建自己的this,而是会从自己作用域链的上一层继承。
const Person = { name: 'Kimmy', age: 20, doSomething: function() { setTimeout(() => console.log(`name: ${this.name}, age: ${this.age}`), 1000); }};
Person.doSomething(); // name: Kimmy, age: 20
const Person2 = { name: 'Kimmy', age: 20, doSomething: () => { setTimeout(() => console.log(`name: ${this.name}, age: ${this.age}`), 1000); }};
Person2.doSomething(); // name: , age: undefined上面两段代码的唯一区别在于doSomething()函数的写法,Person中使用了普通函数定义,Person2中使用了箭头函数定义。
在第一段代码中,Person.doSomeThing()中的this指向函数的调用体,即Person本身,在调用setTimeout()函数时,由于其函数体部分是通过箭头函数定义的,内部的this会继承父作用域的this(即Person),从而输出name: Kimmy, age: 20。
在第二段代码中,Person2.doSomething()中的this指向外层作用域,而Person2的父作用域是全局作用域window,在调用setTimeout()函数时,由于其函数体部分是通过箭头函数定义的,内部的this会继承doSomething()函数所在的作用域this(即window),而window上name属性是'',age属性不存在,所以Person2.doSomething()输出name: , age: undefined。
综上所述,箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正因为它没有this,所以也就不能用作构造函数。
3. 不支持 call()、 apply()、bind() 函数的特性
通过调用 call() 、apply()、bind() 函数可以改变一个函数的执行主体,即改变被调用函数中 this 的指向
但箭头函数中不支持 call() 、apply()、bind()等,因为箭头函数中没有自己的 this ,而是继承父作用域中的 this。
function fn() { return () => { console.log(`id= ${this.id}`); }}
let f = fn.call({id: 1}); // id= 1let f2 = f.call({id: 2})()(); // id = 1let f3 = f().call({id: 3})(); // id= 1let f4 = f()().call({id: 4}); // id= 1上面代码中只有一个this,即函数fn的this,所以f2、f3、f4都输出同样的结果。因为内层函数时箭头函数,没有自己的this,它们的this都是最外层fn函数是this。
4. 不绑定 arguments
在普通函数function中,我们可以通过arguments对象来获取到实际传入的参数值,但在箭头函数中是不存在的。
const fn = () => { console.log(arguments);}fn(1, 2); // Uncaught ReferenceError: arguments is not defined
function fn() { setTimeout(() => { console.log(arguments); }, 0);}
fn(1, 2); // [1, 2]5.支持嵌套
const pipeline = (...funcs) => val => funcs.reduce((a, b => b(a)), val);const plus1 = a => a + 1;const mult2 = a => a * 2;const addThenMult = pipeline(plus1, mult2);addThenMult(5); // 12二.箭头函数不适用场景
(1)定义对象的方法且该方法内部包括this
const Person = { name: 'Kimmy', age: 20, doSomething: () => { this.age++; }};Person.doSomething()方法是一个箭头函数,调用Person.doSomething()时,如果是普通函数,该方法内部的this指向Person,如果写成上面那样的箭头函数,使得this指向全局对象。
(2)不能作为构造函数,不能使用 new 操作符
构造函数时通过new操作符生成对象实例的,生成实例的过程也是通过构造函数给实例绑定this的过程,而箭头函数没有自己的this,因此不能使用箭头函数作为构造函数,也不能通过new操作符来调用箭头函数。
// 普通函数function Person(name) { this.name = name;}let p = new Person('Kimmy'); // 正常
// 箭头函数let Person = (name) => { this.name = name;}let p = new Person('Kimmy'); // Uncaught TypeError: Person is not a constructor(3)没有 prototype 属性
let a = () => 1;
function b() { return 2;}
a.prototype // undefinedb.prototype // {constructor: ƒ}(4)不适合将原型函数定义成箭头函数
在给构造函数添加原型函数时,如果使用箭头函数,其中的this会指向全局作用域window,而并不会指向构造函数,因此并不会访问到构造函数本身,也就无法访问到实例属性,这就失去了作为原型函数的意义。