Skip to content

箭头函数 Arrow Functions #7

@HecateDK

Description

@HecateDK

箭头函数 Arrow Functions

ES6的箭头函数的语法,与coffeeScript中的 => 语法一样,共享this上下文。

箭头函数的产生,主要是为了更简洁的语法和与父作用域共享关键字this

先来看一下六种语言中简单的函数示例:

function (a){ return a>0; }    // js
[](int a){ return a>0; }       // C++
(lambda (a) (a>0)) ; ;         // Lisp
lambda a : a>0                 // python
a => a > 0                     // C#
a -> a > 0                     // java

新的函数语法

CoffeeScript很简洁,特别是函数语法,不同于传统的javascript函数语法,传统的函数语法没有提供任何的灵活性,每一次需要定义一个函数的时候,都必须输入function(){}。

当我们有大量的回调函数时,箭头函数就能看到很明显的优势了。

// ES5
function getVerifiedToken(selector){
  return getUsers(selector)
      .then(function (users) { return users[0]; })
      .then(verifyUser)
      .then(function(user,verifiedToken) { return verifiedToken; })
      .cache(function (err) { console.log(err.stack); });
}

// ES6
function getVerifiedToken(selector){
  return getUsers(selector)
      .then(users => users[0])
      .then(verifyUser)
      .then((user,verifiedToken) => verfiedToken )
      .cache(err => log(err.stack));
}

从上面的重写代码中,我们可以看到箭头函数的一些语法:

  • function和{}都消失了,所有的回调函数都只出现在一行代码里
  • 当只有一个参数时,()也消失了(但rest参数时一个例外,如(...args)=> ...)
  • 当{}消失后,return关键字也可以跟着消失,单行的箭头函数会提供一个隐式的return(注意:仅仅当箭头函数为单行形式的时候,才会出现隐式的return。当箭头函数伴随着{}被声明,那么即使它是单行的,也不会有隐式return)
  • 如果我们的函数内只有一条声明,我们可以不写{}

注意,使用了块语句的箭头函数不会自动返回值,你需要使用return语句将所需值返回

当我们需要写一个接受多重参数(也可能没有参数,或是不定参数、默认参数、参数解构)的函数,就需要用小括号包裹参数list

// ES5
var total = values.reduce(function (a,b){
  return a + b;
},0);

// ES6
var total = values.reduce((a,b) => a + b,0);

当使用箭头函数创建普通对象时,需要将对象包裹在小括号里。

var foo = pupies.map(puppy => {});        // 报错:空对象{}和空白函数代码块{}一模一样,{}被解析为空白函数代码块
var foo = pupies.map(puppy => ({}));      

来看一个更完整的例子:

function () { return 1; }
() => { return 1; }
() => 1
 
function (a) { return a * 2; }
(a) => { return a * 2; }
(a) => a * 2
a => a * 2
 
function (a, b) { return a * b; }
(a, b) => { return a * b; }
(a, b) => a * b
 
function () { return arguments[0]; }
(...args) => args[0]
 
() => {} // undefined
() => ({}) // {}
this
普通function函数和箭头函数的行为的一个微妙的区别是——箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。

javascript里的this,无论我们是否需要它,function函数总会自动接收一个this值。

this的工作原理可以点击 这里
例如:使用jquery来展示一个每秒都会更新的时钟:

$('.current_time').each(function () {         // 当尝试在setInterval的回调中使用this来引用DOM元素时,我们得到的却是一个属于回调函数自身上下文的this
  setInterval(function(){
    $(this).text(Date.now());
  },1000);
});

因为内层函数并没有从外层函数继承this的值,在内层函数里,this会是window或undefined。临时变量self用来将外部的this值导入内部函数(还有另一种方法是在内部函数上执行.bind(this)):

$('.current_time').each(function(){
  var self = this;
  setInterval(function(){
   $(self).text(Date.now()); 
  },1000);
});

但是当我们使用箭头函数的时候,这个问题就不存在了,因为箭头函数会产生一个不属于它自己的上下文this。但要遵循以下规则:

  • 通过object.method()语法调用的方法用非箭头函数定义,这些函数需要从调用者的作用域中获取一个有意义的this值
  • 其它情况全都用箭头函数
    上面的js可以用箭头函数简写为:
$('.current_time').each(function(){
  setInterval(() => $(this).text(Date.now()),1000);
});

再来看一个例子:

// ES5
{
  ...
  addAll:function addAll(pieces){
     var self = this;
     _each(pieces,function(piece){
      self.add(piece);     // 内层函数并没从外层函数继承this的值
     });
  },
  ...
}

// ES6
{
  ...
  addAll:function addAll(pieces){
    _each(pieces,piece => this.add(piece));
  },
  ...
}

// ES6 使用对象字面量方法:
{
  ...
  addAll(pieces){
    _each(pieces,piece => this.add(piece));
  },
  ...
}
箭头函数与普通函数的另一个区别是——它没有自己的arguments变量
function log(msg){
  const print = () => console.log(arguments[0]);
  print('LOG:${msg}');
}
log('hello');     // 'hello'
箭头函数没有属于自己的this和arguments,但是我们可以通过rest参数来得到所有存入的参数数组。
function log(msg){
  const print = (...args) => console.log(args[0]);
  print('LOG:$(msg)');
}
log('hello');         // LOG:hello

=> 替代function是非常便捷的,但是不是什么情况(例如只使用=>来声明函数的代码)都适合用=>,推荐存在以下两种情况时候使用箭头函数:

  • 当只有一条声明(statement)语句时,隐式return
  • 需要使用到父作用域中的this

原文 An Introduction to JavaScript ES6 Arrow Functions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions