2013-12-14 45 views
3

雖然這個問題發生在我專門用KnockoutJS,我的問題更像是一個一般的JavaScript問題。爲什麼在Javascript中,這個上下文基於調用方式而改變?

然而,理解ko.observable()和ko.observableArray()會返回一個方法,所以當爲它們賦值時,您需要調用目標爲方法而不是簡單地爲它們賦值。我正在使用的代碼還應該支持普通對象和數組,我爲什麼需要解析爲調用方法來爲目標分配值。

想到這些2個例子:

非工作(在此上下文中調用的方法改變):

// Assigning value to the target object 
var target; 

// target can be of any of thr following types 
target = ko.observableArray(); // knockout observable array (function) 
// target = ko.observable(); // knockout observable (function) 
// target = {}; // generic object 
// target = []; // generic array 

//#region resolve method to call 
var method; 

if (isObservable(target)) { 
    // if it is a knockout observable array, we need to call the target's push method 
    // if it is a konckout observable, we need to call the target as a method 
    method = target.push || target; 
} else { 
    // if target is a generic array, we need to use the array's push prototype 
    // if target is a generic object, we need to wrap a function to assign the value 
    method = target.push || function(item){ target = item; }; 
} 
//#endregion 

// call resolved method 
method(entity); 

工作(在此上下文中精細):

if (isObservable(target)) { 
    if (target.push) { 
     target.push(entity); 
    } else { 
     target(entity); 
    }; 
} else { 
    if (target.push) { 
     target.push(entity); 
    } else { 
     target = entity; 
    }; 
} 

現在,以實際問題:

在第一種方法中,稍後在執行鏈中使用基因敲除可觀察基因敲除時,指的是this內部的上下文,試圖訪問observable本身(即在有人想知道的情況下使用this.t())。在這種特殊情況下,由於callin的方式,this已更改爲window對象,而不是指向原始可觀察對象。

在後一種情況下,淘汰賽的this上下文正常。

你們任何一個JavaScript大師都能告訴我,我的調用方式可以改變被調用函數的'this'上下文嗎?

好吧,我知道有人想小提琴所以這裏去:)

Method 1 (Uncaught TypeError: Object [object global] has no method 'peek')

Method 2 (Works fine)

附:我沒有試圖修復代碼,我試圖理解爲什麼我的代碼更改了this上下文。


UPDATE:

感謝您的快速解答!當我不知道爲什麼(特別是如何)發生某些事情時,我必須說我討厭它。從你的答案I fiddled up this quick fiddle到攝製的情況,我想我現在知道了:)

// So having an object like Foo 
function Foo() { 
    this.dirThis = function() { 
     console.dir(this); 
    }; 
}; 

// Instantiating a new Foo 
var foo = new Foo(); 

// Foo.dirThis() has it's original context 
foo.dirThis(); // First log in console (Foo) 

// The calling code is in Window context 
console.dir(this); // Second log in console (Window) 

// Passing a reference to the target function from another context 
// changes the target function's context 
var anotherFoo = foo.dirThis; 

// So, when being called through anotherFoo, 
// Window object gets logged 
// instead of Foo's original context 
anotherFoo(); // 3rd log 


// So, to elaborate, if I create a type AnotherFoo 
function AnotherFoo(dirThis){ 
    this.dirThis = dirThis; 
} 

// And and instantiate it 
var newFoo = new AnotherFoo(foo.dirThis); 

newFoo.dirThis(); // Should dir AnotherFoo (4th in log) 
+1

你問爲什麼?這是因爲這是語言設計的方式。 「context」('this'的值)是根據函數的調用方式設置的,就像你在標題中描述的一樣。 –

+1

這個答案包含有關'this'如何在JavaScript中工作的一個很好的解釋:http://stackoverflow.com/a/134149/1443358 –

+1

這是非常長的囉嗦;你應該發佈**最短的**例子來重現你的問題,在這種情況下,它將大約兩行代碼。 – meagar

回答

1

考慮這個例子,

function Person() { 
    this.fname = "Welcome"; 
    this.myFunc = function() { 
     return this.fname; 
    } 
}; 

var a = new Person(); 
console.log(a.myFunc()); 
var b = a.myFunc; 
console.log(b()); 

輸出

Welcome 
undefined 

當你撥打電話到a.myFunc(),當前對象(this)設置爲a。所以,第一個例子工作正常。

但在第二種情況下,var b = a.myFunc;您只能獲得對該函數的引用,並且在調用它時,不會調用任何特定對象,因此窗口對象被分配。這就是爲什麼它打印undefined

要解決這個問題,你可以明確地傳遞this參數與call功能,這樣

console.log(b.call(a)); 

因此,對於你的情況,你可能不得不這樣做

method.call(target, entity); 

檢查fixed fiddle

3

如果您想要選擇'this'在調用時會被使用, 你應該使用bind,這正是爲此做的。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

所以,如果SomeObject有一個push方法,然後將其存儲這樣是行不通的:

var thePushMethod = someObject.push; 

既然你寫這個的時候失去功能的情況下。

現在,如果你這樣做:

var thePushMethod = someObject.push.bind(someObject); 

的背景下,現在裏面存放thePushMethod,你只是,你還可以綁定參數

thePushMethod(); 

公告稱,因此,例如,你可能寫:

var pushOneLater = someObject.push.bind(someObject, 1); 

// then, later : 

pushOneLater(); // will push one into someObject 
相關問題