在JavaScript中var的重要作用及详解中我们知道,var有全局变量和局部变量之分,所以一个变量是有作用域的。在全局作用域中的变量可以被局部作用域的函数引用。而函数中的变量不能拿到全局作用域中使用。可以理解为作用域之间的包含关系。全局作用域包含着局部作用域,而局部作用域在全部作用域里面,并不包含全局作用域。两个函数就分别表示着两个相互独立的作用域,同级的函数之前,即使变量名称一样,也是互不影响的。
例如下面的例子中,在函数外部,找不到变量i,而可以引用全局变量j。
var j = 2;
function add(){
var i = 2;
console.log(i+j);
}
console.log(i)// ReferenceError: i is not defined
add();//4
一、提升变量
JavaScript的函数有个特点,就是函数会先扫描整个函数体,把申明的变量提到函数体的开头。形成了先定义后执行的顺序。如下的例子1中,在执行函数的时候,没报错,而是输出NaN,没报错的原因其实是在输出的时候,其实已经知道j是存在的,只是没赋值。试着把var j;提到var i=1;如例子2,跟例子1这个函数没区别。所以可以知道是JavaScript函数是会把变量提到函数体的最前面,可是不会把赋值提到前面。JavaScript看到的函数其实是例子2中的函数。
所以我们在书写函数的时候,尽可能养成好的习惯,把变量手动提到函数体的前面,免得带来不必要的麻烦。
例如1:
function fun(x){
var i = 1;
console.log(arguments[0]+i+j);//NaN
var j = 2;
}
fun(10);
例子2:
//把变量j提到前面。
function fun(x){
var i = 1;
var j;
console.log(arguments[0]+i+j);//NaN
}
fun(10);
二、全局作用域
无论是变量还是函数,在全局作用域中,都会被默认添加为window的属性。定义函数的时候,我们知道有两种方法,可以把一个匿名函数赋值给一个变量,所以其实这个这个变量也是window的属性。全局作用域里面的函数或者是变量都可以被全局对象window调用。
只是我们在书写的时候,把window省去了。
例如:
var i = 1;
var fun = function(){
alert(i)//输出:1
}
function myfun(x){
var i = 1;
var j = 2;
console.log(arguments[0]+i+j);//输出:13
}
alert(window.i);//输出全局变量中的i
window.fun();//使用全局对象window调用函数
window.myfun(10);
三、局部作用域
我们知道局部作用域里面的变量不能拿到全局作用域中使用,只限在局部作用域中使用,可是有一种情况,比如for循环中定义的变量i,i在for之外还可以被使用,如果想要定义for的局部作用域,只在for循环体中使用变量i,不给局部函数所使用,那我们需要定义块级作用域。
为了解决这个问题,ES6标准中定义了新的关键字let,使用let申明的变量具有块级作用域。
例如:
function fun(){
var arr =['A','B','C'];
for(var i=0; i<arr.length; i++){
console.log(arr[i])//输出A,B,C
}
console.log(i)//在for循环中定义的变量,输出3
}
function myfun(){
var sum = 0;
for(let j = 0; j<5; j++){
sum = sum + j;
}
console.log(sum);//10
// console.log(i)//会报错
}
fun();
myfun();