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ì đề thiscậ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.addValuesvà 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ó thissẽ có giá trị chính xác khi nó được gọi. Để rõ ràng, nếu thiskhô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 thistham 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, fvà obj.addValuestham 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 thiskhông bao giờ có thể nullhoặc undefinedkhi một hàm được gọi. Khi nullhoặ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 valuevà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.
aviệc áp dụng cho mảng args vàctrong cuộc gọi cho các cột của args.