JavaScript中显式声明变量和隐式声明变量有一些需要注意的地方
注:暂时不考虑ES6中的let和const
使用 var 关键字声明的变量是显式声明的变量
如:var abc1 = '你好'
js 允许隐式声明变量而不使用 var
如:abc2='世界'
那么问题来了,这两个变量之间有什么区别吗?
如果 abc1 和 abc2 都在全局范围内,则在浏览器控制台中复制 window 对象:
console.log( window )
如下所示:
你可以在上图中看到:
全局变量 abc1 和 abc2 是 window 对象的属性,并且都具有全局作用域。
如果abc1和abc2都在函数作用域内,复制浏览器控制台中的window对象?
function test(){
var abc1 = 'hello'
abc2 = 'world'
}
test()
console.log( window )
如下所示:
你可以在上图中看到:
在函数作用域中javascript 变量的声明,abc1不会出现在window对象中,它是一个局部变量; 而abc2仍然是window对象的一个属性,具有全局作用域。
如果abc1和abc2都在全局范围内并且都是window对象的属性,那么它们可以像通常的对象属性一样被删除吗?
var abc1 = 'hello'
abc2 = 'world'
delete window.abc1
delete window.abc2
console.log( window )
如下所示:
你可以在上图中看到:
用var声明的变量abc1并没有被删除,仍然是window对象的一个属性; 不带 var 声明的变量 abc2 已被删除。
为什么会有这样的差异呢?
这与默认的对象属性描述符有关!
Object.getOwnPropertyDescriptor(obj, prop) //返回对象的属性描述符
var abc1 = 'hello' // 显式声明变量
var props1 = Object.getOwnPropertyDescriptor(window,'abc1')
console.log( props1 )
如下所示:
你可以在上图中看到:
window对象的属性abc1的描述符中,configurable: false表示该属性不可配置或删除。
abc2 = 'world' // 隐式声明变量
var props2 = Object.getOwnPropertyDescriptor(window,'abc2')
console.log( props2 )
如下所示:
你可以在上图中看到:
window对象的属性abc2的描述符中,configurable: true表示该属性是可配置的,可以删除。
是对象属性描述符中的默认设置导致了能否删除的差异!
另外,这两个方法的变量在解析和执行时也不同:
console.log( abc1 )
var abc1 = 'hello'
如下所示:
你可以在上图中看到:
先复制abc1javascript 变量的声明,然后声明变量abc1,结果“奇怪”为undefined,而不是报错!
在js中,变量声明和函数声明都会有“声明增强”。 js引擎解析并执行代码时,分为两个阶段: 1.预解析阶段; 2. 逐行执行阶段。
在预解析阶段,声明变量abc1,并赋予初始值undefined;
变量abc1在逐行执行阶段被参数化为'hello';
因此,在变量声明之前进行复制不会报错,并且打印的值是未定义的。
console.log( abc2 )
abc2 = 'world'
如下所示:
abc2是未定义的,类似的操作,完全不同的命运!
不带var声明的变量没有“声明改进”机制,即预解析阶段没有声明变量abc2,而是在逐行执行阶段正式参数化后有了变量abc2,所以复制abc2首先会报错!