- Programming languages mostly have two models of scope - Dynamic and Lexical Scope. JavaScript uses Lexical Scope.
- Lexing (Tokenizing) breaks the source code into tokens and assigns semantic meaning to them.
- Lexical Scope is scope defined while lexing. It is based on where variables and blocks of scope are authored at write time and is mostly fixed during lexing process.
- On the other hand, in a Dynamic scope environment scope can be determined dynamically at runtime rather than statically at the write time. Thus in Dynamic scope, the scope chain is based on the call stack and not the nesting of scopes in code as in Lexical scope. Adding a code example to it:
function foo() {
// In Lexical Scope environment a = 1
// In dynamic Scope environment a = 3
console.log(x);
}
function bar() {
var x = 3;
foo();
}
var x = 1;
bar();
- Javascipt have
this
keyword which helps replicating the dynamic scope behavoir. We will discuss this
in a another post.
- Lexical can be cheated using
eval
and with
. (Both are considered bad practices in developer community)
eval()
function takes an argument and treats it as if it had actually been authored code at that point in the program.
function foo(code, x) {
eval( code ); // cheating
console.log( x, y );
}
var y = 2;
foo( "var y = 3;", 1); // 1, 3
with()
is a shorthand for making multiple property references against an object without repeating the object reference each time.
var obj = {
a: 1,
b: 2,
c: 3
};
// old way
obj.a = 2;
obj.b = 3;
obj.c = 4;
// using with()
with(obj) {
a = 2;
b = 3;
c = 4;
}
with()
basically creates a new lexical scope out of thin air wherever we are using the with statement.
function foo(obj) {
with(obj) {
a = 2;
}
}
var o1 = {
a: 3
};
var o2 = {
b: 3
};
foo(o1);
console.log(o1.a); // 2
foo(o2);
console.log(o2.a); // undefined
console.log(a); // 2 which is the leaked global because of falling back to
// global scope in absence of variable in current scope
strict mode
can be used to disallow eval
and with
.
- JS Engine does performance optimization that it performs during compilation phase. It pre-determines where all the variable and function declarations are so that it takes less effort to resolve identifiers during execution. But when it encounters a
eval()
or with
its all pre-determined conclusion are marked invalid. Thus it has performance issues.