2012-03-10 12 views
65

Tôi có một câu hỏi liên quan đến cách con trỏ "này" được xử lý trong một kịch bản hàm lồng nhau.Con trỏ "này" trong hàm lồng nhau

Giả sử tôi chèn mã mẫu sau đây vào một trang web. Tôi gặp lỗi khi tôi gọi hàm lồng nhau "doSomeEffects()". Tôi đã kiểm tra trong Firebug và nó chỉ ra rằng khi tôi ở trong hàm lồng nhau đó, con trỏ "this" thực sự trỏ đến đối tượng "cửa sổ" toàn cục - mà tôi không mong đợi. Tôi không được hiểu một cái gì đó một cách chính xác bởi vì tôi nghĩ vì tôi đã khai báo hàm lồng nhau trong một hàm của đối tượng, nên có phạm vi "cục bộ" liên quan đến hàm (tức là con trỏ "này" sẽ đề cập đến chính đối tượng đó) nó như thế nào trong câu lệnh "if" đầu tiên của tôi).

Bất kỳ con trỏ nào (không có ý định chơi chữ) sẽ được đánh giá cao.

var std_obj = { 
    options : { rows: 0, cols: 0 }, 
    activeEffect : "none", 
    displayMe : function() { 

    // the 'this' pointer is referring to the std_obj 
    if (this.activeEffect=="fade") { } 

    var doSomeEffects = function() { 

     // the 'this' pointer is referring to the window obj, why? 
     if (this.activeEffect=="fade") { } 

    } 

    doSomeEffects(); 
    } 
}; 

std_obj.displayMe(); 
+0

Câu hỏi của bạn chính xác là gì? – Sarfraz

+2

Khi được sử dụng bên trong một hàm, 'this' đề cập đến đối tượng mà hàm được gọi. – approxiblue

+6

Những gì bạn có thể làm trong phạm vi bên ngoài là một cái gì đó như 'var self = this;' và sau đó tham chiếu đến 'self' trong hàm bên trong thông qua việc đóng. – Kai

Trả lời

96

Đối tượng JavaScript thực sự dựa trên cách bạn thực hiện cuộc gọi chức năng.

Nói chung có ba cách để thiết lập đối tượng this:

  1. someThing.someFunction(arg1, arg2, argN)
  2. someFunction.call(someThing, arg1, arg2, argN)
  3. someFunction.apply(someThing, [arg1, arg2, argN])

Trong tất cả các ví dụ trên đối tượng this sẽ someThing. Việc gọi hàm không có đối tượng gốc hàng đầu sẽ giúp bạn nhận được đối tượng toàn cầu trong hầu hết các trình duyệt có nghĩa là đối tượng window.

8

Có sự khác biệt giữa các biến bao vây và "this". "this" thực sự được định nghĩa bởi người gọi hàm, trong khi các biến rõ ràng vẫn còn nguyên vẹn bên trong khối khai báo hàm được gọi là bao vây. Xem ví dụ dưới đây:

function myFirstObject(){ 
    var _this = this; 
    this.name = "myFirstObject"; 
    this.getName = function(){ 
     console.log("_this.name = " + _this.name + " this.name = " + this.name); 
    } 
} 

function mySecondObject(){ 
    var _this = this; 
    this.name = "mySecondObject"; 
    var firstObject = new myFirstObject(); 
    this.getName = firstObject.getName 
} 

var secondObject = new mySecondObject(); 
secondObject.getName(); 

bạn có thể thử nó ra ở đây: http://jsfiddle.net/kSTBy/

gì đang xảy ra trong chức năng của bạn là "doSomeEffects()", được gọi một cách rõ ràng, điều này có nghĩa bối cảnh hay "này" của hàm là cửa sổ. nếu "doSomeEffects" là một phương thức nguyên mẫu, ví dụ: this.doSomeEffects trên nói "myObject", sau đó myObject.doSomeEffects() sẽ gây ra "này" được "myObject".

+4

đối với các bản ghi nhật ký demo và lười biếng: '_this.name = myFirstObject this.name = mySecondObject' – ptim

23

this không phải là một phần của phạm vi đóng, nó có thể được coi là tham số bổ sung cho hàm bị ràng buộc tại trang cuộc gọi. Nếu phương thức không được gọi là phương thức thì đối tượng chung được chuyển thành this. Trong trình duyệt, đối tượng chung giống hệt với window.Ví dụ, hãy xem xét funciton sau,

function someFunction() { 
} 

và các đối tượng sau đây,

var obj = { someFunction: someFunction }; 

Nếu bạn gọi hàm sử dụng cú pháp phương pháp như,

obj.someFunciton(); 

sau đó this là ràng buộc để obj.

Nếu bạn gọi someFunction() trực tiếp, chẳng hạn như,

someFunction(); 

sau đó this được ràng buộc với đối tượng toàn cầu, đó là window.

Công việc phổ biến nhất xung quanh là để nắm bắt điều này vào việc đóng cửa như,

displayMe : function() {  

    // the 'this' pointer is referring to the std_obj  
    if (this.activeEffect=="fade") { }  
    var that = this; 
    var doSomeEffects = function() {  

     // the 'this' pointer is referring to global 
     // that, however, refers to the outscope this 
     if (that.activeEffect=="fade") { }  
    }  

    doSomeEffects();   
}  
3

Theo giải thích của Kyle, bạn có thể sử dụng call hoặc apply để xác định this bên trong hàm:

Đây là khái niệm đó áp dụng cho mã của bạn:

var std_obj = { 
    options: { 
     rows: 0, 
     cols: 0 
    }, 
    activeEffect: "none", 
    displayMe: function() { 

     // the 'this' pointer is referring to the std_obj 
     if (this.activeEffect == "fade") {} 

     var doSomeEffects = function() { 
      // the 'this' pointer is referring to the window obj, why? 
      if (this.activeEffect == "fade") {} 
     } 

     doSomeEffects.apply(this,[]); 
    } 
}; 

std_obj.displayMe(); 

JsFiddle

4

Để hiểu câu hỏi này, hãy thử để có được đầu ra cho đoạn sau

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); 
     (function() { 
      console.log("inner func: this.foo = " + this.foo); 
      console.log("inner func: self.foo = " + self.foo); 
     }()); 
    } 
}; 
myObject.func(); 

Đoạn mã trên sẽ ra sau ra cửa sổ Console:

outer func: this.foo = bar 
outer func: self.foo = bar 
inner func: this.foo = undefined 
inner func: self.foo = bar 

Trong chức năng bên ngoài, cả hai điều này và tự tham khảo myObject và do đó cả hai đều có thể tham khảo và truy cập đúng cách.

Trong hàm bên trong, mặc dù, điều này không còn đề cập đến myObject nữa. Kết quả là this.foo không được định nghĩa trong hàm bên trong, trong khi tham chiếu đến biến cục bộ tự vẫn nằm trong phạm vi và có thể truy cập ở đó. (Trước ECMA 5, điều này trong hàm bên trong sẽ tham chiếu đến đối tượng cửa sổ toàn cục; trong khi, với ECMA 5, hàm này trong hàm bên trong sẽ không được xác định.)

+1

Trong hàm bên trong,' this' đề cập đến đối tượng cửa sổ (trong môi trường trình duyệt) hoặc đối tượng GLOBAL (trong một nút) .js environment) – raneshu

+0

Tại sao điều đó xảy ra? – setu

+0

@raneshu "sử dụng nghiêm ngặt" và 'điều này 'không còn đề cập đến cửa sổ – rofrol

15

Vì đây dường như là một trong những câu hỏi được upvoted nhiều nhất của loại hình này, hãy để tôi thêm, sau tất cả những năm này, giải pháp ES6 sử dụng các chức năng mũi tên:

var std_obj = { 
    ... 
    displayMe() { 
    ... 
    var doSomeEffects =() => { 
         ^^^^^^^ ARROW FUNCTION  
     // In an arrow function, the 'this' pointer is interpreted lexically, 
     // so it will refer to the object as desired. 
     if (this.activeEffect=="fade") { } 
    }; 
    ...  
    } 
}; 
+1

Bây giờ * đó là * tiến bộ! –