箭頭函數(Arrow Function)和普通函數(Regular Function)是 JavaScript 中兩種不同的函數定義方式,它們在語法、上下文(this
)、原型鏈等方面存在顯著區別。以下是它們的主要區別:
1. 語法差異
-
普通函數:
function normalFunction(a, b) {return a + b; }
或者使用函數表達式:
const normalFunction = function(a, b) {return a + b; };
-
箭頭函數:
const arrowFunction = (a, b) => {return a + b; };
如果箭頭函數體只有一條語句,可以省略大括號并自動返回結果:
const arrowFunction = (a, b) => a + b;
2. this
的處理方式
這是箭頭函數和普通函數最重要的區別之一。
-
普通函數:
-
普通函數的
this
是動態綁定的,取決于函數的調用方式:-
作為方法調用:
this
指向調用它的對象。const obj = {
? ? name: "Kimi",
? ? greet: function() {
? ? ? ? console.log(this.name); // 輸出 "Kimi"
? ? }
};
obj.greet(); -
作為普通函數調用:
this
指向全局對象(非嚴格模式下是window
或global
,嚴格模式下是undefined
)。
function greet() {
? ? console.log(this);
}
greet(); // 非嚴格模式下輸出 window,嚴格模式下輸出 undefined -
使用
call
、apply
或bind
: 可以手動綁定this
。greet.call({ name: "Kimi" }); // 輸出 { name: "Kimi" }
-
-
-
箭頭函數:
-
箭頭函數沒有自己的
this
,它會捕獲其所在上下文的this
值,并在函數內部使用。 -
箭頭函數的
this
是在定義時就確定的,不會隨著調用方式改變。
const obj = {
? ? name: "Kimi",
? ? greet: () => {
? ? ? ? console.log(this.name); // 輸出 undefined(因為箭頭函數捕獲了全局上下文的 this)
? ? }
};
obj.greet();const normalGreet = function() {
? ? console.log(this.name); // 輸出 "Kimi"
};
const arrowGreet = () => {
? ? console.log(this.name); // 輸出 undefined
};normalGreet.call({ name: "Kimi" }); // 輸出 "Kimi"
arrowGreet.call({ name: "Kimi" }); // 輸出 undefined -
3. arguments
對象
-
普通函數:
-
普通函數內部可以訪問
arguments
對象,它是一個類數組對象,包含函數調用時傳入的所有參數。
function sum() {
? ? console.log(arguments); // 類數組對象,包含所有參數
? ? return Array.from(arguments).reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 輸出 6 -
-
箭頭函數:
-
箭頭函數不綁定自己的
arguments
對象,只能通過參數名訪問參數。
const sum = (...args) => {
? ? console.log(arguments);? // ReferenceError: arguments is not defined
? ? return args.reduce((a, b) => a + b, 0);
};
console.log(sum(1, 2, 3)); // 輸出 6 -
4. new
調用
-
普通函數:
-
普通函數可以用
new
關鍵字創建一個新的實例對象。
function Person(name) {
? ? this.name = name;
}
const person = new Person("Kimi");
console.log(person); // 輸出 { name: "Kimi" } -
-
箭頭函數:
-
箭頭函數不能用
new
關鍵字調用,否則會拋出錯誤。
const Person = (name) => {
? ? this.name = name;
};
const person = new Person("Kimi"); // TypeError: Person is not a constructor -
5. 原型鏈
-
普通函數:
-
普通函數有
prototype
屬性,可以用于原型鏈繼承。
function Person(name) {
? ? this.name = name;
}
Person.prototype.greet = function() {
? ? console.log(`Hello, my name is ${this.name}`);
};
const person = new Person("Kimi");
person.greet(); // 輸出 "Hello, my name is Kimi" -
-
箭頭函數:
-
箭頭函數沒有
prototype
屬性,因此不能用于原型鏈繼承。
const Person = (name) => {
? ? this.name = name;
};
console.log(Person.prototype); // undefined -
6. 使用場景
-
普通函數:
-
適用于需要動態綁定
this
的場景,例如作為方法調用、事件處理器、構造函數等。 -
適用于需要訪問
arguments
對象的場景。
-
-
箭頭函數:
-
適用于不需要動態綁定
this
的場景,例如回調函數、匿名函數等。 -
適用于需要簡潔語法的場景,尤其是只有一條語句時。
-
總結
-
普通函數:
-
有自己的
this
,動態綁定。 -
有
arguments
對象。 -
可以用
new
調用。 -
有
prototype
屬性。 -
語法稍顯復雜。
-
-
箭頭函數:
-
沒有自己的
this
,捕獲定義時的上下文。 -
沒有
arguments
對象。 -
不能用
new
調用。 -
沒有
prototype
屬性。 -
語法簡潔。
-
根據實際需求選擇合適的函數類型可以提高代碼的可讀性和效率。