本文深入解析JavaScript中变量的声明方式及其作用域机制。通过对比var与直接赋值的区别,详细阐述函数内外变量读取规则及作用域链原理。同时提供减少全局变量污染和简化变量声明的编码最佳实践,帮助开发者写出更清晰、安全的JavaScript代码。
JavaScript变量声明方式与区别
在JavaScript语言中,声明变量通常使用以下语法:
var a=1;
此外,也可以省略var关键字直接赋值:
a=1;
这两种写法在行为上存在显著差异:
前者声明的是当前作用域内的局部变量,而后者则会将变量挂载为当前作用域的全局变量。
JavaScript的一个特性是函数内部可以直接访问全局变量。
示例代码如下:
var n=999;
function f1(){
alert(n);
}
f1(); // 输出 999 相反地,在函数外部无法直接访问函数内部声明的局部变量。
示例代码如下:
function f1(){
var n=999;
}
alert(n); // 报错 error JavaScript变量作用域链机制
二、JavaScript变量作用域链机制
示例代码如下:
var x='000 ';
document.writeln(x); // 输出 '000 '
a();
function a(){
var x='aaa ';
function b(){
document.writeln(x); // 输出 undefined
var x='bbb ';
document.writeln(x); // 输出 bbb
}
b();
document.writeln(x); // 输出 aaa
}
// 最终输出结果为:000 undefined bbb aaa 原理解析:
当程序访问变量时,会优先在当前函数块(权威指南中称为调用对象)内查找;
若未找到,则向上级函数块逐层查找,直至找到定义为止;
若直到顶层代码(即var x='000 '所在层级)仍未找到定义,程序将抛出未定义错误。
1. 按代码执行顺序,首先输出x的值'000 '(此步无疑问);
2. 接着执行函数a();
3. 在a()内部调用函数b();
4. b()中尝试输出x,由于该函数体内已声明x但未赋值,根据变量提升机制,此时x为undefined;(这是关键点!)
5. 随后执行赋值语句,x被赋予'bbb',因此再次输出x时得到bbb;
6. 最后回到a()作用域,输出x得到aaa;
基于上述原理,我们分析以下示例:
示例代码如下:
var x = "global";
function f() {
var x='f1';
function f2(){
x='f2' ;//此处需注意,全局的x并不会被修改为'f2'
alert(x); // 返回 "f2"
alert(window.x); // 返回 "global"
}
f2();
alert(x) // 返回 "f2"
}
f();
alert(x); // 返回 "global",并未被f2内部修改
// 依次弹出的结果为:f2 global f2 global 详细解释:
首先执行f()中的f2()函数;
f2()作为内部函数形成了一个独立的作用域,因此x='f2'修改的是f()作用域内的x值,而非全局x。
alert(x)显示为'f2',而alert(window.x)显示为'global'。
随后执行外层的alert(x),此时x处于全局作用域,因此值为'global'。
三、给新手的建议
减少全局变量与代码规范建议
1. 减少全局变量污染(解决方案:将变量封装到对象中)
引用说明:
“把你踩在全局的那些乱七八糟的脚印都归于一人名下,能显著降低与其他应用、小工具或JS库冲突的可能性。”
—— Douglas Crockford
示例代码如下:
var name = 'Jeffrey';
var lastName = 'Way';
function doSomething() {...}
console.log(name); // 输出 Jeffrey,等同于 window.name 推荐的改进写法
示例代码如下:
var DudeNameSpace = {
name : 'Jeffrey',
lastName : 'Way',
doSomething : function() {...}
}
console.log(DudeNameSpace.name); // 输出 Jeffrey 请注意,我们将所有分散的全局变量都封装到了“DudeNameSpace”这个对象之下;
2. 避免冗长的变量声明?使用逗号分隔即可
示例代码如下:
var someItem = 'some string';
var anotherItem = 'another string';
var oneMoreItem = 'one more string'; 推荐的改进写法
示例代码如下:
var someItem = 'some string',
anotherItem = 'another string',
oneMoreItem = 'one more string'; 这种做法显而易见。虽然不确定是否能提升代码执行速度,但确实使代码更加整洁易读。