2011-11-12 36 views
2

當我運行這段代碼:「這個」是指別的嗎?

var Test = function() { 
    return this.stuff; 
}; 

Test.stuff = 'Neat!'; 

document.write(Test() || 'Not neat.'); 

爲什麼我得到 '不利落。'?爲什麼我不能使用this.stuff訪問stuff資源?

+5

你在這裏試圖做什麼? – hugomg

回答

3

雖然其他人已經發布了爲什麼發生這種情況(對this的理解不正確),但下面是一個可以可靠工作的解決方案。

更新:在ECMAScript的第5版作爲Raynos指出,when using strict mode functions,它是無效使用arguments.callee(它會拋出一個TypeError)。因此,如果使用這種方法,應謹慎行事。 (當使用[正確] ECMAScript的第5版的發動機,沒有理由使用arguments.callee在給它綁定到新的範圍函數的名字 - 一看便知結束。)

var Test = function() { 
    // arguments.callee is the current function, if any 
    return arguments.callee.stuff 
} 
Test.stuff = 'Neat!' 
alert(Test() || 'Not neat.') // Neat! 

另一種是用一個封閉:

var Test = (function() { 
    function fn() { 
    // closure over fn, which names this function-object 
    return fn.stuff 
    } 
    fn.stuff = 'Neat!' // here 
    return fn   // do not combine with function declaration! 
})() 
Test.stuff = 'Neat!' // or here 
alert(Test() || 'Not neat.') // Neat! 

或者,關閉了直接的變量:

var Test = (function() { 
    var stuff = 'Neat!' 
    return function() { 
    // variable closure, no property 
    return stuff 
    } 
})() 
alert(Test() || 'Not neat.') // Neat! 

或者......這麼多的方法。

快樂編碼。


,是由Aadit中號沙指出另一種方法是使用函數標識符來指代當前函數:

var Test = function Temp() { 
    return Temp.stuff 
} 
Test.stuff = 'Neat!' 
alert(Test() || 'Not neat.') // Neat! (But see below.) 

作爲Aadit所指出的,這是有效的,因爲每ECMAScript 5th edition specification第99頁:

在FunctionExpression標識符可以從FunctionExpression的函數體內部參考 允許函數的n遞歸地調用它自己。但是,與FunctionDeclaration不同,FunctionExpression中的標識符不能被引用,也不會影響包含FunctionExpression的範圍。

然而,某些瀏覽器(至少IE9)實現了這個錯誤(和我不知道,如果上述行爲在第三版明確定義)。考慮:

var x = function y() { return y }; y = 42; x(); 

在IE9中它將產生42,在FF8中它將產生函數對象。 IE9是這裏不正確,因爲它引入了y作爲的變量,包含作用域,這是ECMAScript禁止的函數表達式。下面是一個關於如何實現不正確的結果的上下文示例,可能會導致不同的結果:

var Test = function Temp() { 
    return Temp.stuff 
} 
Test.stuff = "Neat!" 
Temp = {} 
alert(Test() || 'Not neat.') // 'Not neat.' in IE9, 'Neat!' in FF8 
+0

使用arguments.callee和直接重複函數名稱會有什麼區別? – hugomg

+1

@missingno偏好? :)我已經使用了兩個,這取決於我想要做什麼以及它如何與代碼的其餘部分「吻合」。我無法想出一個「普遍」的優勢或劣勢,無論從我的頭頂開始,但如果我忽略了某些東西,我不會感到驚訝。注意不要太「聰明」......注意,與全局上下文中的'var Test = function(){return Test.stuff}'不同*因爲'Test'可能真的是'窗口.Test',一個屬性,而不是一個封閉的變量。有人可能會在後面用'Test = function(){}'來破壞事情... ...永遠不知道:) – 2011-11-12 04:32:28

+0

我不喜歡使用'arguments.callee'。我也不喜歡使用'var Test = function(){return Test.stuff; };'。兩者都是訪問數據的緩慢方法。這是因爲'callee'是'arguments'的一種方法,解釋器花更多的時間來訪問它。同樣,'Test'在本地範圍內不存在。因此,解釋者必須向上行進以將其定位在父範圍內。相反,我更喜歡以下方法:'var Test = function Temp(){return Temp.stuff; };'。這裏'Temp'是'Test'的別名,它存在於本地範圍內。這是一個更快,更優雅的解決方案。 ;) –

3

您從全球範圍內被稱爲Test,所以this指的是全局對象,所以this.stuff指的是全局變量stuff這是undefined這是falsy。這就是爲什麼你看到"Not neat."

你可以把它顯示Neat!這樣的:

http://jsfiddle.net/aYh5y/

window.stuff = 'Neat!'; 
var Test = function() { 
    return this.stuff; 
}; 
alert(Test() || 'Not neat.'); 

附錄

這裏有一個方法可以讓this工作作爲封閉物體

var Test = function() { 
    return this.stuff; 
}; 

var example = { 
    g: Test, 
    stuff: "Pretty neat" 
}; 

alert(example.g() || 'Not neat.'); 

這裏我們通過一個目標對象調用Test

http://jsfiddle.net/aYh5y/1/

5

類方法和變量走在原型屬性:

Test.prototype.stuff = 'Neat!' 

構造函數(我假設這是你想要的,鑑於死刑案件和this)應調用與new操作:

new Test() 

,他們不應該返回一個值(而應該使用返回this默認)

function Test(){ 
    this.instanceVariable = 17; 
    //no return! 
} 

至於你的真正需要,你可以訪問的功能和它的性能直接再

function Test(){ 
    return Test.stuff; 
} 

但是我不濫用的大風扇這樣的名稱空間的函數。我更喜歡有一個名稱空間對象來處理事件

//in a real case I would probably use the module pattern for private variables 
//but whatever... 

var Namespace = {}; 

Namespace.stuff = 'Neat!'; 

Namespace.F = function(){ 
    console.log(Namespace.stuff); 
}; 
+0

我實際上想使用像jQuery對象的類(沒有實例化):'Test('Do something'); Test.default = 500;測試('用500做點事情')' – AlicanC

+2

@AlicanC繼承人John Resig發表的關於這個話題的帖子。 http://ejohn.org/blog/simple-class-instantiation/ – danem

+0

@Pete該帖子很好,但它是從2007年。我現在無法在jQuery 1.7的源代碼中找到'arguments.calee'的單一用法。也許他們已經轉向一種新方法?我似乎無法弄清楚。 – AlicanC

0

stuff屬性被分配給函數,但是從全局讀取這個...這兩者是獨立的實體

5

這是你做了什麼:

var Test = function() {    //Test is a Function object 
    return this.stuff;     //this is a pointer to an object, not Test 
}; 

Test.stuff = 'Neat!';     //Add a property to Test 

document.write(Test() || 'Not neat.'); //this has no property stuff 

更改代碼的最後一行:

document.write(Test.call(Test) || 'Not neat.'); //this now points to Test 

的原因,你的代碼沒有工作是因爲this指針點:

  1. 當函數調用的前綴爲w時創建的構造函數的實例w ith new關鍵字。 (例如var foo = new Foo(); //the this in Foo points to foo [for the sake of explanation])。
  2. 傳遞給callapply的對象作爲第一個參數。

你想要做的,而不是什麼是一樣的東西:

var Test = function Temp() {   //Test is a Function object, alias Temp 
    return Temp.stuff;     //Temp is the same as Test, only locally 
}; 

Test.stuff = 'Neat!';     //Add a property to Test 

document.write(Test() || 'Not neat.'); //writes Neat! 

給予好評這個答案,如果你喜歡它。乾杯。

相關問題