This pointer from internal function
i have JavaScript components, that has following architecture:
var MyComponent = function(params)
{
setup(params);
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" points to DOMWindow, not to created object
$(".some-element").click(function(){
_this.doSomething(); // it craches here, because of above
});
}
};
When something, being controlled by interaction logic, happens, sometimes i must forward execution to "public" methods of component.
In this situation, i have a problem with "this" pointer.
Sample code demonstrates it:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal();
};
function _sayInternal()
{
this.say();
};
};
To test it,
- Create an object:
var o = new Item();
- This works fine:
o.say(); // alerts "hello"
- This crashes:
o.sayInterna开发者_JAVA百科l();
I get an error:
TypeError: Result of expression 'this.say' [undefined] is not a function.
I think, such a behaviour takes place, because _sayInternal() function is declared (and not assigned to object, like "this.say = function()"). This way, it is shared across all created objects and acts like a static function in C++.
Is this true ?
No, sayInternal
is not shared between created objects. But you are right, the created objects don't have access to sayInternal
as it is not assigned to them. This function is only local to the constructor function.
this
always refers to the context a function is invoked in. If you call it like func()
, then this
refers to the global object (which is window
in browser). If you set the function as property of an object and call it with obj.func()
, then this
will refer to obj
.
If you assign a "bound" function to a variable and call it:
var method = obj.func;
method();
then this
will again refer to the global object. In JavaScript, functions are like any other value, they don't have a special relationship to the object they are assigned to.
You can explicitly set the context with call
or apply
:
var MyComponent = function(params)
{
setup.call(this, params); // <- using `call`
this.doSomething()
{
// doing something
};
function setup(params)
{
// Setup
// Interaction logic
var _this = this; // "this" to new created object
$(".some-element").click(function(){
_this.doSomething();
});
}
};
or in you other example:
var Item = function()
{
this.say = function()
{
alert("hello");
};
this.sayInternal = function()
{
_sayInternal.call(this);
};
function _sayInternal()
{
this.say();
};
};
That said, this approach to assign functions to objects is not good, because every instance will have its own this.sayInternal
function. So for the Item
code above, every creation of an instance involves creating three functions too, which is a waste of memory.
Making use of prototype inheritance would be a better way:
var Item = function() {
};
Item.prototype = (function() {
function _sayInternal() {
this.say();
};
return {
say: function() {
alert("hello");
},
sayInternal: function(){
_sayInternal.call(this);
}
}
}());
This way, _sayInternal
is only created once and all instances inherit (refer to) the prototype, so say
and sayInternal
also exist only once. The "trick" with the immediate function makes _sayInternal
only accessible by say
and sayInternal
.
精彩评论