文章目錄
- 一、箭頭函數
- 二、與普通函數的差別
-
- 1.箭頭函數不會建立自己的this
- 2.箭頭函數繼承而來的this指向永遠不變(重要)
- 3.call()、apply()、bind()無法改變箭頭函數中this的指向
- 4.箭頭函數不綁定arguments,取而代之用rest參數…解決
- 5.不能使用new操作符(作為構造函數使用)
- 6.不能使用原型屬性
- 7.不能簡單傳回對象字面量
- 8.箭頭函數不能換行
一、箭頭函數
// 箭頭函數
let fun = (name) => {
// 函數體
return `Hello ${name} !`;
};
// 等同于
let fun = function (name) {
// 函數體
return `Hello ${name} !`;
};
二、與普通函數的差別
1.箭頭函數不會建立自己的this
箭頭函數沒有自己的this,它會捕獲自己在定義時(注意,是定義時,不是調用時)所處的外層執行環境的this,并繼承這個this值。是以,箭頭函數中this的指向在它被定義的時候就已經确定了,之後永遠不會改變。
來看個例子:
var id = 'Global';
function fun1() {
// setTimeout中使用普通函數
setTimeout(function(){
console.log(this.id);
}, 2000);
}
function fun2() {
// setTimeout中使用箭頭函數
setTimeout(() => {
console.log(this.id);
}, 2000)
}
fun1.call({id: 'Obj'}); // 'Global'
fun2.call({id: 'Obj'}); // 'Obj'
- 函數fun1中的setTimeout中使用普通函數,2秒後函數執行時,這時函數其實是在全局作用域執行的,是以this指向Window對象,this.id就指向全局變量id,是以輸出’Global’。
- 但是函數fun2中的setTimeout中使用的是箭頭函數,這個箭頭函數的this在定義時就确定了,它繼承了它外層fun2的執行環境中的this,而fun2調用時this被call方法改變到了對象{id: ‘Obj’}中,是以輸出’Obj’。
再來看另一個例子:
var id = 'GLOBAL';
var obj = {
id: 'OBJ',
a: function(){
console.log(this.id);
},
b: () => {
console.log(this.id);
}
};
obj.a(); // 'OBJ'
obj.b(); // 'GLOBAL'
- 對象obj的方法a使用普通函數定義的,普通函數作為對象的方法調用時,this指向它所屬的對象。是以,this.id就是obj.id,是以輸出’OBJ’。
- 但是方法b是使用箭頭函數定義的,箭頭函數中的this實際是繼承它定義時的外層執行環境的this,它定義時所處的外層執行環境就是全局環境,是以指向Window對象,是以輸出’GLOBAL’。(定義對象的大括号{}是無法形成一個單獨的執行環境的,它依舊是處于全局執行環境中)
2.箭頭函數繼承而來的this指向永遠不變(重要)
箭頭函數繼承而來的this指向永遠不變。對象obj的方法b是使用箭頭函數定義的,這個函數中的this就永遠指向它定義時所處的全局執行環境中的this,即便這個函數是作為對象obj的方法調用,this依舊指向Window對象。
3.call()、apply()、bind()無法改變箭頭函數中this的指向
由于 this 已經在詞法層面完成了綁定,通過 call() 、 apply() 、bind()方法調用一個函數時,隻是傳入了參數而已,對 this 并沒有什麼影響:
var id = 'Global';
// 箭頭函數定義在全局作用域
let fun1 = () => {
console.log(this.id)
};
fun1(); // 'Global'
// this的指向不會改變,永遠指向Window對象
fun1.call({id: 'Obj'}); // 'Global'
fun1.apply({id: 'Obj'}); // 'Global'
fun1.bind({id: 'Obj'})(); // 'Global'
4.箭頭函數不綁定arguments,取而代之用rest參數…解決
箭頭函數沒有自己的arguments對象。在箭頭函數中通路arguments實際上獲得的是外層局部(函數)執行環境中的值。
// 例子一
let fun = (val) => {
console.log(val); // 111
console.log(arguments);
// Uncaught ReferenceError: arguments is not defined
// 因為外層全局環境沒有arguments對象
};
fun(111);
// 例子二
function outer(val1, val2) {
let argOut = arguments;
console.log(argOut); //Arguments(2) [111, 222, callee: ƒ, Symbol(Symbol.iterator): ƒ]
let fun = () => {
let argIn = arguments;
console.log(argIn); //Arguments(2) [111, 222, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log(argOut === argIn); // true,箭頭函數中通路arguments是外層局部(函數)執行環境中的值。
};
fun();
}
outer(111, 222);
rest參數用于擷取函數的多餘參數,這樣就不需要使用arguments對象了
var foo = (...args) => {
return args[0]
}
console.log(foo(1)) //1
5.不能使用new操作符(作為構造函數使用)
箭頭函數不能用作構造器,和 new 一起用就會抛出錯誤。
var Foo = () => {};
var foo = new Foo(); //Foo is not a constructor
構造函數的new操作分為四步:
- 建立一個空對象
- 連結到原型
- 綁定this值
- 傳回新對象
但是,箭頭函數沒有原型屬性,沒有自己的this,它的this其實是繼承了外層執行環境中的this,且this指向永遠不會随在哪裡調用、被誰調用而改變,是以箭頭函數不能作為構造函數使用,或者說構造函數不能定義成箭頭函數,否則用new調用時會報錯。
6.不能使用原型屬性
箭頭函數沒有原型屬性。
var foo = () => {};
console.log(foo.prototype) //undefined
7.不能簡單傳回對象字面量
var func = () => { foo: 1 };
// Calling func() returns undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
如果要傳回對象字面量,用括号包裹字面量
var func = () => ({ foo: 1 });
8.箭頭函數不能換行
var func = ()
=> 1; // SyntaxError: expected expression, got '=>'
參考:https://www.jianshu.com/p/eca50cc933b7
本文連結:https://blog.csdn.net/qq_39903567/article/details/115208019