javascript OOP混乱
可能重复:javascript OOP混乱,javascript,Javascript,可能重复: 我有一个这样定义的类 function SocialMiner(tabUrl) { var verbose=true; var profileArray=new Array(); this.tabUrl=tabUrl; this.getTabUrl=function(callback) { chrome.tabs.getSelected(null, function(tab) {
我有一个这样定义的类
function SocialMiner(tabUrl)
{
var verbose=true;
var profileArray=new Array();
this.tabUrl=tabUrl;
this.getTabUrl=function(callback)
{
chrome.tabs.getSelected(null, function(tab)
{
callback(tab.url);
});
}
this.setTabUrlValue=function(pageUrl)
{
this.tabUrl=pageUrl;
console.log("22"+this.tabUrl); //this statement shows url correctly
}
}
当我像这样调用这个方法时
miner.getTabUrl(miner.setTabUrlValue);
miner.logToConsole("1"+miner.tabUrl); //This statement returns undefined
回调内部的
console.log
正确输出url
,但是miner
ojbect的tabUrl
属性未定义,如第二个console.log
中所示。为什么会这样?我认为发生这种情况是因为闭包变量在函数调用中无法生存。解决方案是在构造函数中保存对该的引用(稍后可通过闭包获得):
在setTabUrlValue
中使用:
that.tabUrl=pageUrl;
我怀疑将方法作为函数(回调
)运行会失去作用域,即不再知道任何此
。换句话说,它在构造函数的范围内运行,而不是作为使用它的实例的方法。函数可以使用构造函数范围中引用this
的变量,并且在实例创建时指向右侧this
您还可以强制回调
在当前实例范围内运行,如下所示:
callback.call(this,tab.url);
console.log("5");
miner.getTabUrl(function(pageUrl) {
miner.setTabUrlValue(pageUrl);
console.log("6");
miner.logToConsole("1"+miner.tabUrl);
console.log("7");
});
在这种情况下,您可以留下this.tabUrl=pageUrl代码>原样
这是对代码的简化。这些方法返回this
,以便能够直接引用实例的属性(请参见console.log
最后一行):
再看看@您的代码,我认为您两次失去了作用域,因为callback
是从另一个回调中调用的。这就是为什么我认为你的代码应该是:
chrome.tabs.getSelected(
null,
function(tab) {
callback.call(that,tab.url); //< use that here
}
);
chrome.tabs.getSelected(
无效的
功能(选项卡){
callback.call(即tab.url);//<在这里使用它
}
);
此外,在您编写的代码@github中,我没有看到任何miner
实例的实例化。这是JavaScript中一个棘手的问题,正如其他人指出的,这是问题的关键。在任何地方使用this
的问题在于,它的值可能会根据调用函数的人/地点而变化(例如,请参阅JavaScript中的和方法)。我猜想,如果您将this
的值写入控制台中的chrome.tabs.getSelected
函数的回调中,您会发现它不再是您的矿工
解决方案是,当您确信它是正确的时,捕获对您实际感兴趣的这个的引用,然后从那时起使用该引用。在您的示例中,看到它的注释可能更有意义:
function SocialMiner(tabUrl)
{
//At this point we know "this" is our miner object, so let's store a
//reference to it in some other (not so transient) variable...
var that = this;
var verbose=true;
var profileArray=new Array();
this.tabUrl=tabUrl;
this.getTabUrl=function(callback)
{
chrome.tabs.getSelected(null, function(tab)
{
//at this point "this" is whatever the "chrome.tabs.getSelected"
//method has decided it is (probably a reference to the tab or something)
callback(tab.url);
});
}
this.setTabUrlValue=function(pageUrl)
{
//because this can be called from anywhere, including the chrome callback
//above, who knows what "this" refers to here (but "that" is definitely
//still your miner)
that.tabUrl=pageUrl;
console.log("22"+that.tabUrl);
}
}
您可以看到,在像jQuery这样大量使用回调的库中,this
的变化有多大,在jQuery中,this
通常被设置为方便的值,但肯定不是您最初调用时逻辑范围内的this
编辑:看看,这只是一个时间问题,chrome.tabs.getSelected
显然在您对日志的“第二次”调用完成后异步返回
console.log("5");
miner.getTabUrl(miner.setTabUrlValue); //setTabUrlValue is logging with '22'
console.log("6");
miner.logToConsole("1"+miner.tabUrl);
console.log("7");
// Output:
5
6
1 undefined //the chrome.tabs.getSelected hasn't returned yet...
7
22 http://url //now it has (so if you tried to use miner.tabUrl now you'd be all good...
解决方案是将get/set之后的所有内容放入回调,因为在tabUrl设置完成之前,您不希望发生任何事情。。。比如说:
callback.call(this,tab.url);
console.log("5");
miner.getTabUrl(function(pageUrl) {
miner.setTabUrlValue(pageUrl);
console.log("6");
miner.logToConsole("1"+miner.tabUrl);
console.log("7");
});
希望您能按照预期的顺序得到结果。是否存在logToConsole
方法?因此,这个问题有3个正确的答案,问题是对“this”是什么的误解。您无法获得有效答案的原因是,您的代码段高度依赖于脚本的其余部分。我强烈建议您访问jsfiddle.net,一起获得一个更通用的答案来说明您的问题。这将使你更容易理解你的问题,并给你一个正确的答案。@Matt:请看更正后的代码,它仍然不起作用。第二行未定义miner.TabUrl。这不是重复的,你回复中的帖子包含了一个不同的问题,你可以详细说明一下,我认为这是因为回调是异步执行的。不是吗?对callback()的调用不会保留正在操作的对象。这是一个静态函数调用。您需要做的是将回调作为一个方法应用于对象:callback.call(this,pageUrl)@扎斯:上面的解决方案似乎不起作用。你能解释一下吗?我试过了,但没有起作用。请看这里的要点:嗨,Madhur Ahuja,请看编辑后的答案。也许我会晚一点再看,但现在已经很晚了,该睡觉了;~)祝你晚安,但还是不走运:(谢谢。我没有看到构造函数中定义了.logToConsole
,这可能是问题所在吗?@Kooilnc:请在这里查看完整的代码,谢谢您的详细解释。我现在正在使用这个实现,如gist中所示。但是,第二行仍然在为miner打印未定义的。tabUrl@Madhur-查看我的编辑。。。