I'm still confused when it comes to scope when working with object's methods. In the code below I have two neighbors. Each has it's own method.
var counter = 0;
var neighbor1 = {
name: 'John',
myFunction: function () {
console.log(this.name)
this.doStuff();
}
};
var neighbor2 = {
name: 'Bob',
doOtherStuff: function () {
console.log(this.name);
if(counter>5) {
return false;
} else {
counter++;
this.myFunction();
}
}
};
neighbor1.doStuff = neighbor2.doOtherStuff;
neighbor1.myFunction();
I understand when I call the neighbor1.myFunction method that it will call the neighbor2.doOtherStuff method because I've used the assignment operator above. What I don't understand is why 'this' will always be the neighbor1 object (John) and never the neighbor2 object (Bob). Can someone please explain in simple terms why neighbor1 is always 'this'? Thanks!
this is always referring/pointing to execution context(from where you executing the function, not from where you writing the function). You're invoking this.doStuff() at neighbor1 and hence the this is always pointing to neighbor1.
If you wish to understand more about this, I would recommend study this awesome material
Related
I am fairly new to Javascript and stomped across this while writing some frontend code. I reproduced this here:
var obj1 = {
func1(val) {
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
this.obj2.func2();
}
}
obj1.func1(10);
obj1.func1(20);
Why is the value of the val not getting changed inside the func2() method? It seems that only the value is getting copied to the object obj2 without taking the reference into consideration.
But it works perfectly when I change the code to this:
var obj1 = {
func1(val) {
this.val = val;
var that = this;
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(that.val)
}
}
}
this.obj2.func2();
}
}
obj1.func1(10);
obj1.func1(20);
Can anyone tell the reason behind the difference? Is it something to do with the scope?
In the first snippet, when you do
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
The obj2 method that has been assigned, which gets assigned once and never again, closes over the val parameter in its scope when it was assigned - that is, when obj1.func1(10) was run.
In the second snippet, you assign to the val property of the instance every time func1 runs:
func1(val) {
this.val = val;
so by the time you log that.val later, it's always the parameter you just passed.
On the first case, you have:
if (!this.obj2) {
this.obj2 = {
func2() {
console.log(val);
}
}
}
So you make func2 always console.log the value it was originally created with. The second time it's called it will just call func2 with original val because functions retain access to the original scope they were declared (this is called closure).
The second time, when you do
this.val = val;
var that = this;
You're going to console.log a dynamic reference to this, so it's going to be value you passed because the this is going to be different on this scop
as far as I can understand the "This" keyword in javascript always points to the app itself or a global object. What you just did is setting a reference to the variable you are trying to use which is how I remedy this behaviour mistimes. I hope this helped at least?
have a look at this post. understanding the this keyword
cheers.
Is it possible to create an alternate of Array.forEach that automatically sets the context "this" to be the same context as when the method was invoked?
For example (not working, not sure why):
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
this.myVar = 'myVar';
[1,2,3].each(function() {
console.log(this.myVar); // logs 'myVar'
});
}
Array.forEach already takes a context argument as the optional last parameter,
(function() {
this.myvar = "myvar";
[1,2,3,4].forEach(function(v) {
console.log("v:"+v);
console.log("myvar="+this.myvar);
}, this);
})();
See MDN forEach
Also, the above examples (if we're not dealing with methods on instances regarding this) work without using bind or the optional context argument for forEach, the following also works correctly:
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
});
}
myFunction();
Because javascript is functionally scoped, so the anonymous function can access the parent function's scope using this and it logs correctly. this only really becomes problematic as a context when dealing with instance methods.
The answer is no, a JavaScript function cannot determine the value of this in the caller.
You can bind the function passed with the current object, like this
function myFunction() {
this.myVar = 'myVar';
[1,2,3].forEach(function() {
console.log(this.myVar); // logs 'myVar'
}.bind(this));
}
In ECMA Script 6, you can use an Arrow function, like this
[1,2,3].forEach(() => {
console.log(this.myVar); // logs 'myVar'
});
An alternative to messing with the this variable when passing around callbacks, you could always just assign this to a new variable so child scoped functions can access it:
Array.prototype.each = function(fn) {
return this.forEach(fn, arguments.callee.caller);
}
function myFunction() {
var me = this;
me.myVar = 'myVar';
[1,2,3].each(function() {
console.log(me.myVar); // logs 'myVar'
});
}
now you don't have to remember to pass this as a second parameter
Firstly, it must be pointed out that myFunction is a constructor. Yet, the first letter in the identifier is not capitalized. Please call it MyFunction.
If a constructor is called without the new operator, this is bound to the global object, i.e. window in browsers. This makes the capitalization convention our only way of spotting such mishaps.
The following lines of code demonstrate this:
// After the original code...
myFunction();
console.log(window.myVar); // logs "myVar"
Secondly, to be able to apply functions on any array, instead of changing Array.prototype, consider the following:
var utils = {array: {}}; // utils.array is a container for array utilities.
utils.array.each = function (array, func) {
var i;
for (i = 0; i < array.length; i += 1) { func(array[i]); }
};
utils.write = function (s) {
console.log(s); // Alternatively, document.write(s);
};
utils.array.each([1, 2, 3], utils.write); // prints 1 2 and 3 (on separate lines)
Notice that we didn't use this and new. They make JavaScript look like Java, apart from that, they rarely serve a useful purpose.
While libraries may modify Object.prototype and Array.prototype, end-developers shouldn't.
Also, we should (ideally) be able to do something like:
utils.array.each([1, 2, 3], console.log); or
utils.array.each([1, 2, 3], document.write);.
But most browsers won't allow it.
Hope this helped.
If I understand your requirement correctly, then you are trying to override the "this".
I think this can help you.
Here's a sample of a simple Javascript class with a public and private method (fiddle: http://jsfiddle.net/gY4mh/).
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction();
}
}
ex = new Example;
ex.publicFunction();
Calling the private function from the public one results in "this" being the window object. How should I ensure my private methods are called with the class context and not window? Would this be undesirable?
Using closure. Basically any variable declared in function, remains available to functions inside that function :
var Example = (function() {
function Example() {
var self = this; // variable in function Example
function privateFunction() {
// The variable self is available to this function even after Example returns.
console.log(self);
}
self.publicFunction = function() {
privateFunction();
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Another approach is to use "apply" to explicitly set what the methods "this" should be bound to.
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.apply(foo, null);
// => foo
Yet another approach is to use "call":
function Test() {
this.name = 'test';
this.logName = function() {
console.log(this.name);
}
}
var foo = {name: 'foo'};
var test = new Test();
test.logName()
// => test
test.logName.call(foo, null);
// => foo
both "apply" and "call" take the object that you want to bind "this" to as the first argument and an array of arguments to pass in to the method you are calling as the second arg.
It is worth understanding how the value of this in javascript is determined in addition to just having someone tell you a code fix. In javascript, this is determined the following ways:
If you call a function via an object property as in object.method(), then this will be set to the object inside the method.
If you call a function directly without any object reference such as function(), then this will be set to either the global object (window in a browser) or in strict mode, it will be set to undefined.
If you create a new object with the new operator, then the constructor function for that object will be called with the value of this set to the newly created object instance. You can think of this as the same as item 1 above, the object is created and then the constructor method on it is called.
If you call a function with .call() or .apply() as in function.call(xxx), then you can determine exactly what this is set to by what argument you pass to .call() or .apply(). You can read more about .call() here and .apply() here on MDN.
If you use function.bind(xxx) this creates a small stub function that makes sure your function is called with the desired value of this. Internally, this likely just uses .apply(), but it's a shortcut for when you want a single callback function that will have the right value of this when it's called (when you aren't the direct caller of the function).
In a callback function, the caller of the callback function is responsible for determining the desired value of this. For example, in an event handler callback function, the browser generally sets this to be the DOM object that is handling the event.
There's a nice summary of these various methods here on MDN.
So, in your case, you are making a normal function call when you call privateFunction(). So, as expected the value of this is set as in option 2 above.
If you want to explictly set it to the current value of this in your method, then you can do so like this:
var Example = (function() {
function Example() {
function privateFunction() {
// "this" is window when called.
console.log(this);
}
this.publicFunction = function() {
privateFunction.call(this);
}
}
return Example;
})();
ex = new Example;
ex.publicFunction();
Other methods such as using a closure and defined var that = this are best used for the case of callback functions when you are not the caller of the function and thus can't use 1-4. There is no reason to do it that way in your particular case. I would say that using .call() is a better practice. Then, your function can actually use this and can behave like a private method which appears to be the behavior you seek.
I guess most used way to get this done is by simply caching (storing) the value of this in a local context variable
function Example() {
var that = this;
// ...
function privateFunction() {
console.log(that);
}
this.publicFunction = function() {
privateFunction();
}
}
a more convenient way is to invoke Function.prototype.bind to bind a context to a function (forever). However, the only restriction here is that this requires a ES5-ready browser and bound functions are slightly slower.
var privateFunction = function() {
console.log(this);
}.bind(this);
I would say the proper way is to use prototyping since it was after all how Javascript was designed. So:
var Example = function(){
this.prop = 'whatever';
}
Example.prototype.fn_1 = function(){
console.log(this.prop);
return this
}
Example.prototype.fn_2 = function(){
this.prop = 'not whatever';
return this
}
var e = new Example();
e.fn_1() //whatever
e.fn_2().fn_1() //not whatever
Here's a fiddle http://jsfiddle.net/BFm2V/
If you're not using EcmaScript5, I'd recommend using Underscore's (or LoDash's) bind function.
In addition to the other answers given here, if you don't have an ES5-ready browser, you can create your own "permanently-bound function" quite simply with code like so:
function boundFn(thisobj, fn) {
return function() {
fn.apply(thisobj, arguments);
};
}
Then use it like this:
var Example = (function() {
function Example() {
var privateFunction = boundFn(this, function() {
// "this" inside here is the same "this" that was passed to boundFn.
console.log(this);
});
this.publicFunction = function() {
privateFunction();
}
}
return Example;
}()); // I prefer this order of parentheses
VoilĂ -- this is magically the outer context's this instead of the inner one!
You can even get ES5-like functionality if it's missing in your browser like so (this does nothing if you already have it):
if (!Function.prototype.bind) {
Function.prototype.bind = function (thisobj) {
var that = this;
return function() {
that.apply(thisobj, arguments);
};
}:
}
Then use var yourFunction = function() {}.bind(thisobj); exactly the same way.
ES5-like code that is fully compliant (as possible), checking parameter types and so on, can be found at mozilla Function.prototype.bind. There are some differences that could trip you up if you're doing a few different advanced things with functions, so read up on it at the link if you want to go that route.
I would say assigning self to this is a common technique:
function Example() {
var self = this;
function privateFunction() {
console.log(self);
}
self.publicFunction = function() {
privateFunction();
};
}
Using apply (as others have suggested) also works, though it's a bit more complex in my opinion.
It might be beyond the scope of this question, but I would also recommend considering a different approach to JavaScript where you actually don't use the this keyword at all. A former colleague of mine at ThoughtWorks, Pete Hodgson, wrote a really helpful article, Class-less JavaScript, explaining one way to do this.
I see objects in JavaScript organized most commonly in the below two fashions. Could someone please explain the difference and the benefits between the two? Are there cases where one is more appropriate to the other?
Really appreciate any clarification. Thanks a lot!
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {}
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
})();
Second:
SomeObject = function() {
SomeObject.prototype.doSomething: function() {
},
SomeObject.prototype.doSomethingElse: function() {
}
}
Both of those examples are incorrect. I think you meant:
First:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
return SomeObject;
})();
(Note the return at the end of the anonymous function, the use of = rather than :, and the semicolons to complete the function assignments.)
Or possibly you meant:
function SomeObject() {
}
SomeObject.prototype.doSomething = function() {
};
SomeObject.prototype.doSomethingElse = function() {
};
(No anonymous enclosing function.)
Second:
function SomeObject() {
}
SomeObject.prototype = {
doSomething: function() {
},
doSomethingElse: function() {
}
};
(Note that the assignment to the prototype is outside the SomeObject function; here, we use : because we're inside an object initializer. And again we have the ; at the end to complete the assignment statement.)
If I'm correct, there's very little difference between them. Both of them create a SomeObject constructor function and add anonymous functions to its prototype. The second version replaces the SomeObject constructor function's prototype with a completely new object (which I do not recommend), where the first one just augments the prototype that the SomeObject constructor function already has.
A more useful form is this:
var SomeObject;
SomeObject = (function() {
function SomeObject() {
}
SomeObject.prototype.doSomething = doSomething;
function doSomething() {
}
SomeObject.prototype.doSomethingElse = doSomethingElse;
function doSomethingElse()
}
return SomeObject;
})();
There, the functions we assign to doSomething and doSomethingElse have names, which is useful when you're walking through code in a debugger (they're shown in call stacks, lists of breakpoints, etc.). The anonymous function wrapping everything is there so that the doSomething and doSomethingElse names don't pollute the enclosing namespace. More: Anonymouses anonymous
Some of us take it further:
var SomeObject;
SomeObject = (function() {
var p = SomeObject.prototype;
function SomeObject() {
}
p.doSomething = SomeObject$doSomething;
function SomeObject$doSomething() {
}
p.doSomethingElse = SomeObject$doSomethingElse;
function SomeObject$doSomethingElse()
}
return SomeObject;
})();
...so that not only do we see doSomething, but SomeObject$doSomething in the lists. Sometimes that can get in the way, though, it's a style choice. (Also note I used the anonymous function to enclose an alias for SomeObject.prototype, to make for less typing.)
First off, both snippets will not parse for me (Chrome) - you should use = in place of :. That said, my humble opinion follows.
The latter snippet is slightly strange, because you actually define methods on SomeObject's prototype at the time of the object construction, rather than at the parse time. Thus, if you have re-defined some method on SomeObject.prototype, it will get reverted to the original version once a new object is constructed. This may result in unexpected behavior for existing objects of this type.
The former one looks fine, except that the (function { ...} ())() wrapper may not be necessary. You can declare just:
function SomeObject() {}
SomeObject.prototype.doSomething = function() {}
SomeObject.prototype.doSomethingElse = function() {}
The actual difference between first and second in your questions is just:
var o = (function () {})(); # call this (A)
and
var o = function () {}; # call this (B)
Unfortunately, neither of the examples that you gave are written correctly and, while I don't think either will actually give an error at parse-time, both will break in interesting ways when you try to do things with the result.
To give you an answer about the difference between (A) and (B), (A) is the immediate function application pattern. The JavaScript Patterns book has a good discussion, which I recommend.
The actual problems in your code have been explained by other people while I was writing this. In particular T.J. Crowder points out important things.
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
function Peon(number) {
this.number = number;
this.inc = function() {
number=number+1;
};
return true;
}
var p=new Peon(10);
function returnNumber() {
p.inc();
alert(p.number);
}
</SCRIPT>
</HEAD>
<BODY>
<INPUT id="b00" TYPE="button" Value="Click" onClick="returnNumber()">
</BODY>
</HTML>
This code doesn't work as intended. Is there a way to make it work without having to write
this.number=this.number+1;
Here it is a trivial choice, but in bigger codes not having this.* would make it a lot more readable. Is it possible?
You can make number "private", but then you need a getter:
function Peon(number) {
var number = number;
// increment
this.inc = function() {
number++;
};
// a simple getter
this.getNumber = function() {
return number;
}
}
var p = new Peon(10);
p.inc();
alert(p.getNumber());
You should read Douglas Crockfords "The Good Parts" for more information on how to use this pattern, there's (limited) a preview available at Google Books.
Also you don't need to return something from the constructor, your return true is superfluous.
No, you have to use this to reference properties on the this object. Note that this in JavaScript is very different from this in some other languages, like C or Java. More here and here.
What your code is doing is accessing the number argument that was passed into the Peon constructor function, rather than the this.number property you created in the constructor. Which is why it doesn't work as intended, but doesn't fail, either.
There's no reason to define your inc operation within the Peon constructor function, BTW, and some good reasons not to (every individual object created via Peon will get its very own copy of that function). So instead, you can define it like this:
function Peon(number) {
this.number = number;
// Don't return values out of constructor functions, it's
// an advanced thing to do. In your case, you were returning
// `true` which was being completely ignored by the JavaScript
// interpreter. If you had returned an object, the `this` object
// created for the `new Peon()` call would have been thrown away
// and the object you returned used instead.
}
Peon.prototype.inc = function() {
++this.number;
};
var p=new Peon(10);
function returnNumber() {
p.inc();
alert(p.number); // alerts 11
}
Not really, but this is a little more concise
this.number++
Actually, as a side note, you'd be better off declaring .inc outside the constructor of Peon. You could do this with prototype. That way the inc function is not reconstructed each time you create an object of type Peon.
Peon.prototype.inc = function(){
this.number++;
}
Or instead of using p.inc() you could do p.number++. That's the only way I can think of avoiding the this keyword.
The only readable way I can see doing it would be:
this.inc = function() {
this.number++;
};
Otherwise, in your "bigger codes" postulation, you could do something like this:
this.inc = function() {
var number = this.number; // obviously simple here. Imagine more complexity
number++;
};
Yes, you do not need to use 'this' in javascript. You can access variables via closure instead of 'this'
function createPeon(number) {
function inc() {
number=number+1;
};
function getNumber() {
return number;
}
return { inc, getNumber };
}
var p=createPeon(10);
p.inc();
alert(p.getNumber());