Is it safe to use the keyword "this" to create new Locker? I am afraid that "this" may point to something else at the runtime. I am new to JavaScript and closures.
var Employee = function() {
this.initialize.apply(this, arguments);
};
_.extend(Employee.prototype, {
initialize : function(opts) {
this._locker = new Locker({
employee : this
});
// OR
var self = this;
this._locker = new Locker({
employee : self
});
}
});
Looking at this code in particular:
this._locker = new Locker({
employee : this
});
Assuming that this already points to the right object, the above doesn't introduce a new scope; it would be the same as writing:
var options = {
employee : this
};
this._locker = new Locker(options);
You don't need to use self in this case.
You will have seen self used when someone wishes to pass the value of this into a different scope as a closure.
var self = this;
var myFunc = function() {
// do something with self (aka this)
};
In the example above this inside myFunc won't be known until the function is invoked - google 'dynamic vs static scoping' - and it won't be the 'this' from outside of the function. That this is passed through as self in my example.
Note: that you don't have to use self any other variable name will do.
In your example you aren't attempting to pass this into a different scope so it should be fine.
Both snippets act the same.
The value of this is determined by how a function is called, so you are right in that this may point to something else at runtime.
However, once initialize has been called the value of this for that call has already been set. So:
var self = this;
this._locker = new Locker({
employee : self
});
Just adds an intermediate step, assigning this to a temporary variable (see Jack's) answer
Your safer bet would be to use "this," since you are using apply and passing "this." Apply will force "this" keyword to be the thisArg that you passed to the function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
"self" is set to the Window object earlier in the initialization, but I don't think it changes after, unless you specifically change it.
Is it safe to use the keyword "this" to create new Locker?
Yes.
> var Employee = function() {
> this.initialize.apply(this, arguments);
> };
Within a function called with new (i.e. called as a constructor), this will always point to the new instance. Using apply means that arguments is not passed as an Object, but as a sequence of values. So I think you should be doing:
function Employee () {
this.initialize(arguments);
}
Note that function declarations are less code and more reliable than function expressions.
> _.extend(Employee.prototype, {
> initialize : function(opts) {
Since you are calling this with apply and using arguments as the parameter object, the arguments are passed individually by value. So opts will be the first value of the arguments originally passed to the Employee constructor, the others will be available as members of this new function's arguments object.
>
> this._locker = new Locker({
> employee : this
> });
> }
The value of this is set when a function is called (or by bind). In this case, initialize is intended to be called as a method of an instance so this will reference the instance. It could be called some other way so this references some other object (or any value if in strict mode), but the following has no effect on that.
This code doesn't make any difference to the value passed to Locker:
> var self = this;
> this._locker = new Locker({
> employee : self
> });
You seem to be trying to avoid a closure, but there is no closure here to avoid. Closures aren't caused by a function call, but by functions returning other functions that are created within them (through declarations or expressions). These functions continue to have access to the outer function's lexical environment after they have completed, e.g.
var foo = (function() {
var bar = 'bar';
return function(){ return bar;};
}());
foo(); // bar
The function foo has a closure to the variable bar declared in an outer function. No other function can access bar to read or set its value, it's only available to foo (this is how private members are emulated in javascript).
Where you run into trouble is where the value of the variable held in the closure is unexpectedly changed after the closure has been formed. That will not happen in the original code.
Related
Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.
Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.
Maybe the title sounds a little bit weird (please improve it) -- but I need a solution for the following scenario. I have the following code:
var Foo = function () {
this._hello = "world!";
};
Foo.prototype.bar = function () {
console.log(this._hello);
};
var f = new Foo();
f.bar(); // => "world!"
f.bar.apply(this); // => undefined
I know that apply changes the context, so inside of bar, this will be the global object (at the second call).
But what I need is to access this from Foo function. A solution that I see would be:
var Foo = function () {
var self = this;
self._hello = "world!";
self.bar = function () {
console.log(self._hello);
};
};
However, I would choose not to have method declarations inside of another function.
I'd prefer to define methods same column level (just for code style):
var Foo = ...;
Foo.prototype.method = ...;
Is this possible? How?
You can use the bind() method to tackle these kinds of problems. Instead of something.method(f.bar) call something.method(f.bar.bind(f)) to get the bar method always called on the expected context (f).
If you don't want to use bind in every location where you pass bar around as a callback, you can also put it in the constructor to create a dedicated bound function for every instance by default:
function Foo() {
this._hello = "world!";
this.bar = this.bar.bind(this);
}
Foo.prototype.bar = function () {
console.log(this._hello);
};
var f = new Foo;
something.method(f.bar); // works!
It's not possible to do this by assigning a function to the prototype like this.
Unless you assign something to f.bar directly (as in your second example, and Bergi's answer), the value you will get for f.bar is a reference to the function you assigned to the prototype's property Foo.prototype.bar. This will be exactly the same function object for any other object that has Foo.prototype as a prototype. There is no reference to f in this function object.
So when you call f.bar(), how does this refer to the value of f? It is a special syntax, that basically equates to f.bar.apply(f). It is only the fact that you use this method-call syntax that sets this to the value of f. Any other reference to f.bar will just evaluate to the prototype's single, shared function object.
If you call it with f.bar.apply(somethingElse), this is now set to somethingElse, and all association with f is lost.
It's not a question of apply(...) changing scope. fn.apply(x) sets this to x within fn, whereas y.fn() sets this to y.
Similarly, in your example if you assign f.bar to a variable and then invoke it via the variable instead of using the method-call syntax f.bar(), your this will be the window object (if running in a browser) and again you'll get undefined.
var func=f.bar; // now func === Foo.prototype.bar
func(); // => undefined
See also How to find the object a function belongs to?
When I declare a new object type :
var MyType = function(constructorArg) {
this.whatever = constructorArg;
};
var myTypeInstance = new MyType('hehe');
In that case, this refers to the function assigned to MyType.
Now let's add a simple accessor for the property whatever (without using the prototype) :
var MyType = function(constructorArg) {
this.whatever = constructorArg;
this.getWhatever = function() {
// Here this should logically point to the function assigned
// to this.whatever instead of the current instance of MyType.
return this.whatever;
};
};
This works right ?
But why isn't this, inside the body of the function assigned to the property whatever, not pointing to that function itself ?
Thanks for your help !
EDIT : I'll modify my example :
var MyType = function(arg) {
this.property = arg;
this.MySubType = function(subTypeArg) {
this.subTypeProperty = subTypeArg;
// What is "this" refereing to here ?
// To the instance of MyType, or to the instance of MySubType ?
// I know it would not make sense to do something like this in real world
// but i'm trying to have a clearer understanding of the way "this" is set.
};
}
EDIT : As said in the comments :
When using
myTypeInstance.MySubType('hehe');
then this refers to myTypeInstance.
When using
var mySubTypeInstance = new myTypeInstance.MySubType('hehe');
then this refers to mySubTypeInstance
If i understood well.
Regarding your edit, it is like it always is: It depends on how you call this.MySubType.
If you call it as this.MySubType(), i.e. as object method, then this (inside the function) would refer to this (outside the function), which is an instance of MyType.
If you call it as new this.MySubType() then it refers to a new instance of MySubType.
If you call it as this.MySubType.call(foo), this refers to foo.
Have a look at the MDN documentation, section "Function context".
I don't think this gets a new value assigned to it inside an anonymous function. You might want to look this page.
The inner function can be accessed only from statements in the outer function.
The inner function forms a closure: the inner function can use the arguments and variables of the outer function, while the outer function cannot use the arguments and variables of the inner function.
My guess would be that this must be accessable from inside the inner function and as such will not be overwritten.
Edit: I did not see the comments while typing, Felix Kling explains it much better in his comment.
I am using the javascript inheritance helper provided here: http://ejohn.org/blog/simple-javascript-inheritance/
I have the following code, and I have problem accessing the inherited property or function from a closure within a subclass as illustrated below. I am new to OOP javascript code and I appreciate your advice. I suppose within the closure, the context changes to JQuery (this variable) hence the problem. I appreciate your comments.
Thanks,
-A
PS - Using JQuery 1.5
var Users = Class.extend({
init: function(names){this.names = names;}
});
var HomeUsers = Users.extend({
work:function(){
// alert(this.names.length); // PRINTS A
// var names = this.names; // If I make a local alias it works
$.map([1,2,3],function(){
var newName = this.names.length; //error this.names is not defined.
alert(newName);
});
}
});
var users = new HomeUsers(["A"]);
users.work();
this in the inner function
function(){
var newName = this.names.length;
alert(newName);
}
is not the same as this in the outer function.
work: function(){
$.map([1,2,3],function(){
var newName = this.names.length;
alert(newName);
});
}
There are many ways that people work around this:
Store a reference to outer function's this as another variable
work: function(){
var that = this;
$.map([1,2,3],function(){
var newName = that.names.length;
alert(newName);
});
}
As you see, that is being used instead of this.
Use jQuery's $.proxy
work: function(){
$.map([1,2,3],$.proxy(function(){
var newName = this.names.length;
alert(newName);
}, this));
}
What $.proxy does is it creates another function that calls the function you passed in (in this case, the inner function), but explicitly set the context of the function (this) to the second arguments.
Use Function.prototype.bind
work: function(){
$.map([1,2,3],function(){
var newName = this.names.length;
alert(newName);
}.bind(this));
}
It works just like jQuery's $.proxy, but in this one, you call the bind method of the function.
It isn't supported on all browsers, but there is a JavaScript implementation of Function.prototype.bind on MDC. You can use it.
this in a confusing keyword, and if you want to learn more about this, then look at this.
The this variable is not like the others. Normal variables are always available to their child scopes, but this is, by default, set to the global window object when a function is called:
alert(this.names); # Works; this == yourObject
$.map([1,2,3],function(){
alert(this.names); # Doesn't work; this == window.
});
The documentation for jQuery.map() confirms this:
this will be the global window object.
Thus, the solution is to set another variable to this so it will be available in the child scope:
var that = this;
$.map([1,2,3],function(){
alert(that.names);
});
I recommend viewing Douglas Crockford's presentation Function the Ultimate, in which he shows all sorts of crazy things you can do with functions and objects in JavaScript.