这是个很经典的例子,也是一个常见的笔试题。大家先不要看答案,试试看。页面的JS代码如下:
(function(){
var m =n = 6;
})();
console.log(“m defined? ” + (typeof a !== ‘undefined’));
console.log(“n defined? ” + (typeof b !== ‘undefined’));
下面来挖挖这个例子背后的知识点。

知识点1:()()是什么?
其实是(function (){/*代码语句*/})();,这是个自执行匿名函数,首先第一个括号里是一个匿名函数(没有函数名),第二个括号表示立即执行,合起来就表示自执行匿名函数(页面加载解析JS的时候就直接执行了),而一般情况下,函数是在调用的时候才执行。
为什么要用这种方式呢?
自执行函数除了立即执行之外,主要是为了划分作用域,或者说创建命名空间,如果不显示的声明为全局变量,匿名函数的代码是封闭在匿名函数内的,外部无法访问。
知识点2:表达式的写法
var m = n = 6;
其实是以下两个语句的
n = 6; //
var m = n; //
而不是 var两个变量
var n = 6;
var m = n;
不同之处在 n=6 he var n=6,这又涉及到JS中变量的创建,
JS是弱类型语言,所以可以随便挖(var), 但是关键字 var 创建的变量是 局部变量,只存在所在作用域,如果前面没有关键字 var 声明的变量是全局变量——变成全局对象window的属性。所以这涉及到变量的声明问题。

知识点3:作用域
见到问题的关键部分。一开始我们以为 在函数内变量m,都是函数内声明的,而两个函数在匿名函数外无法调用匿名函数内的两个变量,所以都应该是undefined。
正确答案是 m是undefined,n 是
m defined? false
n defined? true
原因在知识点2已经说过,m 是匿名函数内局部变量,n是全局变量,所以在函数外部,可以访问n,不能访问m。
这一延伸一个很复杂的知识点——作用域。
- 变量作用域
变量作用域前面已经说过,需要特别说明的是函数的参数也是函数内的局部变量,和函数内显示声明的局部变量一样,他们的作用域仅仅在函数体内,函数外是访问不到的。而且全局变量和局部变量同名的情况下,局部变量的优先级要高于全局变量。
var num = 111; //声明一个全局变量
function show() {
var num = 222; //声明一个局部变量
return num;
}
console.log(show()); //输出:222
var num = 111; //声明一个全局变量
function show() {
return num;
}
console.log(show()); //输出:111 ,函数内找不到变量num,就一直往上级的作用域找,直到全局作用域。
- 函数作用域
不像C和Java是块级作用域,JS是函数作用域。意思是在JS中,函数体内声明的变量在其函数体内始终是可见的,包括函数体内的嵌套的函数。
- 作用域链
上一篇JS引用类型中讲过,函数也是对象。实际上,在JS中里一切都是对象。函数对象和其它对象一样,拥有可以访问的属性和一些仅供JavaScript引擎访问的内部属性。[[Scope]]就是其中一个内部属性,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。对象在创建后,其作用域就可以通过这个一层层往上翻,形成一个类似链条的结构:

作用域是一个很复杂的问题,也是一个难点。本片文章整体上进行了介绍,具体技术细节,下次再聊。所以,JS也没有想象中的那么容易,加油吧!

发表评论