作用域是指变量的作用范围,在 JavaScript 中有两种作用域,一种是全局作用域,一种是函数作用域。先看个例子:
function first(){ var a = 1; };
function second(){ console.log(a); };
first(); //调用函数 first
second(); //调用函数 second,报错:a is not defined
上面这个例子就牵扯到作用域的问题,变量 a 在函数 first 中声明,那么它的作用范围就仅限于在函数 first 中,在 second 函数中打印变量 a,就会报错:变量 a 没有被定义。下面来具体说一下 JavaScript 中的这两种作用域:
1、函数作用域
JavaScript 把函数视为一个封闭的结构体,与外界完全独立,在函数内声明的变量、参数、私有函数等对外是不可见的。函数作用域在调用函数时创建,函数执行完毕后销毁,每一次调用函数都会创建一个新的作用域,他们之间是相互独立的,在函数作用域中可以访问到全局作用域的变量,但是在全局作用域中一般无法访问到函数作用域的变量,函数作用域可以通过 return 语句(闭包的方式)向外界开放内部成员,例如:
function outer(){
var data = 1; //外层函数的内部数据会一致缓存在内存中
function inner(){
return data;
}
return inner;
}
var colsure1 = outer(); //拿到闭包之后可以决定什么时候执行它
var colsure2 = outer();
console(colsure == colsure); //false
var data1 = colsure1(); //执行拿到的闭包
var data2 = colsure2();
console(data1 == data2); //true
由于调用了两次 outer() 方法,从而创建了两个 data 对象,因此两个闭包访问到的数据(data)在内存中的地址是不同的。
在函数作用域中操作一个变量时,它会在自身作用域中寻找该变量,如果找到就直接使用,如果没有找到就会到上一级作用域中寻找,直至找到全局作用域,如果全局作用域中依然没有该变量,就会报错:ReferenceError。如果在函数中要访问全局变量,可以直接通过 window 对象来访问。
2、全局作用域
直接写在 <script> 标签中的 JavaScript 代码,都在全局作用域。全局作用域在页面加载时创建,在页面关闭时销毁。在全局作用域中,有一个全局对象 window,它有浏览器创建并可以直接使用,在全局作用于下创建的变量和函数都会作为 window 对象保存。全局作用域中的变量都是全局变量,在页面的任意部分都可以访问到。在脚本中自定义一个变量或函数时,可以通过 window 对象访问它们。先看个例子:
var a = 1; //全局变量 a
function fun(){ //全局函数
alert(a);
}
alert(window.a); //引用window对象的属性a,返回 1
window.fun(); //调用window对象的方法fun,返回 1
定义全局变量与在 window 对象上直接定义属性还是有一点不同:全局变量不能通过 delete 运算符删除,而直接在 window 对象上定义的属性可以被删除。
var a = 1;
window.b = 2;
c = 3;
alert(delete window.a); //返回 false,删除失败
alert(delete window.b); //返回 ture,删除成功
alert(delete window.c); //返回 ture,删除成功
alert(window.a); //返回 1
alert(window.b); //返回 undefined
alert(window.c); //返回 undefined
使用 var 语句声明全局标量,window 会为这个属性定义一个名为"configurable"的特性,这个特性的值被设置为 false,这样改属性就不能通过 delete 运算符删除。
直接访问为声明的变量,JavaScript 会抛出错误,但是通过 window 对象进行访问,可以判断未声明的变量是否存在。
alert(a); //抛出异常
alert(window.a); //返回 undefined