- 词法阶段
- 词法化
- 对源代码中的字符进行检查
- 词法作用域
- 就是写代码时将变量和块作用域写在哪里决定
- 作用域查找会在找到第一个匹配的标识符时停止
- 所以,重名标识符会有overriding
- 作用域始终从运行时所处的最内部作用域开始
- 逐级向外,沿着作用域链
- 综上,运行时,在最内部作用域开始搜寻变量,找不到沿着作用域链向外查找,找到第一个与之匹配的标识符,OK
- 词法化
- 改变词法作用域
- eval
function foo(str, a) { eval(str); console.log(a, b); } var b = 2; foo("var b = 3;", 1); // 1, 3
- 严格模式下的eval没有效果
function foo(str) { "use strict"; eval( str ); console.log( a ); // ReferenceError: a is not defined } foo( "var a = 2" );
- 严格模式下,eval在运行时有自己的词法作用域
- eval(..)可以将包含声明语句的代码字符串插入,修改运行时的词法作用域
- with
var obj = { a: 2, b: 3 }; function fo(obj) { with (obj) { b = 5; } } var o = { b: 33 }; var p = { a: 23 }; fo(o); console.log(o.b); // 33 fo(p); console.log(p.b); // undefined
- 对象o有属性;,对象p没有属性b,不会创建该属性
- with语句将一个对象的引用作为作用域来处理,将对象的属性当作作用域中的标识符,创建了一个新的运行时词法作用域。
- eval和with使引擎在编译时对作用域的优化无效,所以会导致运行变慢。
- eval
- 函数作用域和块作用域
隐藏内部实现
最小授权原则(最小暴露原则)
- 最小限度地暴露必要内容。
所以变量和函数不会都声明在全局作用域中
function doSomething(a) { b = a + doSomethingElse(a * 2); console.log(b * 3); } function doSomethingElse(a) { return a - 1; } var b; doSomething(2); // 15
变量b和函数doSomethingElse()是函数doSomething()的私有内容,外部作用域可以访问到是危险的,下面将私有内容隐藏在函数内部。
function doSomething(a) { var b; function doSomethingElse(a) { return a - 1; } b = a + doSomethingElse(a * 2); console.log(b * 3); }
隐藏的好处