в JavaScript «это», кажется, теряется, когда функция внутри объекта объекта - PullRequest
1 голос
/ 01 августа 2011

объект F имеет функцию, хранящуюся как this.fn и this.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 ]

1 голос
/ 01 августа 2011

Внутри функции this полностью зависит от того, как вы вызвали функцию.

При вызове функции с использованием точечной нотации из объекта this будет автоматически установлен на этот объект.

Если вы скажете someObject.someChildObject.someFunction(), то в пределах someFunction() вы обнаружите, что this будет установлено на someChildObject.

Так что в вашем примере f1.fn() должно привести к this, являющемуся f1 в fn(), но затем в этой функции вы говорите this.state.fn() - которая вызовет state 'fn() с this, установленным в state.

Вы можете переопределить это поведениеиспользуя call или apply.

Другой пример, представляющий интерес для вас:

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, функция будет регистрировать это свойство.

1 голос
/ 01 августа 2011

Живой пример

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.i, который state.i, который 42 в моем случае, но undefined в вашем случае.

В качестве альтернативы вы можете заставить this быть не state, а быть объектом, которого вы ожидаете, выполнив

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

.bind - это ES5, поэтому вы должны получить ES5-прокладку

...