ES6之箭頭函數細談

在這裏插入圖片描述
箭頭函數與普通函數的區別,實質是我們是否理解了箭頭函數,在我剛開始接觸ES6時,印象中的箭頭函數與普通函數的區別就是this的指向不同,一個指向window,一個指向當前的實例,作用域。可箭頭函數遠遠不止這麼一個知識點,於是重新學習箭頭函數:

JavaScript裏,this的值在函數被調用的時候纔會指定。 頂級的非方法式調用會將 this視爲window。 (注意:在嚴格模式下, this爲undefined而不是window)。 箭頭函數能保存函數創建時的 this值,而不是調用時的值。這是來自ts官網的解釋。

箭頭函數
說明

箭頭函數表達式的語法比函數表達式更簡潔,並且沒有自己的thisargumentssupernew.target。這些函數表達式更適用於那些本來需要匿名函數的地方,並且它們不能用作構造函數。

箭頭函數的this

1.箭頭函數不會創建自己的this,它只會從自己的作用域鏈的上一層繼承this。箭頭函數的this指向在定義的時候繼承自外層第一個普通函數的this。

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| 正確地指向 p 實例
  }, 1000);
}

var p = new Person();

2.如果箭頭函數外層沒有普通函數,在非嚴格模式下,默認綁定的this指向全局對象,嚴格模式下this指向undefined

var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log( this.i, this)
  }
}
obj.b(); 
// undefined, Window{...}
obj.c(); 
// 10, Object {...}
箭頭函數沒有prototype(原型),所以箭頭函數本身沒有this
let obj = () =>{};
console.log(obj .prototype); // undefined
通過 call 或 apply 調用,不能直接修改箭頭函數的this指向

由於 箭頭函數沒有自己的this指針,通過 call() 或 apply() 方法調用一個函數時,只能傳遞參數(不能綁定this),他們的第一個參數會被忽略。

var adder = {
  base : 1,
    
  add : function(a) {
    var f = v => v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v => v + this.base;
    var b = {
      base : 2
    };
            
    return f.call(b, a);
  }
};

console.log(adder.add(1));         // 輸出 2
console.log(adder.addThruCall(1)); // 仍然輸出 2(而不是3 )
箭頭函數的arguments, 箭頭函數不綁定Arguments 對象,也就是說arguments也沒有
  • 注意:箭頭函數的this指向普通函數時,它的argumens繼承於該普通函數
function foo() {
  console.log(arguments) // { '0': 1, '1': 2 }
  return function() {
    console.log(arguments[0]) // { '0': 3, '1': 4 }
  }
}

foo(1, 2)(3, 4) // 3
rest參數獲取函數的剩餘參數,在大多數情況下,使用剩餘參數是相較使用arguments對象的更好選擇。

rest參數的用法相對於arguments的優點:

  • 箭頭函數和普通函數都可以使用。
  • 更加靈活,接收參數的數量完全自定義。
  • Rest 參數的操作符表示爲3個點 …。直白地講,它的意思就是“把剩餘的參數都放到一個數組中”。
let a = (first, ...rest) => {
  console.log(first, rest); // 1 [2, 3, 4]
};
a(1, 2, 3, 4);
function foo() {
  console.log(arguments) // { '0': 1, '1': 2 }
  return () => console.log(arguments[0])
}

foo(1, 2)(3, 4) // 1
使用 new 操作符

箭頭函數不能用作構造器,和 new一起用會拋出錯誤,因爲箭頭函數沒有constructor。

var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
箭頭函數的使用,比普通函數更加簡潔

更簡短的函數並且不綁定this

1.使回調函數看起來更加優雅
2.只有一個參數的時候可以省略括號
3.函數只有一條語句時可以省略{}和return
4.箭頭函數都是匿名函數,並且都不用寫function

[8, 6, 7, 9].map(function(item) { 
  return item; 
});
[8, 6, 7, 9].map(item =>  item;);
使用 yield 關鍵字

yield關鍵字通常不能在箭頭函數中使用(除非是嵌套在允許使用的函數內)。因此,箭頭函數不能用作生成器

例子(面試常考題)
var id = 'global';
var obj = {
  id: 'item',
  a: function(){
    console.log(this.id);
  },
  b: () => {
    console.log(this.id);
  }
};

obj.a();    // 'item'
obj.b();    // 'global'

上面這個例子,對象obj的方法a使用普通函數定義的,普通函數作爲對象的方法調用時,this指向它所屬的對象。所以,this.id就是obj.id,所以輸出’item’。
但是方法b是使用箭頭函數定義的,箭頭函數中的this實際是繼承的它定義時所處的全局執行環境中的this,所以指向Window對象,所以輸出’global’。(這裏要注意,定義對象的大括號{}是無法形成一個單獨的執行環境的,它依舊是處於全局執行環境中!!)

文章小結
箭頭函數有幾個使用注意點。

(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。

(2)不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。

(3)不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。

(4)不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。

(5)不要在最外層去定義箭頭函數,至少箭頭函數外部要包一層普通函數。

(6)箭頭函數的this意外指向和代碼的可讀性。

什麼情況下使用箭頭函數
  1. 無複雜邏輯或者無副作用的純函數場景下,例如map,forEach回調中使用。
箭頭函數使用中注意事項

1.返回對象字面量,記得用圓括號把對象字面量包起來:
2.換行,箭頭函數在參數和箭頭之間不能換行。
3.解析順序,箭頭函數的解析順序相對||靠前
4.在一個簡寫體中,只需要一個表達式,並附加一個隱式的返回值。在塊體中,必須使用明確的return語句。

var func = () => ({foo: 1});

var func = ()
           => 1; 
// SyntaxError: expected expression, got '=>'

callback = callback || (() => {});

var func = (x, y) => { return x + y; }; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章