- js中没有块级作用域,只有全局作用域和函数作用域。(es5以下)全局变量可以在任何地方访问,局部变量只能在声明它的地方访问。
var a=1; function func(){ var a=2; } console.log(a);//1
- 在函数中声明变量时,省略var后会声明全局变量。
function func(){ a=1; } console.log(a)//输出1
- 在js中,当变量被声明时,声明会被提升到它所在函数的顶部。
function func(){ console.log(a);//undefined var a=1; } function _func(){ var a; console.log(a);//undefined a=1; }
上面
var a=1;
相当于做了两件事,声明 a变量和为变量a赋值1;所以,上面的例子中的func函数等效于_func函数。
这里要注意的是:声明了变量后没有赋值,值是undifined,而如果没有声明这个变量则会报错X。 - 在函数被调用时,js引擎会对函数代码进行两轮处理。第一轮引擎分析代码并做了三件事:
- 声明+初始化函数参数
- 声明局部变量
- 声明并初始化函数
- 执行环境和执行环境对象
执行环境是指函数的执行,由函数执行时发生的所有事物组成。
执行环境对象是一个对象{},用于保存执行环境部分的变量和函数。
每次调用函数都会创建一个执行环境对象。
执行环境对象不能直接访问。
下面是执行outer(1)的过程js引擎在第一轮中每一步 执行环境对象所发生的变化,可以看出,第一轮中并不执行内部函数和为局部变量赋值。
outer(1);//执行环境对象:{} function outer(arg){//执行环境对象:{arg:1} var local_var='foo';//执行环境对象:{arg:1,local_var:undefined} function inner(){//执行环境对象:{arg:1,local_var:undefined,inner:function(){...}} console.log('inner'); } inner();//js引擎第一轮不会执行inner()代码 }
var a=1; function outer(){ var a=2; console.log(a);//2 otherOuter();//1 } function otherOuter(){ console.log(a); }; outer();
由于函数作用域是按照词法来划分的,所以作用域在定义函数时就确定了,因此,即使在outer内部调用otherOuter函数,otherOuter也不能访问outer内的变量。把定义移到outer函数里面,则不同:
var a=1; function outer(){ var a=2; console.log(a);//2 function otherOuter(){ console.log(a); }; otherOuter();//2 } outer();
- 作用域链:当有嵌套环境时,变量的作用域就形成了作用域链,查找变量的定义时,js引擎会首先在当前执行环境查找,如果没有找到,则会沿着作用域链向上,直到找到该变量或者到达全局作用域(window或者global)为止。全局变量是作为全局对象的属性来保存的。定义全局变量a,会有a===window.a