本文探讨JavaScript中两个常被忽视的作用域特性:一是with语句会将内部定义的变量提升至外层函数作用域,导致意外访问;二是传统JS中var声明不受花括号块限制,变量会泄露到外层作用域。理解这些机制有助于避免常见的变量污染和逻辑错误。
虽然资深开发者可能早已熟知,但这两个知识点在实际开发中仍具有相当的价值,因此整理出来与大家分享。
with 语句导致的变量提升
首先看以下代码示例:
代码如下:
<script type="text/javascript" >
function test() {
with (location) {
var temp = "an url";
}
alert(temp);
}
test();
</script> 执行该函数会输出什么?直觉上可能认为会弹出 undefined,但实际结果是弹出字符串 "an url"。这一现象涉及 JavaScript 变量作用域的一个特殊机制。
在 JavaScript 中,每个作用域都关联一个所谓的“变量对象”(术语未必完全严谨,但概念存在),用于存储当前作用域内定义的标识符。程序启动时进入全局作用域,由于全局定义了 test 函数,其变量对象中便包含 test 的标识符。调用 test 函数时,进入其局部作用域,此时会将全局作用域中的标识符复制一份到局部变量对象中,因此在 test 内部可以访问全局标识符。反之,外层作用域无法直接访问内层定义的内容。按此逻辑,alert(temp) 应输出 undefined,因为 temp 是在 with 块内部定义的。然而为何此处能访问到内层定义的标识符呢?
原因在于 with 语句块的作用域变量对象是只读的。因此,在 with 块内定义的标识符无法存储在当前层,而是被提升到上一层作用域,即 test 函数的作用域中。这使得 alert(temp) 能够访问到那个定义在 with 块内的 temp 变量。类似的情况也出现在 try...catch 语句中。
缺乏块级作用域的影响
其次,JavaScript(ES5及之前)中不存在传统意义上的语句块作用域,代码如下:
代码如下:
if (true) {
var temp = "oh";
}
alert(temp); 这几行代码看似简单。若依据其他编程语言的常规经验,alert 语句可能会报错,但事实并非如此,alert 正常输出了字符串 "oh"。
这表明在 JavaScript(ES5)中,var 声明不受花括号 {} 形成的语句块限制,变量会泄露到外层作用域。
上述两个示例虽然基础,技术深度有限,但许多资深开发者可能早已掌握。然而,了解这些语言特性对于减少 JavaScript 编码时的出错概率仍具实用价值,故分享于此,期望对各位的 JS 开发有所帮助。