in javascript, "this" seems to get lost when function in within an object's object
the object F has a function stored as this.fn
and this.state.fn
. can be called successfully as f.fn()
but not as 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!
the problem seems to be that the function is stored in the object state
, because this works:
f1.state.fn.call( f1 ); F.prototype.fn = function() { this.state.fn.call(this); };
which seems to imply that the this
context within F.state.fn
is not F
but rather F.state
- which to me is completely counter-intuitive - is this right!?
Within a function, this
depends entirely on how you called the function.
When you call a function using dot notation from an object this
will be automatically set to that object.
If you say someObject.someChildObject.someFunction()
then within someFunction()
you'll find this
will be set to someChildObject
.
So in your example f1.fn()
should result in this
being f1
within fn()
, but then within that function you say this.state.fn()
- which will call state
's fn()
with this
set to state
.
You can override this behaviour using call
or apply
.
Another example just for your interest:
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'
If you create a reference to a function originally defined as an object property and call the function via that reference then this
will be whatever applies to your new reference. In my example the x
reference is a global, which in practice means it belongs to the window
object. What you can learn from this is that the function that f1.f()
calls doesn't really belong to f1
at all.
Continuing that example:
f2 = {};
f2.i = "hello";
f2.f = f1.f;
f2.f(); // 'this' will be f2, so should log "hello"
When you call f2.f()
, you'll find this
is set to f2
, and because I've set a property f2.i
the function will log that property.
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!
When you call state.fn()
it prints this.i
which is state.i
which is 42
in my case but undefined
in your case.
You can alternatively force this
to not be state
but to be the object you expect it to be by doing
this.state = {
'fn': f.bind(this)
};
.bind
is ES5 however so you should get the ES5-shim
精彩评论