JavaScript 对象引用

JavaScript Object 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"-属性,在 "Field" 的 setter 中检查。如果设置,setter 还将调用 onchange-属性.

中给定的对象

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

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

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

编辑:

感谢 Steffen Heil,更改为:

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

而且有效!

您对 this.onchange 的调用在 Field 中,因此您正在调用 Field 的函数。赋值 this.Filter1.onchanged=this.getSomething 将方法 getSomethingLW_makePlan 复制到 Field,它将在其中被调用。

所以在现在称为 onchangedgetSomething 中,引用 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' );

这将与我在上面使用 "late binding" 给出的修复相匹配。大多数图书馆更喜欢 "early binding":

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

那么原代码会变成:

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

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