作用域工作模式:1 词法作用域;2 动态作用域(Bash脚本、Perl中的一些模式)
2.1 词法阶段
词法作用域就是定义在词法化阶段的作用域,也就是写代码时将变量和块作用域写在哪里决定的
function foo(a) {
var b = a
function bar (c) {
return c
}
bar (b * 2)
}
foo(2)
包含三个逐级嵌套作用域
查找
作用域查找找到第一个匹配的标识符停止,多层嵌套作用域可定义同名标识符,称为“遮蔽效应”,全局变量会自动成为全局对象的属性,可以间接通过对全局对象属性的引用访问
2.2 欺骗词法
欺骗词法作用域会导致性能下降
2.2.1 eval
eval(...)
接收一个字符串为参数,在执行eval
之后的代码时,引擎并不知道前面的代码是以动态形式插入,并对词法作用域的环境进行修改的
function foo (str, a){
eval(str)
console.log(a, b)
}
var b = 2
foo("var b = 3", 1) // 1 3
eval
对foo
的词法作用域做了修改,在foo
内部创建b
,遮蔽外部作用域同名变量
严格模式中,eval
在运行时有其自己的词法作用域,无法修改所在作用域
2.2.2 with(不推荐使用)
with
声明实际上根据传递给它的对象凭空创建一个全新的词法作用域
2.2.3 性能
JavaScript引擎在编译阶段进行数项的性能优化,有些优化依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符
引擎无法在编译时对作用域查找并优化,引擎只能谨慎认为优化是无效的
function func() {
console.time("func");
var obj = {
a: [1, 2, 3]
};
for(var i = 0; i < 100000; i++)
{
var v = obj.a[0];
}
console.timeEnd("func");
}
func();
function funcWith() {
console.time("funcWith");
var obj = {
a: [1, 2, 3]
};
with(obj) {
for(var i = 0; i < 100000; i++) {
var v = a[0];
}
}
console.timeEnd("funcWith");
}
funcWith();
// 使用with代码运行速度变慢
// func: 1.23424224ms
// funcWith: 48.23424224ms
网友评论