在javascript中,当在一个对象的对象中运行时,“this”似乎会丢失

时间:2011-08-01 06:37:23

标签: javascript object scope this

对象F的函数存储为this.fnthis.state.fn。可以f.fn()成功调用,但不能f.state.fn()

function F( i, f ) {
        this.i = i;     
        this.state = { 'fn':f };
        this.f = f;
};                      
F.prototype.inc = function() { this.i++ };
F.prototype.fn = function() { this.state.fn() };
f1 = new F( 1, function() { console.log( this.i ); } );
f1.f();                 // this works
f1.inc();               // this works
f1.state.fn;            // prints the function
f1.fn();                // undefined!
f1.state.fn();          // undefined!

问题似乎是函数存储在对象state中,因为这有效:

f1.state.fn.call( f1 );
F.prototype.fn = function() { this.state.fn.call(this); };

这似乎暗示this中的F.state.fn上下文 F,而是F.state - 这对我来说完全是反...直觉 - 这是对的!?

2 个答案:

答案 0 :(得分:1)

Live example

function F(i, f) {
    this.i = i;
    this.state = {
        'fn': f,
        i: 42
    };
    this.f = f;
};
F.prototype.inc = function() {
    this.i++
};
F.prototype.fn = function() {
    this.state.fn()
};
f1 = new F(1, function() {
    console.log(this.i);
});
f1.f(); // this works
f1.inc(); // this works
f1.state.fn; // prints the function
f1.fn(); // 42!
f1.state.fn(); // 42!

当您致电state.fn()时,会打印this.istate.i在我的情况下为42,但在您的情况下为undefined

您也可以强制this不是state,而是成为您期望的对象

this.state = {
    'fn': f.bind(this)
};

.bind是ES5但是你应该得到ES5-shim

答案 1 :(得分:1)

在一个函数中,this完全取决于你如何调用函数。

使用来自对象this的点表示法调用函数时,将自动设置为该对象。

如果你说someObject.someChildObject.someFunction()然后在someFunction()内,你会发现this将被设置为someChildObject

因此,在您的示例f1.fn()中,this应该f1 fn() this.state.fn(),但是在该函数中你会说state - 这会调用{ {1}} fn() this设置为state

您可以使用callapply覆盖此行为。

另一个仅为您感兴趣的例子:

function F( i, f ) {
        this.i = i;     
        this.state = { 'fn':f };
        this.f = f;
};                      
f1 = new F( 1, function() { console.log( this.i ); } );
f1.f();   // works - 'this' will be f1
var x = f1.f; // create a reference to the same function
x();      // won't work - 'this' will probably be 'window'

如果您创建对最初定义为对象属性的函数的引用并通过该引用调用该函数,那么this将适用于您的新引用。在我的示例中,x引用是全局的,实际上它意味着它属于window对象。您可以从中学到的是f1.f()调用的函数根本不属于f1

继续这个例子:

f2 = {};
f2.i = "hello";
f2.f = f1.f;
f2.f(); // 'this' will be f2, so should log "hello"

当您致电f2.f()时,您会发现this设置为f2,并且因为我设置了属性f2.i,该功能将记录该属性。