什么是作用域?
作用域是变量与函数的可访问范围。它们是以函数块来划分,每个函数就是一个作用域。
局部作用域
在函数里面声明的变量或者函数是局部作用域,它们只能在声明的函数里面使用,在外面是访问不到的。
1 function fn(){ 2 var a=10; 3 function fn1(){ 4 console.log('hello'); 5 } 6 } 7 console.log(a);//a is not defined 8 console.log(fn1());//fn1 is not defined
因为函数可以嵌套函数,在函数内部声明的变量与函数,它的子函数是可以访问到的。
1 function fn(){ 2 var a=10; 3 function fn1(){ 4 console.log(a);//10 子函数可以访问到父函数的变量 5 } 6 fn1(); 7 } 8 fn();
全局作用域
在函数外面声明的变量或者函数就是全局作用域,它们在任何地方都是可以访问到的(包括script标签对)。
1 <script> 2 var a=10; 3 </script> 4 <script> 5 console.log(a);//10 6 </script>
如果一个变量没有var而直接赋值,那不管它是在函数内部还是在函数外声明,它都具有全局作用,在任何地方都可以访问到。声明变量的时候,一定要加var,尽量避免使用全局变量。
1 function fn(){ 2 c=100; 3 } 4 fn(); 5 console.log(c);//100
所有的全局变量都是window的属性。
作用域链
作用域链是变量与函数的查找规则,函数要找到一个变量,首先他会找自己内部有没有这个变量,如果自己内部有这个变量,它就会取这个变量的值。如果没有,它就会一层一层的往外找,直到找到为止。如果外面也没有,就会报错。
1 var a=5; 2 function fn1(){ 3 var a=3; 4 function fn2(){ 5 console.log(a);//undefined 6 var a=2; 7 console.log(a);//2 8 } 9 fn2(); 10 console.log(a);//3 11 } 12 fn1(); 13 console.log(a);//5
预解析
变量与函数都会有一个解析过程,在作用域中会提前把带有var和function关键字的事先声明,解析到当前作用域的最开始的位置,然后再从上到下执行js语句。
通过var关键字定义的变量或函数进行预解析的时候都只是声明,不管它有没有赋值,都会先赋一个undefined值。
1 console.log(a);//undefined 2 var a=1; 3 console.log(b);//undefined 4 var b; 5 console.log(c);//undefined 6 var c=function(){ 7 alert(1); 8 }
预解析只会发生在通过var定义的变量和function定义的函数上。
注意:函数表达式的函数体是不会被预解析的,所以不能在声明前去调用。
1 fn();//fn is not defined 2 abc();//undefined is not a function 3 var abc=function fn(){ 4 console.log(1); 5 };