ES2015 中的箭头函数和词法 this

箭头函数是使用=>语法对函数定义的简写。它们在语法上类似于 C#,Java 8 和 CoffeeScript 中的相关特性。它们支持表达式(Expression bodies)和函数体(Statement bodies)。与函数不同,箭头函数与其上下文代码共享相同的词法this(注:箭头函数并没有自己的this,它的this是派生而来的,根据“词法作用域”派生而来)。如果箭头函数在另一个函数体内,它共享其父函数的 arguments 变量。

// 使用表达式(Expression bodies)
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);

// 使用函数体(Statement bodies)
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// 词法`this`
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
};

// 词法 arguments
function square() {
  let example = () => {
    let numbers = [];
    for (let number of arguments) {
      numbers.push(number * number);
    }

    return numbers;
  };

  return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

更多信息: MDN Arrow Functions

注:

用Babel转译一下上面的代码,结果:

"use strict";

// Expression bodies
var odds = evens.map(function (v) {
  return v + 1;
});
var nums = evens.map(function (v, i) {
  return v + i;
});

// Statement bodies
nums.forEach(function (v) {
  if (v % 5 === 0) fives.push(v);
});

// Lexical this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends: function printFriends() {
    var _this = this;

    this._friends.forEach(function (f) {
      return console.log(_this._name + " knows " + f);
    });
  }
};

// Lexical arguments
function square() {
  var _arguments = arguments;

  var example = function example() {
    var numbers = [];
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (var _iterator = _arguments[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
        var number = _step.value;

        numbers.push(number * number);
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    return numbers;
  };

  return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

值得注意的是,这里的this

// Lexical this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends: function printFriends() {
    var _this = this;

    this._friends.forEach(function (f) {
      return console.log(_this._name + " knows " + f);
    });
  }
};

从转译结果的printFriends函数中var _this = this;可以看出,_this指向bob对象。

比较一下下面两段代码:

var bob = {
  _name: "Bob",
  _friends: [""],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
};
bob.printFriends();// Bob knows 
var bob = {
  _name: "Bob",
  _friends: [""],
  printFriends() {
    this._friends.forEach(function (f) {
      return console.log(this._name + " knows " + f);
    });
  }
};
bob.printFriends();// undefined knows 

原因很简单:箭头函数与其上下文代码共享相同的词法this,所以this指向bob对象,第2段代码forEach中的匿名函数上下文是window对象,所以this指向window对象。

题外话,要想修复第2段代码的问题,除了Babel提供的转译外,还可以使用 ES5 的 bind() :

var bob = {
  _name: "Bob",
  _friends: [""],
  printFriends() {
    this._friends.forEach(function (f) {
      return console.log(this._name + " knows " + f);
    }.bind(this));
  }
};
bob.printFriends();// Bob knows 

bind() 最简单的用法是使函数的上下文指向其参数。(https://www.css88.com/archives/5611)。

赞(6) 打赏
未经允许不得转载:WEB前端开发 » ES2015 中的箭头函数和词法 this

评论 1

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #-49

    学习了,很不错

    hojas2年前 (2017-02-14)回复

前端开发相关广告投放 更专业 更精准

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏