JavaScript: Scope
Difference between variable scope and this:
- If a variable is called it’s definition is searched for in current scope, then parent scope, then grandparent scope and so on until it is found (a.k.a lexical scope)
- In function definitions which are not arrow functions
thisvalue is defined for meimplicitly(asexecution context, see more below in thethissection!). - In arrow functions, this retains the value of the enclosing lexical context’s this.
- Everything you wanted to know about JavaScript scope
Important facts
Local scopes are only
New functions = new scope
- that’s the rule.
setTimeout
Variables called within a setTimeout function call address the values in the global scope, even if the variable values are set differently locally.
function hoisting
function declaration overrides variable declaration when hoisted only if variable is not assigned yet.
function expressions (anonymous functions)
Function expressions are not hoisted.
var myName = function() {
console.log('Andre");
}this
deep_thought is the execution context and thus this is the deep_thought object, so it’s variables are available with this in ask_question method! (taken from this perfect explanation by using execution context and object oriented design in the article!))
var the_answer = 0;
var deep_thought = {
the_answer: 42,
ask_question: function () {
return this.the_answer;
}
};
var the_meaning = deep_thought.ask_question();Here another example (in which this is actually not needed): this is bound in the
var Word = function(t) {
var text = t;
var translate = function(lang) {
switch (lang) {
case 'foo':
t = this.text.substring(1, this.text.length) + "aaaaa";
break;
default:
t = "I don't speak " + lang
}
return t;
}
return {
text: text,
translate: translate,
}
}An article or another article and an article about the execution context and here a quiz inside a stackoverflow answer
this always refers to the inner function, if you have nested functions, you have to create another variable and point that to this.
var myObject = {
AddChildRowEvents: function(row, p2) {
var that = this;
if(document.attachEvent) {
row.attachEvent('onclick', function(){that.DoSomething();});
} else {
row.addEventListener('click', function(){that.DoSomething();}, false);
}
}
}Solve this issue
Before
var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
console.log(this); // <nav> element
setTimeout(function () {
console.log(this); // [object Window]
}, 1000);
};
nav.addEventListener('click', toggleNav, false);After
var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
var that = this;
console.log(that); // <nav> element
setTimeout(function () {
console.log(that); // <nav> element
}, 1000);
};
nav.addEventListener('click', toggleNav, false);Changing scope with call, apply and bind
With .call and .apply you can call your function with a desired scope (i.e. a desired this value) plus optional arguments.
.call and .bind are the same, only .bind does not call the function. With .bind the function isn’t invoked, and the scope can be changed if needed, but arguments are sat waiting to be passed in.
call:.call(scope, arg1, arg2, arg3)apply:.apply(scope, [arg1, arg2])bind:.bind(scope, arg1, arg2, arg3)
Usage of .bind:
nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false);Public and Private Scope
var Module = (function () {
var myModule = {};
var _privateMethod = function () {
};
myModule.publicMethod = function () {
};
myModule.anotherPublicMethod = function () {
};
return myModule; // returns the Object with public methods
})();
// usage
Module.publicMethod();or
var Module = (function () {
var _privateMethod = function () {
};
var publicMethod = function () {
};
})();Discuss on Twitter ● Improve this article: Edit on GitHub