Cần làm rõ tham chiếu đến ECMA 5.
Tôi cho rằng nó có nghĩa là ECMA-262 Edition 5. Cần lưu ý rằng ECMA-262 (hay còn gọi là ECMAScript hoặc, chính xác hơn là Javascript) là ngôn ngữ kịch bản chung đã được triển khai trong Trình duyệt Internet. Từ tiêu chuẩn Edition 5.1:
Các bước sau được thực hiện khi điều khiển nhập vào ngữ cảnh thực thi cho mã hàm có trong đối tượng hàm F, một người gọi cung cấp thisArg và một người gọi cung cấp danh sách đối số:
- Nếu mã chức năng là mã nghiêm ngặt, hãy đặt ThisBinding thành thisArg.
- Nếu không nếu thisArg là null hoặc không xác định, hãy đặt ThisBinding thành đối tượng toàn cục.
- Khác nếu Loại (thisArg) không phải là Đối tượng, hãy đặt ThisBinding thành ToObject (thisArg).
- Khác đặt ThisBinding thành thisArg
- ... (không phải về "cái này")
Thuật ngữ "đối tượng toàn cầu" đề cập đến bất kỳ đối tượng nào ở trên cùng của chuỗi phạm vi. Đối với các trình duyệt, đây sẽ là đối tượng "cửa sổ" nhưng đây là lựa chọn triển khai (Máy chủ Windows Script có một đối tượng toàn cục vô hình nhưng không có chế độ nghiêm ngặt nên các tham chiếu không đủ điều kiện truy cập thuộc tính của nó và không có "tự" toàn cầu). Ngoài ra, "chế độ nghiêm ngặt" phải được bật rõ ràng nếu không nó không hoạt động (mục 14.1 của tiêu chuẩn). Do đó, "this" không xác định sẽ vẫn phân giải đối tượng toàn cục (cửa sổ) trong "ECMA 5" với chế độ nghiêm ngặt không hoạt động.
Vì vậy, câu trả lời cho câu hỏi là:
"this" luôn đề cập đến đối tượng gọi hàm. Nếu hàm không được gọi bởi một đối tượng (tức là không phải là một cuộc gọi phương thức) thì "this" (như được truyền cho hàm) là "không xác định". Tuy nhiên, nếu KHÔNG sử dụng chế độ nghiêm ngặt thì "this" không xác định được đặt thành đối tượng toàn cục (quy tắc 2 ở trên).
"self" không có ý nghĩa cú pháp đặc biệt, nó chỉ là một định danh. Các trình duyệt có xu hướng định nghĩa window.self (chỉ là một thuộc tính của đối tượng cửa sổ chung) = window. Điều này dẫn đến các tham chiếu không đủ tiêu chuẩn đến "self" giống với "window" UNLESS "self" đã được xác định lại trong một phạm vi kèm theo (chẳng hạn như "var self = this;" ở trên. Chúc bạn may mắn khi xác định lại "this".)
Vì vậy, lời giải thích đầy đủ của ví dụ trên là:
outer func: this.foo = bar
// "this" refers to the invoking object "myObject"
outer func: self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func: this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func: self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"
Một biến thể thú vị của ví dụ này tạo ra một bao đóng bằng cách trả về một tham chiếu đến hàm bên trong.
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
return function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
};
}
};
var yourObject = {
foo: "blat",
func: myObject.func() // function call not function object
};
console.log("----");
yourObject.func();
Sản xuất
outer func: this.foo = bar
outer func: self.foo = bar
----
inner func: this.foo = blat
inner func: self.foo = bar
Lưu ý cách hàm bên trong không được gọi cho đến khi được gọi bởi yourObject. Vì vậy this.foo bây giờ là yourObject.foo nhưng bản thân vẫn phân giải thành biến trong phạm vi bao quanh, tại thời điểm đối tượng hàm bên trong được trả về, là (và trong kết quả đóng vẫn là) myObject. Vì vậy, trong hàm bên trong, "this" đề cập đến đối tượng gọi hàm bên trong trong khi "bản thân" đề cập đến đối tượng được gọi là hàm bên ngoài để tạo tham chiếu đến hàm bên trong.
Để tóm tắt tóm tắt của tóm tắt, "cái này" được định nghĩa bởi tiêu chuẩn ngôn ngữ, "bản thân" được định nghĩa bởi bất kỳ ai định nghĩa nó (người thực hiện thời gian chạy hoặc người lập trình kết thúc).