js的词法作用域
对于JavaScript来说,无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只有函数被声明时所出的位置决定。
运行时修改词法作用域的方法
注意其所带来的各种问题如性能下降等
eval
eval()
函数接受一个字符串为参数,并将其中的内容视为好像书写时就存在那个位置。
eval()通常被用来执行动态创建的代码。(如果是固定的代码,一般直接写在那里了)
NOTE:在严格模式中,eval在运行时有自己的词法作用域,其中的声明无法修改所在的作用域。
with
with()
块可以将一个对象处理为词法作用域,相当于创建了一个新的作用域,将对象的属性处理为定义在这个作用域中的标识符。
with()通常被当做重复引用同一个对象中的多个属性的快捷方式。
问题:虽然将对象的属性作为标识符,但是快内部正常的声明并不会被限制在该作用域(对象)中,造成变量泄漏。
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——不好,a 被泄漏到全局作用域上了!
js引擎的优化依赖于根据代码的静态词法分析,预先确定变量的定义位置。因此动态改变作用域引起性能问题。
基于函数的作用域
最小暴露原则:在软件设计中,应该最小限度地暴露必要内r容。
“隐藏”变量和函数是一个有用的技术(也就是用作用域将其包装起来):
1.防止在外部对本应该属于某一作用域的变量和函数的意外使用。
2.避免同名标识符的冲突
Note:始终给函数命名是一个最佳实践,匿名和具名对行内函数表达式和立即执行函数表达式(Immediately Invoked Function Expression)没有影响。
其他作用域
with
存储对象属性的表示符仅在with内而非外部作用域有效
try/catch
catch分句会创建一个块作用域,其中声明的变量仅在catch内部有效
let
let
关键字可以将变量绑定到所在的作用域中。为使变量的附属关系变得敢接清晰,可以显式使用{...}
括号来为let创建一个用于绑定的块。使用let进行的声明不会进行提升。
Note const
也会创建块作用域变量