Tại sao “this” trong một hàm ẩn danh không được xác định khi sử dụng nghiêm ngặt?


85

Tại sao điều này trong một hàm ẩn danh không được xác định khi sử dụng javascript ở chế độ nghiêm ngặt? Tôi hiểu tại sao điều này có thể có ý nghĩa, nhưng tôi không thể tìm thấy bất kỳ câu trả lời cụ thể nào.

Thí dụ:

(function () {
    "use strict";

    this.foo = "bar"; // *this* is undefined, why?
}());

Kiểm tra trong một fiddle: http://jsfiddle.net/Pyr5g/1/ Kiểm tra trình ghi nhật ký (firebug).


4
Lưu ý rằng điều này không liên quan gì đến các hàm ẩn danh, mà là phương thức gọi. Xem fiddle sửa đổi này (xem trong nhật ký bảng điều khiển).
Phrogz

@Phrogz: Đây có thể là nguyên nhân của một số nhầm lẫn. Cảm ơn vì đã chỉ ra điều đó.
T. Junghans

Câu trả lời:


101

Đó là bởi vì, cho đến ECMAscript 262 phiên bản 5, có một sự nhầm lẫn lớn nếu những người sử dụng nó constructor pattern, quên sử dụng newtừ khóa. Nếu bạn quên sử dụng newkhi gọi một hàm tạo trong ES3, hãy thistham chiếu đến đối tượng toàn cục ( windowtrong trình duyệt) và bạn sẽ chặn đối tượng toàn cục bằng các biến.

Đó là hành vi khủng khiếp và để mọi người tại ECMA quyết định, chỉ để thiết lập thisđể undefined.

Thí dụ:

function myConstructor() {
    this.a = 'foo';
    this.b = 'bar';
}

myInstance     = new myConstructor(); // all cool, all fine. a and b were created in a new local object
myBadInstance  = myConstructor(); // oh my gosh, we just created a, and b on the window object

Dòng cuối cùng sẽ báo lỗi trong ES5 nghiêm ngặt

"TypeError: this is undefined"

(đó là một hành vi tốt hơn nhiều)


4
Điều này thật ý nghĩa. Bạn có tài liệu tham khảo để sao lưu báo cáo không?
Rob W

1
@RobW: Tôi sẽ phải tự tìm kiếm, nhưng tôi đã nghe Douglas Crockford nói vài lần, đây là lý do cho quyết định đó.
jAndy

1
Nó được đề cập trong JavaScript: The Good Parts của Crockford. Nó được mô tả chi tiết. Tuy nhiên, không phải về quyết định ECMAs.
madr

1
Đây là lý do hợp lý cho việc tại sao chế độ nghiêm ngặt mặc định điều này là không xác định. Lý do hợp lý khác là hiệu quả, lý do logic khác là this === windowlà khó hiểu và rò rỉ phạm vi toàn cầu như một thẻ vào chức năng
Raynos

2
@jAndy: Cảm ơn vì câu trả lời. Điều này thật ý nghĩa. Tôi cũng tìm thấy lời giải thích ngắn gọn về những thay đổi đối với điều này trên javascriptweblog.wordpress.com/2011/05/03/… : "Đáng chú ý nhất, nếu đối số đầu tiên để gọi hoặc áp dụng là null hoặc không xác định, giá trị này của hàm được gọi sẽ không được chuyển đổi thành đối tượng toàn cục. "
T. Junghans

15

Có một cơ chế được gọi là "quyền anh" bao bọc hoặc thay đổi thisđối tượng trước khi vào ngữ cảnh của hàm được gọi. Trong trường hợp của bạn, giá trị của thisphải là undefinedvì bạn không gọi hàm như một phương thức của một đối tượng. Nếu chế độ không nghiêm ngặt, trong trường hợp này, điều này được thay thế bằng windowđối tượng. Ở strictchế độ, nó luôn không thay đổi, đó là lý do tại sao nóundefined ở đây.

Bạn có thể tìm thêm thông tin tại
https://developer.mozilla.org/en/JavaScript/Strict_mode


@samuel vậy làm cách nào chúng ta có thể gán một biến cho đối tượng window ở chế độ nghiêm ngặt ??
Null Pointer

8

Theo câu trả lời của This Stack Overflow , bạn có thể sử dụng thisbên trong các hàm ẩn danh, đơn giản bằng cách gọi .call(this)vào cuối nó.

(function () {
    "use strict";

    this.foo = "bar";
}).call(this);

4
Lưu ý rằng thissẽ là Windowđối tượng trong trường hợp này, mà có thể không được mong muốn
Ninjakannon

Câu trả lời này không giải thích câu hỏi được hỏi.
Anvesh Checka
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.