Javascript Class + Properties不坚持他们的价值观

时间:2010-10-25 13:37:43

标签: javascript oop properties

我正在尝试用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课程的新手,所以我不确定需要做什么,所以我希望有人可以帮助我。 :)

谢谢你的时间!

4 个答案:

答案 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();

执行方法时,您可以使用其callapply方法指定您希望在其中执行的上下文:

// 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