2010-12-17 49 views
4

我不確定這是用JavaScript表示的。我給出了2個例子。JavaScript中的'this'是什麼引用?

你能幫我分析一下嗎?非常感謝你。

//exmp1 
function f1() 
{ 
    alert(this); 
    function f2() 
    { 
    alert(this); 
    } 
    f2(); 
} 
f1(); 

//exmp2 
var jsn = 
{ 
    name : "b", 
    func : function() // closure 
    { 
    alert(this); 
    return function() 
    { 
     return this; 
    } 
    } 
} 

alert(jsn.func()()); 
+1

**題外話**:你'jsn' VARNAME建議你在來思考[ JSON(http://json.org)。但那不是JSON,這是JavaScript Object Literal Notation。 (JSON是對象文字符號的一個子集;它需要雙引號,並且沒有函數或未定義,並且只支持十進制[不是十六進制或八進制]。)人們會混淆這兩個a * lot * :-),所以我認爲這值得一提。 – 2010-12-17 08:27:19

回答

13

this是不同的JavaScript比在像C++或Java的其他語言。第一個示例中的this的值將始終是全局對象(window,在瀏覽器上)。第二個示例中的this是第一個警報的jsn對象,第二個示例的window。這是因爲this完全由確定通過如何調用一個函數,而不是它的定義。

如果在調用函數時沒有做任何特別的事情,則this是全局對象。當您通過對象屬性(jsn.func())調用函數時,將this設置爲屬性來自的對象。 (但不要錯誤的印象,func是不是專門綁定到jsn; JavaScript沒有方法,只是功能; details。)f1然後返回一個函數,它在最後alert內調用;由於該調用不是通過對象屬性,因此將this設置爲全局對象。

一些例子:

// Simple function 
function foo() { 
    alert(this === window); 
} 
foo(); // true, within the call, `this` === `window` 

// Object example, and twist at the end 
var obj = { 
    func: function() { 
     alert(this === obj); 
    }, 
}; 
obj.func(); // true, within the call, `this` === `obj` 
obj["func"](); // true, within the call, `this` === `obj` 

var f = obj.func; // Not calling it, just getting a reference to the function 
f(); // false, within the call `this` !== `obj` (`this` === `window`) 

// Creating functions on the fly, returning them, and how that has 
// nothing whatsoever to do with how `this` gets set: 
var obj = { 
    func: function() { 
     return function() { 
      alert("I'm a generated function"); 
      alert(this === obj); 
     }; 
    } 
}; 
obj.func()(); // alerts the "I'm a generated function", then false; `this` !== `obj` 
obj.bar = obj.func(); 
obj.bar(); // alerts the "I'm a generated function", then true; `this` === `obj` 

有控制什麼this是一個函數內的第二種方法:使用JavaScript函數的.call.apply特點:

var obj = { 
    func: function() { 
     alert(this === obj); 
    } 
}; 
function foo(a, b) { 
    alert(this === obj); // Yes, really obj; see below 
    alert(a); 
    alert(b); 
} 
foo(1, 2);    // alerts false (`this` !== `obj`), then 1, then 2 
obj.func();    // alerts true, `this` === `obj` 
foo.call(obj, 3, 4);  // alerts true (`this` === `obj`), then 3, then 4 
foo.apply(obj, [5, 6]); // alerts true (`this` === `obj`), then 5, then 6 

正如你所看到的,第一個參數爲callapply是在函數調用中使this的對象。 callapply之間的唯一區別是指定參數以傳遞到目標函數:使用call,您只需在第一個參數後面提供參數;與適用,你提供他們作爲一個數組。

最後,還有第三種方法:new關鍵字。 JavaScript具有構造函數的概念。構造函數的目的是創建以特定方式初始化的對象的實例。這裏有一個例子:

function Foo(b) { 
    this.bar = b; 
} 
var f = new Foo(); 

從技術上講,任何功能可以作爲一個構造函數。該公約旨在提供與大寫字母開頭的new名稱一起使用的功能,以加強我們以特殊方式稱呼它們。

通過new調用函數將創建一個新的對象實例,並在該函數調用中使該對象成爲this的值。所以

function Foo(b) { 
    alert(this === window); 
} 
var f = new Foo(); // alerts false, `this` !== `window` (it points to the new object created for the call) 
var f = Foo();  // alerts true, `this` === `window` because we didn't use `new` 

正如你所看到的,以正確的方式調用一個函數是很重要的。如果它的設計與new一起使用,請通過new致電;如果不是,不要。

new不僅僅是創建一個空白對象,創建的對象還有一些其他方面的設置,我不會在這裏詳細討論,但我不想留下印象所有它所做的就是創建一個新的對象實例。)

+1

+1很好的答案。所有的基礎都以簡單的英語爲基礎。每當這個問題再次出現時,我會指出這個答案。 – slebetman 2010-12-17 08:19:47

0

當您使用函數作爲構造函數時,它指向您正在構造的對象。

function Test() { 
    this.test = true; 
} 

t = new Test(); 
alert(t.test); 
+0

*「當您使用函數作爲構造函數時,它指向您正在構建的對象」*真實但無關緊要。他從未在代碼中做過這件事。沒有什麼新東西。 – 2010-12-17 07:42:35

+0

我不熟悉javascript。我認爲這是唯一的用途,所以我學到了一些東西[= – 2010-12-17 07:44:13

1

在您的最後一個例子(JSON對象內部的功能),this是指持有該函數的JSON對象。

在第一個示例中,第一個this指的是持有f1的對象,它恰好是全局窗口對象。 f2中的第二個this也指的是全局對象而不是f1,並且這是一個javascript中的已知錯誤,當​​您在另一個函數中定義了一個函數時。

一個共同的解決辦法是這樣的(沒有雙關語意):

function f1() { 
    alert (this); 
    var that = this; 
    function f2() { 
    alert (that); 
    } 
    f2(); 
} 

請注意,如果你在一個JSON對象定義一個函數,它仍然是「搬來搬去」和this情況下會發生變化。例如:

var car1 = { 
    color: "red", 
    f: function() { alert (this.color); } 
} 

car1.f(); // prints "red" 

var car2 = { 
    color: "blue", 
} 

car2.f = car1.f; 

car2.f(); // prints "blue" 
1

在JavaScript「這」總是指「擁有」該對象的功能,或者更確切地說,向其中一個功能是通過在它被稱爲時的屬性綁定的對象。考慮下面這個例子:

var f = function() { alert(this); } 
f(); // Alerts the "DOM window" (global) object, which 
    // is implied if there is no explicit owner. 
var o = {toString:function(){return "Foo!";}} 
o.func = f; 
o.func(); // Alerts the "Foo!" object (o) since the 
      // function then belongs to it as a member. 

現在關於你的具體的例子,這裏發生了什麼:

//exmp1 
function f1() { 
    alert(this); 
    function f2() { 
    alert(this); 
    } 
    f2(); // Alerts "the global object", since f2 
     // is not bound to any object's property. 
} 
f1(); // Alerts "the global object" (probably DOM window) 
     // for same reason as above. 

//exmp2 
var jsn = { 
    name : "b", 
    func : function() { 
    alert(this); // Will alert the "jsn" object, since it 
       // owns the function in its "func" member. 
    return function() { 
     return this; // Returns whoever is calling it! 
    }; 
    } 
} 
alert(jsn.func()()); // "jsn.func()" returns a function which gets 
        // called by the global "DOM window" object. 
+0

*「...擁有」函數的對象...「*對象不具有函數,或者至少,如果它們具有(例如,通過具有指向該函數的屬性),則它沒有任何除了當你通過屬性調用函數時使用'this'做。建議刪除或修改陳述。另外,在做'apply'的例子時使用原語似乎是一個非常奇怪的選擇。 – 2010-12-17 07:53:48

+0

感謝您的提示:「所有權」的清晰度不想混淆任何人。應用處理原語必須是V8的一個怪癖,自動提供Object wrappers,ECMA262 5th Ed。的確聲明它應該是一個TypeError。 – maerics 2010-12-17 08:01:51

+0

這不是V8的怪癖。會發生什麼是因爲'apply'需要一個對象,所以該原語被提升爲一個對象(也就是說,一個等價的對象被創建並用該原語的值初始化)並用於調用該函數。但是到達函數的東西並沒有連接到原語。例子:http://jsbin.com/ipuzo4/2調用'apply'並傳入一個原語是完全有效的,但我不會在一個基本的例子中使用它。 :-) – 2010-12-17 08:09:25

相關問題