我正在尝试用javascript创建一个类。我用JSON类型的对象创建它。
这样做:
Foo = {
PubId: '',
Init:function( oCallback )
{
this.sendCommand( 'INIT', {}, oCallback );
},
sendCommand : function( sCommand, aParams, oCallback )
{
setTimeout( oCallback, 1000, '{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}' );
return true;
},
onData : function( sData )
{
var aRes = JSON.parse( sData );
this.PubId = aRes.pubid;
alert( this.PubId );
return this.PubId;
},
umtest:function(){ alert( this.PubId ); }
}
然后我在包含脚本之后也这样做了:
Foo.Init( Foo.onData );
问题是this.PubId在onData方法中更新,但在它之外,pubid是空的。
我是javascript课程的新手,所以我不确定需要做什么,所以我希望有人可以帮助我。 :)
谢谢你的时间!
答案 0 :(得分:2)
你这里有两个问题。 第一个问题并不了解this
在Javascript中的工作原理。通过Foo.onData
调用setTimeout( oCallback, ...)
时,this
将引用全局对象而不是Foo
。
要将Foo
称为this
,我们应该更改您的代码:
sendCommand: function (sCommand, aParams, oCallback) {
var that = this; // save this reference
setTimeout(function () {
oCallback.call( that, // call the function with it
'{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}' );
}, 1000);
return true;
},
为了测试更改的内容,请将此代码添加到onData
:
// is `this` really Foo or the global object?
alert(this === Foo); // should be true
alert(this === window); // should be false
在更新版本中this
将正确引用Foo
作为调用对象。
您可能遇到的第二个问题是,使用setTimeout
调用的函数只会在1000 ms = 1s
之后执行,所以如果您只是检查{{1}在alert(Foo.PubId)
之外你会得到一个空字符串(因为还没有调用回调)。
为了测试Foo
是否确实发生变化:
Foo.PubId
您可以查看完整的测试用例here。
答案 1 :(得分:1)
当使用点表示法调用属于对象的方法时,其上下文(this
指向的位置)是它所连接的对象。例如:
// Context: `this` is `myObj`
myObj.myMethod();
但是,当您将该函数的引用存储在另一个变量中时,它会丢失该上下文关系,并且该上下文将成为全局对象:
// Context: `this` is the global object - `window` in a web browser
var myMethod = myObj.myMethod;
myMethod();
执行方法时,您可以使用其call
或apply
方法指定您希望在其中执行的上下文:
// Context: `this` is `myObj`
var myMethod = myObj.myMethod;
myMethod.call(myObj);
在您的特定示例中,我会考虑使用在名为bind
的较新版本的JavaScript中引入的新方法。 IE9,Firefox 4以及较新版本的Google Chrome和Safari都支持bind
,它允许您将功能“锁定”到特定的上下文。您可以使用以下代码(取自Function.prototype.bind的MDC文档)在不支持它的浏览器中实现其大部分功能:
// PARTIAL WORKAROUND for Function.prototype.bind
if (!Function.prototype.bind)
Function.prototype.bind = function(context /*, arg1, arg2... */) {
'use strict';
if (typeof this !== 'function') throw new TypeError();
var _slice = Array.prototype.slice,
_concat = Array.prototype.concat,
_arguments = _slice.call(arguments, 1),
_this = this,
_function = function() {
return _this.apply(this instanceof _dummy ? this : context,
_concat.call(_arguments, _slice.call(arguments, 0)));
},
_dummy = function() {};
_dummy.prototype = _this.prototype;
_function.prototype = new _dummy();
return _function;
};
在代码中使用它非常简单:
Foo.Init( Foo.onData.bind(Foo) );
答案 2 :(得分:0)
onData独立于类执行。
你必须像这样打电话
Foo.Init(function(d) { Foo.onData(d);} );
让它按预期工作。
答案 3 :(得分:0)
这是一个范围问题。当您将Foo.onData
传递给init
函数时,它会“失去”与该类的连接。函数是第一类对象,因此它们可以自己存在。您可以执行以下操作:
Foo = {
PubId: '',
Init:function(oCallback, scope)
{
this.sendCommand('INIT', {}, oCallback, scope);
},
sendCommand : function(sCommand, aParams, oCallback, scope)
{
var cb = oCallback;
if(scope) {
cb = function(data) {
oCallback.call(scope, data);
};
}
setTimeout( cb, 1000, '{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}' );
return true;
}
//...
}
然后用
调用它Foo.Init(Foo.onData, Foo);
传递给call()
的第一个参数将在方法内变为this
。