我有一个使用另一个对象(不是单例)的单例对象,需要一些信息到服务器:
var singleton = (function(){
/*_private properties*/
var myRequestManager = new RequestManager(params,
//callbacks
function(){
previewRender(response);
},
function(){
previewError();
}
);
/*_public methods*/
return{
/*make a request*/
previewRequest: function(request){
myRequestManager.require(request); //err:myRequestManager.require is not a func
},
previewRender: function(response){
//do something
},
previewError: function(){
//manage error
}
};
}());
这是向服务器发出请求的“类”
function RequestManager(params, success, error){
//create an ajax manager
this.param = params;
this._success = success; //callbacks
this._error = error;
}
RequestManager.prototype = {
require: function(text){
//make an ajax request
},
otherFunc: function(){
//do other things
}
}
问题是我无法从单例对象中调用myRequestManager.require。 Firebug consolle说:“myRequestManager.require不是函数”,但我不明白问题出在哪里。 有没有更好的解决方案来实现这种情况?
答案 0 :(得分:6)
您的代码按照您引用的顺序排列,不是吗?单身人士出现在来源的RequestManager
上方?
如果是这样,那就是你的问题。这是相当微妙的(!),但假设您的两位引用代码按照您显示的顺序排列,这是事情发生的顺序(我将在下面详细解释):
RequestManager
。RequestManager
的实例。RequestManager
原型被替换为新原型。由于{<1}}实例在之前实例化原型已更改,因此它没有您在该(新)原型上定义的功能。它继续使用实例化时原型对象。
您可以通过重新排序代码或通过向myRequestManager
的原型添加属性而不是替换它来轻松解决此问题,例如:
RequestManager
这是有效的,因为你没有替换原型对象,你刚刚添加它。 RequestManager.prototype.require = function(text){
//make an ajax request
};
RequestManager.prototype.otherFunc = function(){
//do other things
};
看到了添加内容,因为您已将它们添加到它正在使用的对象中(而不是在构造函数的myRequestManager
属性上设置新对象)。
为什么会发生这种情况有点技术性,我将主要遵从规范。当解释器输入新的“执行上下文”(例如,函数或全局 - 例如,页面级 - 上下文)时,它执行操作的顺序不是严格的自上而下的源顺序,存在阶段。第一阶段之一是实例化上下文中定义的所有函数;在之前发生任何逐步执行的代码。在the spec的10.4.1节(全局代码),10.4.3(功能代码)和10.5(声明绑定)中详细介绍了它们的所有内容,但基本上,这些函数是在第一行的第一行之前创建的 - 步骤代码。 : - )
使用隔离的测试示例最容易看到:
prototype
正如您所看到的,如果您运行它,<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
</style>
<script type='text/javascript'>
// Uses Thing1
var User1 = (function() {
var thing1 = new Thing1();
function useIt() {
alert(thing1.foo());
}
return useIt;
})();
// Uses Thing2
var User2 = (function() {
var thing2 = new Thing2();
function useIt() {
alert(thing2.foo());
}
return useIt;
})();
// Thing1 gets its prototype *replaced*
function Thing1() {
this.name = "Thing1";
}
Thing1.prototype = {
foo: function() {
return this.name;
}
};
// Thing2 gets its prototype *augmented*
function Thing2() {
this.name = "Thing2";
}
Thing2.prototype.foo = function() {
return this.name;
};
// Set up to use them
window.onload = function() {
document.getElementById('btnGo').onclick = go;
}
// Test!
function go() {
alert("About to use User1");
try
{
User1();
}
catch (e)
{
alert("Error with User1: " + (e.message ? e.message : String(e)));
}
alert("About to use User2");
try
{
User2();
}
catch (e)
{
alert("Error with User2: " + (e.message ? e.message : String(e)));
}
}
</script>
</head>
<body><div>
<div id='log'></div>
<input type='button' id='btnGo' value='Go'>
</div></body>
</html>
会失败,因为它使用的User1
实例没有Thing1
属性(因为原型已被替换),但foo
1}}起作用,因为它使用* User2
实例(因为原型是增强的,而不是替换的)。