1. 基本用法
- var f = v => v;
- // 等同于
- var f = function (v) {
- return v;
- };
- // 如果箭头函数不需要参数或需要多个参数, 就使用一个圆括号代表参数部分.
- var f = () => 5;
- // 等同于
- var f = function () { return 5 };
- var sum = (num1, num2) => num1 + num2;
- // 等同于
- var sum = function(num1, num2) {
- return num1 + num2;
- };
- // 如果箭头函数的代码块部分多于一条语句, 就要使用大括号将它们括起来, 并且使用 return 语句返回.
- var sum = (num1, num2) => { return num1 + num2; }
- // 由于大括号被解释为代码块, 所以如果箭头函数直接返回一个对象, 必须在对象外面加上括号, 否则会报错.
- // 报错
- let getTempItem = id => { id: id, name: "Temp" };
- // 不报错
- let getTempItem = id => ({ id: id, name: "Temp" });
箭头函数可以与变量解构结合使用.
- const full = ({ first, last }) => first + ' ' + last;
- // 等同于
- function full(person) {
- return person.first + ' ' + person.last;
- }
箭头函数的一个用处是简化回调函数.
- // 正常函数写法
- [1,2,3].map(function (x) {
- return x * x;
- });
- // 箭头函数写法
- [1,2,3].map(x => x * x);
- // 正常函数写法
- var result = values.sort(function (a, b) {
- return a - b;
- });
- // 箭头函数写法
- var result = values.sort((a, b) => a - b);
rest 参数与箭头函数结合的例子.
- const numbers = (...nums) => nums;
- numbers(1, 2, 3, 4, 5)
- // [1,2,3,4,5]
- const headAndTail = (head, ...tail) => [head, tail];
- headAndTail(1, 2, 3, 4, 5)
- // [1,[2,3,4,5]]
2. 为什么需要箭头函数
先看一个例子
- const Person = {
- 'name': 'little bear',
- 'age': 18,
- 'sayHello': function () {
- var that=this;
- console.log('我叫' + this.name + '我今年' + this.age + '岁!')
- setInterval(function () {
- console.log('我叫' + this.name + '我今年' + this.age + '岁!')
- }, 1000)
- setInterval(function () {
- console.log('我叫' + that.name + '我今年' + that.age + '岁!')
- }, 1000)
- }
- }
- Person.sayHello()
- // 我叫 little bear 我今年 18 岁!
- // 我叫 undefined 我今年 undefined 岁! 因为 setInterval 执行的时候, 是在全局作用域下的, 所有 this 指向的是全局 window, 而 window 上没有 name 和 age, 所以当然输出的是 undefined
- // 我叫 little bear 我今年 18 岁! 通常的写法是缓存 this, 然后在 setInterval 中用缓存的 this 进行操作,
- const Person = {
- 'name': 'little bear',
- 'age': 18,
- 'sayHello': function () {
- setInterval(() => {
- console.log('我叫' + this.name + '我今年' + this.age + '岁!')
- }, 1000)
- }
- }
- Person.sayHello()
- // 我叫 little bear 我今年 18 岁!
3. 使用注意点
(1) 函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象.
(2) 不可以当作构造函数, 也就是说, 不可以使用 new 命令, 否则会抛出一个错误.
(3) 不可以使用 arguments 对象, 该对象在函数体内不存在. 如果要用, 可以用 rest 参数代替.
(4) 不可以使用 yield 命令, 因此箭头函数不能用作 Generator 函数.
上面四点中, 第一点尤其值得注意. this 对象的指向是可变的, 但是在箭头函数中, 它是固定的.
this 指向的固定化, 并不是因为箭头函数内部有绑定 this 的机制, 实际原因是箭头函数根本没有自己的 this, 导致内部的 this 就是外层代码块的 this. 正是因为它没有 this, 所以也就不能用作构造函数.
- const Person = {
- 'name': 'little bear',
- 'age': 18,
- 'sayHello': function() {
- setInterval(() => {
- console.log('我叫' + this.name + '我今年' + this.age + '岁!')
- }, 1000)
- }
- Person.sayHello()
- // 我叫 little bear 我今年 18 岁!
- function Person () {
- this.name = 'little bear',
- this.age = 18
- setInterval(() => {
- console.log('我叫' + this.name + '我今年' + this.age + '岁')
- },1000)
- }
- let p = new Person()
- // 我叫 little bear 我今年 18 岁!
除了 this, 以下三个变量在箭头函数之中也是不存在的, 指向外层函数的对应变量: arguments,super,new.target.
- function foo() {
- setTimeout(() => {
- console.log('args:', arguments);
- }, 100);
- }
- foo(2, 4, 6, 8)
- // args: [2, 4, 6, 8]
上面代码中, 箭头函数内部的变量 arguments, 其实是函数 foo 的 arguments 变量.
4. 什么时候不能用箭头函数
1. 在对象上定义函数
先来看下面这段代码
- var obj = {
- array: [1, 2, 3],
- sum: () => {
- console.log(this === window); // => true
- return this.array.reduce((result, item) => result + item);
- }
- };
- // Throws "TypeError: Cannot read property'reduce'of undefined"
- obj.sum();
sum 方法定义在 obj 对象上, 当调用的时候我们发现抛出了一个 TypeError, 因为函数中的 this 是 window 对象, 所以 this.array 也就是 undefined. 原因也很简单, 相信只要了解过 es6 箭头函数的都知道箭头函数没有它自己的 this 值, 箭头函数内的 this 值继承自外围作用域
解决方法也很简单, 就是不用呗. 这里可以用 es6 里函数表达式的简洁语法, 在这种情况下, this 值就取决于函数的调用方式了.
- var obj = {
- array: [1, 2, 3],
- sum() {
- console.log(this === obj); // => true
- return this.array.reduce((result, item) => result + item);
- }
- };
- obj.sum(); // => 6
通过 object.method() 语法调用的方法使用非箭头函数定义, 这些函数需要从调用者的作用域中获取一个有意义的 this 值.
2. 在原型上定义函数
在对象原型上定义函数也是遵循着一样的规则
- function Person (pName) {
- this.pName = pName;
- }
- Person.prototype.sayName = () => {
- console.log(this === window); // => true
- return this.pName;
- }
- var person = new Person('wdg');
- person.sayName(); // => undefined
使用 function 函数表达式
- function Person (pName) {
- this.pName = pName;
- }
- Person.prototype.sayName = function () {
- console.log(this === person); // => true
- return this.pName;
- }
- var person = new Person('wdg');
- person.sayName(); // => wdg
3. 动态上下文中的回调函数
this 是 js 中非常强大的特点, 他让函数可以根据其调用方式动态的改变上下文, 然后箭头函数直接在声明时就绑定了 this 对象, 所以不再是动态的.
在客户端, 在 dom 元素上绑定事件监听函数是非常普遍的行为, 在 dom 事件被触发时, 回调函数中的 this 指向该 dom, 可当我们使用箭头函数时:
- var button = document.getElementById('myButton');
- button.addEventListener('click', () => {
- console.log(this === window); // => true
- this.innerhtml = 'Clicked button';
- });
因为这个回调的箭头函数是在全局上下文中被定义的, 所以他的 this 是 window. 所以当 this 是由目标对象决定时, 我们应该使用函数表达式:
- var button = document.getElementById('myButton');
- button.addEventListener('click', function() {
- console.log(this === button); // => true
- this.innerHTML = 'Clicked button';
- });
4. 构造函数中
在构造函数中, this 指向新创建的对象实例
this instanceOf MyFunction === true
需要注意的是, 构造函数不能使用箭头函数, 如果这样做会抛出异常
- var Person = (name) => {
- this.name = name;
- }
- // Uncaught TypeError: Person is not a constructor
- var person = new Person('wdg');
理论上来说也是不能这么做的, 因为箭头函数在创建时 this 对象就绑定了, 更不会指向对象实例.
5. 太简短的 (难以理解) 函数
箭头函数可以让语句写的非常的简洁, 但是一个真实的项目, 一般由多个开发者共同协作完成, 就算由单人完成, 后期也并不一定是同一个人维护, 箭头函数有时候并不会让人很好的理解, 比如
- let multiply = (a, b) => b === undefined ? b => a * b : a * b;
- 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;
- }
- let double = multiply(2);
- double(3); // => 6
- multiply(2, 3); // => 6
5. 总结
毫无疑问, 箭头函数带来了很多便利. 恰当的使用箭头函数可以让我们避免使用早期的. bind() 函数或者需要固定上下文的地方并且让代码更加简洁.
箭头函数也有一些不便利的地方. 我们在需要动态上下文的地方不能使用箭头函数: 定义需要动态上下文的函数, 构造函数, 需要 this 对象作为目标的回调函数以及用箭头函数难以理解的语句. 在其他情况下, 请尽情的使用箭头函数.
来源: http://www.qdfuns.com/article/18271/fe8b7494407afc0952c48ab6e0b2e5fb.html