ES6箭頭函數

參考: http://es6.ruanyifeng.com/?search=%E7%AE%AD%E5%A4%B4&x=0&y=0#docs/function

箭頭函數的基本用法

let f1 = v => v;
let f2 = () => 5;
let f3 = (num1, num2) => num1 + num2;
let f4 = (num) => {
  let n = 2;
  return num + n;  
}

使用示例

[1,2,3].map(x => x * x);
var result = values.sort((a, b) => a - b);
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]]

注意事項

  1. 函數體內的this對象,就是定義時所在的對象(函數體內沒有自己的this 對象,利用作用域查找到最近的this對象),而不是使用時所在的對象。
  2. 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤(沒有this對象)。
  3. 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest參數代替。
  4. 不可以使用yield命令,因此箭頭函數不能用作 Generator函數。

關于第一點的一個說明

箭頭函數內并沒有自己的this對象,在箭頭函數內使用的this對象時,會通過作用域鏈查找到最近的this對象

 function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

上面代碼中,setTimeout的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo函數生成時,而它的真正執行要等到100毫秒后。如果是普通函數,執行時this應該指向全局對象window,這時應該輸出21。但是,箭頭函數導致this總是指向函數定義生效時所在的對象(本例是{id: 42}),所以輸出的是42

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭頭函數
  setInterval(() => this.s1++, 1000);
  // 普通函數
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0

上面代碼中,Timer函數內部設置了兩個定時器,分別使用了箭頭函數和普通函數。前者的this綁定定義時所在的作用域(即Timer函數),后者的this指向運行時所在的作用域(即全局對象)。所以,3100毫秒之后,timer.s1被更新了3次,而timer.s2一次都沒更新。

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就是外層代碼塊的this。正是因為它沒有this,所以也就不能用作構造函數。也就不能用call()、apply()、bind()這些方法去改變this的指向。

所以,在ES6箭頭函數轉成ES5如下所示:

// ES6
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log('id:', _this.id);
  }, 100);
}

長期以來,JavaScript 語言的this對象一直是一個令人頭痛的問題,在對象方法中使用this,必須非常小心。箭頭函數”綁定”this,很大程度上解決了這個困擾。

嵌套箭頭函數

let insert = (value) => ({into: (array) => ({after: (afterValue) => {
  array.splice(array.indexOf(afterValue) + 1, 0, value);
  return array;
}})});

insert(2).into([1, 3]).after(1); //[1, 2, 3]

// λ演算的寫法
fix = λf.(λx.f(λv.x(x)(v)))(λx.f(λv.x(x)(v)))

// ES6的寫法
var fix = f => (x => f(v => x(x)(v)))
               (x => f(v => x(x)(v)));

ES7綁定this

箭頭函數可以綁定this對象,大大減少了顯式綁定this對象的寫法(call、apply、bind)。但是,箭頭函數并不適用于所有場合,所以ES7提出了“函數綁定”(function bind)運算符,用來取代call、apply、bind調用。雖然該語法還是ES7的一個提案,但是Babel轉碼器已經支持。函數綁定運算符是并排的兩個冒號(::),雙冒號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象,作為上下文環境(即this對象),綁定到右邊的函數上面。

foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);

const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
  return obj::hasOwnProperty(key);
}

如果雙冒號左邊為空,右邊是一個對象的方法,則等于將該方法綁定在該對象上面。

var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;

let log = ::console.log;
 // 等同于
var log = console.log.bind(console);

由于雙冒號運算符返回的還是原對象,因此可以采用鏈式寫法。

// 例一
import { map, takeWhile, forEach } from "iterlib";

getPlayers()
::map(x => x.character())
::takeWhile(x => x.strength > 100)
::forEach(x => console.log(x));

// 例二
let { find, html } = jake;

document.querySelectorAll("div.myClass")
::find("p")
::html("hahaha");
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1、基本用法 在ES6中允許使用箭頭()=>來定義函數。 如果函數不需要參數或者需要多個參數就使用圓括號來代替。 ...
    字母31閱讀 211評論 0 0
  • 箭頭符號在JavaScript誕生時就已經存在,當初第一個JavaScript教程曾建議在HTML注釋內包裹行內腳...
    程序員之路閱讀 761評論 0 3
  • 函數參數的默認值 基本用法 在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。 上面代碼檢查函數l...
    呼呼哥閱讀 3,476評論 0 1
  • 前言 最近學習了慕課網上的vue仿餓了嗎的視頻,體會到了es6的箭頭函數的妙用,因此特別總結了一下箭頭函數的用法。...
    破浪_閱讀 412評論 0 3
  • 雖然沙僧比較乏味無趣,個性和本領都不突出,但他是以忠厚為標志存在于老百姓心目中的。想象他挑著擔子的身影,黝黑的臉孔...
    1caf6e0e8be5閱讀 3,425評論 0 0