JavaScript对象参考

时间:2015-10-12 09:47:39

标签: javascript object reference pass-by-reference

我已经看到很多关于这种情况的问题,但我仍然无法弄清楚,究竟我的问题是什么。 (我还在尝试使用JavaScript,尤其是对象)

代码:

function Field(val) 
{ var value = val; 
this.__defineGetter__("value", function(){ return value; });
this.__defineSetter__("value", function(val){ value = val; if(this.onchange) this.onchange.call(); });
}


function LW_makePlan()
{

    /* [...] */
    this.Filter1=new Field("");
    this.Filter2=new Field("");
    this.Filter3=new Field("");


    this.init = function() 
    {
        /* [...] */

        this.Filter1.onchange=this.getSomething;
    }

    this.getSomething = function()
    {
        arg="modus=doWhat";
        arg=arg+"&filter1=" + this.Filter1.value;
        arg=arg+"&filter2=" + this.Filter2.value;
        arg=arg+"&filter3=" + this.Filter3.value;
        request_fkt(null, true, arg , this.setSomething);
    }

    this.setSomething = function(data)
    {
        alert(data);
    }

    this.init();

};

我正在尝试:

test = new LW_makePlan();
test.Filter1.value="anything";

test.Filter1有一个" onchange" -property,在" Field"的setter中检查。如果设置,setter也将调用onchange-property中给出的对象。

这到目前为止工作但看起来,这个调用创建了一个全新的对象 - 实例......不是一个实例,就像函数" getSomething"被复制为一个独立的函数,因为我调用了代码,但是例如函数中的this.Filter1" getSomething"未定义......

为什么会发生这种情况?我该如何避免这种情况?

PS:我不想使用某种类型的事件处理 - 来自第三方代码的东西,我想自己做一些帮助。

编辑:

感谢Steffen Heil,改为:

var scope=this;
this.Filter1.onchange=function() { scope.getSomething(); };

它有效!

1 个答案:

答案 0 :(得分:1)

您对this.onchange的来电位于Field,因此您正在调用Field的函数。作业this.Filter1.onchanged=this.getSomethinggetSomething方法从LW_makePlan复制到Field,并将其调用。{/ p>

因此getSomething内部现在称为onchanged,引用this引用Field而非LW_makePlan

用这个替换作业:

var source = this;
this.Filter1.onchange = function() { return source.getSomething(); };

它会起作用。大多数框架都有bind方法,使其更具可读性(将额外变量隐藏在范围内)。

回复第一条评论:

您可以显式调用这样的函数:

x.call( object, arg1, arg2, ag3 );
x.apply( object, [ arg1, arg2, arg3 ] );

这些是相同的,x是什么并不重要。被调用函数this内部的值为object。 x可以是:

alert
window.alert
(function(){})
(alert)
(window.alert)

对函数的正常调用是快捷方式:

object.f = g;
object.f( arg1 )        =>  g.call( object, arg1 );
f( arg1 )               =>  f.call( window, arg1 );

虽然window是浏览器中的全局对象;其他环境可能会使用另一个全局对象。

虽然这两个快捷方式之间的区别似乎很明显,但下面会怎样呢?

(object.f)( arg1 )

这是完全有效的javascript,因为object.f是一个函数,可以使用(args1)调用函数。但是:

object.f = g;
(object.f)( arg1 )       => g.call( window, arg1 )

因此a.f = b.f;将成员引用从a复制到b,但是this上下文,代码执行时取决于f的方式调用。

a.f(x) == a.f.call(a,x) == (a.f).call(a,x) == b.f.call(a,x) == (b.f).call(a,x)
b.f(x) == b.f.call(b,x) == (b.f).call(b,x) == a.f.call(b,x) == (a.f).call(b,x)

顺便说一下,您可以非常轻松地定义自己的bind

function bind( object, method ) {
  return function() {
    return object[ method ].apply( object, arguments );
  };
}

然后原始代码将成为:

this.Filter1.onchange = bind( this, 'getSomething' );

这将匹配我上面使用"后期绑定"的修复。大多数图书馆更喜欢"早期绑定":

function bind( object, method ) {
  return function() {
    return method.apply( object, arguments );
  };
}

然后原始代码将成为:

this.Filter1.onchange = bind( this, this.getSomething );

优点是性能更好,但主要区别在于调用bind后getSomething更改时发生的情况。第一个实现调用新值,第二个实现调用旧值。