Open LeoYuan opened 11 years ago
@varfunction 唐洋,有啥想法不?
谈一下我对var命令及作用域的理解吧~ 在function运行时,js引擎会先构建function的执行环境,其中重要一步就是把这个function里,通过var命令声明的变量放到这个函数的作用域头部。 需要注意的是,放到作用域头部的标识符,并不指向任何内存区域,比如看下面例子:
var a = 1;
function b() {
debugger;//第一行
a = 10; //第二行
function a() {} //第三行
}
b();
console.log(a);
b函数执行前,由于第三行的作用, 相当于 var a = function(){};
所以相当于在b的作用域顶端放入了一个 执行环境.a
,这个a并不影响全局变量,只是b函数的局部变量。
(这也是IE8和其他浏览器的差异所在,
IE8下,相当于执行执行环境.a = undefined;
,
而其他浏览器下,相当于执行执行环境.a = 执行环境.a || undefined;
)
上述代码,执行到第一行时,a = undefined;
执行完第二行,a = 10;
执行完第三行,a = function();
不知道这是不是可以解释你的问题?
洋仔,发现你上边分析的小案例有误。。。
var
和function
都是直接提升的,function
不会转换成var a = function() {}
所以,function a() {}
应该提升到a = 10
上边,因此,代码等价于
var a = 1;
function b() {
function a() {};
a = 10;
}
b();
console.log(a);
没问题的,效果都一样。
你说的“直接提升”,和我说的 “相当于 var a = function(){}
”
本质都是在作用域链的最前面定义了 a
这个东西,只是在不同浏览器中a
的初始化方式不同,所以导致你遇到的问题。
呵呵,撇开我最原始的问题不谈。。。
在上面的小demo中,function a() {}
确实被提升到了a=10
之前,虽然不影响此贴的最终结果,但是怕你对 变量提升 有点小误解,特意提醒下。
事件背景
在某个页面中引入的first.js文件中有如下一段代码(已做简化处理)。
注:
globalObj
是系统中被认可的少数几个全局变量之一。 在同一个页面中位置靠后引入的另一个js文件second.js中有如下代码此时一切如预期运行,globalObj中被注入了新的属性
secondAttr
。 可随着需求的变更,需要给globalObj
中新增加一个属性thirdAttr
,于是我写了如下一句代码结果在 IE8 下,神奇的事情出现了,
globalObj
对象中的firstAttr
消失了,去掉后来增加的代码后,又出现了,冥思苦想都想不明白,在运行var globalObj = globalObj || {};
的时候,globalObj
已经存在,显然不会去覆盖,怎么回事? 各种console都不得要领,最后被同事一句外行话惊醒,注:事实上js是解释运行的,没有编译阶段。
这才想起,js中确实有hoisting一说,即函数定义和变量初始化会被提升(hoisted),谜团遂解。
柳暗花明
正是因为这句
var globalObj = globalObj || {};
中的var globalObj = undefined
被提升到了作用域的顶端,此例即被提升到了文件最开始处,于是反而影响了文件头部那句globalObj = globalObj || {};
的执行,globalObj
被重置了!拓展阅读
JavaScript-Scoping-and-Hoisting written by ben cherry Javascript function scoping and hoisting asked on stackoverflow
疑问
不过还有一点还是不太明白,为什么IE9+, Chrome, FF都没事呢?难道对于这种情况下的hoisting做了特殊处理?