Theo một trích đoạn từ Đóng cửa: Hướng dẫn dứt khoát của Michael Bolin . Nó có thể trông hơi dài, nhưng nó bão hòa với nhiều cái nhìn sâu sắc. Từ "Phụ lục B. Các khái niệm JavaScript thường bị hiểu sai":
Điều gì đề this
cập đến khi một chức năng được gọi
Khi gọi một hàm của biểu mẫu foo.bar.baz()
, đối tượng foo.bar
được gọi là người nhận. Khi hàm được gọi, nó là máy thu được sử dụng làm giá trị cho this
:
var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
for (var i = 0; i < arguments.length; i++) {
this.value += arguments[i];
}
return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);
Nếu không có máy thu rõ ràng khi một hàm được gọi, thì đối tượng toàn cục sẽ trở thành máy thu. Như đã giải thích trong "goog.global" trên trang 47, cửa sổ là đối tượng toàn cầu khi JavaScript được thực thi trong trình duyệt web. Điều này dẫn đến một số hành vi đáng ngạc nhiên:
var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN
Mặc dù obj.addValues
và f
đề cập đến cùng một chức năng, chúng hoạt động khác nhau khi được gọi vì giá trị của người nhận khác nhau trong mỗi cuộc gọi. Vì lý do này, khi gọi một hàm đề cập đến this
, điều quan trọng là phải đảm bảo rằng nó this
sẽ có giá trị chính xác khi nó được gọi. Để rõ ràng, nếu this
không được tham chiếu trong thân hàm, thì hành vi của f(20)
và obj.addValues(20)
sẽ giống nhau.
Vì các hàm là các đối tượng hạng nhất trong JavaScript, nên chúng có thể có các phương thức riêng. Tất cả các hàm đều có các phương thức call()
và apply()
có thể xác định lại người nhận (nghĩa là đối tượng this
tham chiếu) khi gọi hàm. Các chữ ký phương thức như sau:
/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;
Lưu ý rằng sự khác biệt duy nhất giữa call()
và apply()
là call()
nhận các tham số hàm dưới dạng các đối số riêng lẻ, trong khi apply()
nhận chúng dưới dạng một mảng duy nhất:
// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);
Các cuộc gọi sau là tương đương, f
và obj.addValues
tham chiếu đến cùng chức năng:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
Tuy nhiên, vì call()
cũng không apply()
sử dụng giá trị của máy thu của chính nó để thay thế cho đối số người nhận khi nó không được chỉ định, nên những điều sau đây sẽ không hoạt động:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
Giá trị của this
không bao giờ có thể null
hoặc undefined
khi một hàm được gọi. Khi null
hoặc undefined
được cung cấp làm người nhận đến call()
hoặc apply()
, đối tượng toàn cầu được sử dụng làm giá trị cho người nhận thay thế. Do đó, mã trước đó có cùng tác dụng phụ không mong muốn là thêm thuộc tính được đặt tên value
vào đối tượng toàn cục.
Có thể hữu ích khi nghĩ về một hàm là không có kiến thức về biến được gán. Điều này giúp củng cố ý tưởng rằng giá trị của điều này sẽ bị ràng buộc khi hàm được gọi thay vì khi nó được xác định.
Kết thúc chiết xuất.
a
việc áp dụng cho mảng args vàc
trong cuộc gọi cho các cột của args.