Scope clarification in javascript [duplicate] - javascript

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
Explanation asked about the value of 'this' in Javascript [duplicate]
(2 answers)
Closed 8 years ago.
Simple question. Why do we have set that = this? If we dont, we are in the global scope...but why?
var myObj = {
specialFunction: function () {
},
anotherSpecialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
var that = this;
this.getAsyncData(function () {
// this now refers to global scope....why?
that.specialFunction();
that.anotherSpecialFunction();
});
}
};
myObj.render();

Writing that = this doesn't change the scope. The way the anonymous function is called will always end up with this being global object,* because that's exactly what the spec says should happen. Using that = this is just a workaround.
You could make this always point to myObj by using Function.call:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb.apply(this);
},
render: function () {
this.getAsyncData(function () {
this.specialFunction();
});
}
};
and/or using Function.bind:
var myObj = {
specialFunction: function () {
},
getAsyncData: function (cb) {
cb();
},
render: function () {
function callback() {
this.specialFunction();
}
this.getAsyncData(callback.bind(this));
}
};
* Unless you're in strict mode, in which case this is undefined.

take a look at the this keyword in JavaScript and how it works. I’m sure we’ve all come across this issue:
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
}
});
});
this is a variable that is automatically set for you when a function is invoked. The value it’s given depends on how a function is invoked. In JavaScript we have a few main ways of invoking functions. I wont talk about them all today, but just the three ways most people use them; either when a function is called as a method, or on it’s own, or as an event handler. Depending on how a function is invoked, this is set differently:
function foo() {
console.log(this); //global object
};
myapp = {};
myapp.foo = function() {
console.log(this); //points to myapp object
}
var link = document.getElementById("myId");
link.addEventListener("click", function() {
console.log(this); //points to link
}, false);
Doing $("myLink").on("click", function() {}) means that when the element is clicked, the function is fired. But this function is bound as an event handler, so this is set to the reference to the DOM element myLink. The success method you define within the Ajax request is just a regular function, and as such when it’s invoked, this is set to the global object, as it is when any function that’s not an event handler or an object method is.
$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
var _this = this; //store reference
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
console.log(_this); //better!
}
});
});
Source: http://tinyurl.com/melbl92

EDIT: in JavaScript the "this" context depends on how your function is called, example:
function helloWorld()
{
console.log(this);
}
And here two ways to call this function:
new helloWorld(); note that if you call your function in this
way, the context of this will be the context of the function +
prototype, so your console will show this: helloWorld {}
helloWorld(); if you call your function without of the "new",
the context of "this" will be global(Window), so your console will show
this: Window about:home
Ok, with this little explanation i will try to explain now why you
have sometimes to use self/that...
Imagine that you want to use this.name inside this.hello function. Like I said before, the context of "this" depends on how your function is called, so if you want to ensure that this.name inside of this.hello function refer to this.name outside is recommended that you use self/that to avoid what happens bellow
function helloWorld(){
var self = this;//or that = this
this.name = "YourName"
this.hello = function(){
console.log(this); //the context of "this" here will be: "hello {}"
return this.name; //undefined, because you don't have name attribute inside hello function
}
new this.hello(); //note how hello is called here...
}
var test = new helloWorld();
And here a good explanation about context x scope:
http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Related

Private Instance of This in Javascript [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
As in, sometimes when I look at code by other people, they will go var self = this; or in jquery for example, go var $self = $(this);
is there a particular reason for doing so?
It preserves the value of this for use in functions defined inside the current function.
// Contrived example
var myObject = {
func: function () {
var self = this;
setTimeout(bar, 1000);
function bar () {
alert(this); // `window`
alert(self); // `myObject`
}
}
};
myObject.func();
By holding a reference to this in some context, you have the ability to access it in other contexts such as within member functions or forEach loops.
Consider the following example:
function ViewModel() {
var self = this;
self.linksArray = ["link1", "link2", "link3"];
self.linksArray.forEach(function(link) {
// this refers to the DOM window
// and self refers to the parent context (ViewModel)
});
};
As others have mentioned, you could set a variable to $(this) if you wish to use it in another function.
On practical example would be when doing an ajax call tied to an event on the page. Using JQuery:
<script>
$(document).on("click", ".mySelector", function () {
// Where we are in the click event, $(this) refers to whatever
// element has a class of mySelector that was clicked
var self = $(this);
theDiv.html('');
$.ajax({
cache: false,
type: "GET",
url: "/SomeAjaxMethod",
data: { },
success: function (data) {
// Trying to access $(this) here will return undefined, as
// we are technically in the callback method
// Where our event is based on a class, there is likely more
// than one element on the page with the class, so it would be
// difficult to get the exact element again without some other code
self.html(data);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Ajax failed.")
}
}); // end ajax call
}); // end on mySelector class click
</script>
or:
<script>
$(document).ready(function () {
$('.foo').click(function () {
var self = $(this); // Whatever element that was clicked with foo class
$('.bar').each(function () {
var bar = $(this); // Current iteration of bar element in the loop
var baz = self; // self is still the initial value, but $(this) is not
}); // end bar loop
}); // end foo click
}); // end doc ready
</script>
The particular example (not using JQuery) is the function closure. Referencing this in a function closure refers to the function object, not the context in which the closure was defined. Your example is one way to deal with the closure problem:
var that = this;
function(){
that.something = 1;
}();
Another way to deal with this is with the apply method on the function:
function(arg){
this.something = 1;
}.apply(this, argumentArray);
The first argument in apply is the "this argument" that "this" will refer too.
One purpose of that would be to make this accessible to inner functions. for example:
function clickHandler(){
console.log(this); // this is body
var $self = this;
function inner(){
console.log(this); // this is window
console.log($self); // this is body
}
inner();
}
$("body").click(clickHandler);
Run it in console to get a sense.

Recursive timeout loses visibility to itself

I have defined an API object:
function API() {
var self = this;
return {
getRandomArticle: function() {
$.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=50000&format=json&callback=?", function (data) {
for(var id in data.query.pages) {
console.log(data.query.pages[id].extract);
}
});
},
repeatAPICall: function() {
self.getRandomArticle();
console.log(self);
setTimeout(self.repeatAPICall, 5000);
}
}
}
And then I instantiated the API object with window.test = new API();.
When I head over to Chrome Dev tools and call window.test.repeatAPICall(), it works once, then it fails and says TypeError: Object #<API> has no method 'getRandomArticle'
I suspect that somehow the recursive call is behaving differently than I intended, what am I doing wrong?
Working code:
function API() {
var self = this;
self.getRandomArticle = function() {
$.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=50000&format=json&callback=?", function (data) {
for(var id in data.query.pages) {
console.log(data.query.pages[id].extract);
}
});
},
self.repeatAPICall = function() {
self.getRandomArticle();
console.log(self);
setTimeout(self.repeatAPICall, 5000);
}
return this;
}
window.test = new API();
Now you've fixed "self" vs. "this" the next change is to use
self.getRandomArticle= ...
self.repeatAPICall=...
and then just return self/this. That should work. Right now, you have two objects - this and the one you return.
Your main issue is the passing of this.repeatAPICall into setTimeout. When you call a method in JavaScript, the this keyword points to the object that called it:
var something = {
foo : function(){
return this;
}
};
something.foo(); //=> something
However, if you assign the function to a different variable, the context changes (to the global window object):
var something = {
foo : function(){
return this;
}
};
something.foo(); //=> something
var bar = something.foo;
bar(); //=> window
This is what's happening above; you're passing a reference to the function to setTimeout, which is then losing the correct context.
Instead, you need to pass in a function which keeps the context; you could use the self = this statement like so:
repeatAPICall: function() {
self = this;
self.getRandomArticle();
setTimeout(function(){
self.repeatAPICall();
}, 5000);
This creates anonymous function which remembers the state of the self object (this is how JavaScript variable scope works). When that function gets called, it can then call repeatAPICall as a method on that object, rather than as a function with no context.
The accepted answer avoids having to do this (each method can access self), but hopefully this explains why it wasn't working.

What is a best practice for ensuring "this" context in Javascript?

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.

'this' keyword within anonymous function

Can someone tell me what object this.onSubmit is referring to in the following code?
(function () {
var _d = vjo.dsf.EventDispatcher;
var _r = vjo.Registry;
function $1(p0) {
return function (event) {
return this.onSubmit(p0, event);
};
};
})();
I apologise if there is not enough context attached to this example.
In JavaScript, the value of this is dynamically set. So to know its value, you need to know how the function is being called/used.
So the generic answer would be that this is referring to whatever was set as the this value of the execution context.
Whatever object is being bound when the function is run.
Example:
(function() {
....
function $1(p0) {
return function (event) {
return this.onSubmit(p0, event);
};
};
var testObj = {
foo: 'bar',
onSubmit: function(x,y) { console.log(x,y); }
};
var func = $1('moep');
func.call(testObj, 'hrhr'); // logs >> moep, hrhr
Here it will be the window object. You can confirm this by adding console.log(this) on the line before.

Javascript module pattern, scope and "this"

I'm trying to wrap my head around building a custom JavaScript library. I've read a lot about the module pattern, and also read Crockford's articles on private and public members. I know what is an immediately invoked function expression and why we do stuff like
var myLib = (function() {
}())
However, I'm still a little lost in some cases regarding scope and closures in general. The concrete problem I have is:
Why does the following example alert DOMWindow, rather than the myLib object?
http://jsfiddle.net/slavo/xNJtW/1/
It would be great if you can explain what "this" refers to in all of the methods in that example and why.
Inside any function declared (anywhere) and invoked as follows this will be window object
function anyFunc(){
alert(this); // window object
}
anyFunc();
var anyFunc2 = function(){
alert(this); // window object
}
anyFunc2();
If you want to create private functions and access the instance of 'myObject' you can follow either of the following methods
One
module = (function () {
var privateFunc = function() {
alert(this);
}
var myObject = {
publicMethod: function() {
privateFunc.apply(this); // or privateFunc.call(this);
}
};
return myObject;
}());
module.publicMethod();
Two
module = (function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(_this);
}
var myObject = {
publicMethod: function() {
privateFunc();
}
};
_this = myObject;
return myObject;
}());
module.publicMethod();
These are solutions to your issue. I would recommend using prototype based objects.
EDIT:
You can use the first method.
In fact here myObject is in the same scope as privateFunc and you can directly use it inside the function
var privateFunc = function() {
alert(myObject);
}
The real scenario were you can use a proxy for this is shown below. You can use call also.
Module = function () {
var _this; // proxy variable for instance
var privateFunc = function() {
alert(this + "," + _this);
}
this.publicMethod = function() {
privateFunc(); // alerts [object Window],[object Object]
privateFunc.call(this); // alerts [object Object],[object Object]
}
_this = this;
return this;
};
var module = new Module();
module.publicMethod();
You need to explicitly state that myPrivateMethod is a member of myLib:
function MyLib ()
{
this._myPrivateField = "private";
this._myPrivateMEthod = function ()
{
alert(this); // Alerts MyLib function;
}
}
var libObject = new MyLib();
Just remember that without using enclosure techniques, nothing in JavaScript is ever truly private!
A better way to do the above is like so:
function MyLib(instanceName)
{
this.name = instanceName;
}
MyLib.prototype.myPrivateFunction()
{
alert(this);
}
To call your method after that:
var libObject = new MyLib();
libObject.myPrivateMethod(); // Alerts info about libObject.
The thing to remember about the module pattern is that it runs once and completes. The methods that are still available to be called are the closures. At the time of creating module, "this" refered to the window and was replaced by its value.
In your linked fiddle, the "this" keyword is never changed by a "new" keyword or other context change, so it still refers to the global window object.
edit: clarification

Categories

Resources