发一个很简单的例子,之前线上代码有个错误,因为发布的时候的失误,重复包含了两个版本的common库。
然后发生了一些看似诡异的事情,其实,事情并不是无迹可寻。
出现的原因,其实是因为javascript的预编译机制,也或者说,是变量定义的机制问题。
这个东西如果要讨论的话,我觉得一个我道行太浅,再一个,网上有大段可以搜索到的,就不需要赘述了。
代码说话吧~ 把下面的测试代码扔进你的浏览器的console中,回车运行,你会看到:
(function() {
//调用 定义式的someFunc #4 (#4覆盖掉#2)
someFunc();
var someFunc = function() {
console.log('#1.function defined by var.');
}
//调用变量赋值式的someFunc
someFunc();
function someFunc() {
console.log('#2.normal.');
}
//定义式因为先运行已经被变量复制
someFunc();
var someFunc = function() {
console.log('#3.function defined by var.');
}
//变量式#3覆盖#1
someFunc();
function someFunc() {
console.log('#4.normal.');
}
//依旧是#3
someFunc();
})();
输出结果应该不外如是是这样:
#4.normal.
#1.function defined by var.
#1.function defined by var.
#3.function defined by var.
#3.function defined by var.
至于为什么,我想注释已经很明白了。 顺便发一个javascript前端面试题,感觉其实这个考察还是很必要..
在程序执行完毕后,变量a,b,c的数值是多少呢,比较简单,不过如果你不确定你知道正确答案的话,可以在浏览器里跑一下。
从这里开始基本不说答案了,因为你只需要把源码复制,扔浏览器里,答案就出来了。
(function() {
var a = 1, b = c = 0;
function x(n){n = n + 1;}
b = x(a);
function x(n){n = n + 3;}
c = x(a);
//你认为a, b, c是多少呢?
console.log('result:', a, b, c);
})();
简单变一下,答案略有改动,同时也给出了上面的那道题如果出错了的同学的原因。
(function() {
var a = 1, b = c = 0;
function x(n){return n + 1;}
b = x(a);
function x(n){return n + 3;}
c = x(a);
//你认为a, b, c是多少呢?
console.log('result:', a, b, c);
})();
(function() {
var a = 1, b = c = 0;
function x(n){return n + 1;}
b = x(a);
function x(n){return n + 3;}
c = x(a);
//你认为a, b, c是多少呢?
console.log('result:', a, b, c);
})();
再综合考察一下,这段代码会有什么问题。
提示,javascript预编译会将要声明的变量初始化为undefined。
(function() {
console.log(typeof(x));
x();
function x(){console.log('#1 is Loaded.');}
console.log(typeof(y))
y();
var y = function(){console.log('#2 is Loaded.');}
})();
最后就是这两段代码运行结果是否相同
(function() {
console.log(typeof(x));
function x(){return;}
var x = '';
console.log(typeof(x))
})();
(function() {
console.log(typeof(x));
var x = '';
function x(){return;}
console.log(typeof(x))
})();
大概就是这个样子。
2013年1月25日补充内容: 偶得一博客,是新浪运营部的前端前辈:刘晓龙的一篇分享。
http://blog.imlxl.com/archives/category/jishu
内容如下:
很简单的机制,见代码 因为预解析机制的存在,v1在赋值前已经声明在闭包里了,所以alert会出现错误。
(function() {
v1 = 1;
if(0) {
var v1;
}
})();
alert(v1);
确实看似很简单的一个例子,但是执行后会出现什么样子的错误,和为什么会出现这样的错误呢。
首先执行顺序是定义闭包(),以及使用()操作执行闭包。
接着是使用alert显示变量v1的数值。 闭包内的执行顺序是先定义全局变量v1,然后在判断0=true分支中定义闭包内的局部变量。
理论上局部不会干扰全局,打印出来的会是1. 但是犹豫预编译,定义式的变量就会被变量式的覆盖,然后定义式的变量就会失去全局的属性。
于是就会报ReferenceError: v1 is not defined
如果你确实想让他可以全局访问,可以考虑挂载全局变量,当然,需要注意的事项在这里: