字面意思,作用域是指变量和函数的作用范围,换言之,作用域决定了变量和函数的可见性和有效时间。javascript作用域是用函数来区分,与其他语言的大括号不同。
for (var i=0; i<5; i++){ var mystring = "平底斜"; console.log(i); } alert(mystring);//弹出"平底斜"
这段代码在javascript中运行正常,在其他语言中就会报错。这是因为javascript的作用域是基于函数,而不是大括号。
作用域分为全局作用域和局部作用域。
有三种情况会出现全局作用域:
1、最外层定义的变量和函数
var mystring = "平底斜"; function fun(){ alert("Hello World"); }
变量mystring和函数fun()拥有全局作用域,在任何位置都可以直接调用。
2、未定义的变量
function fun(){ var a=b=0; mystring = "平底斜"; console.log(mystring); } fun(); alert(b);
变量mystring没有使用var进行变量声明,所以即使在函数内部也是全局变量。容易忽略的是变量b,看上去使用var进行了声明,实际上只对变量a进行了声明,等同于
function fun(){ var a=(b=0); //自右向左赋值 mystring = "平底斜"; console.log(mystring); }
一个JS文件中应该尽可能少的出现全局变量,最佳实践是使用var进行变量声明,并且在声明的同时进行赋值。
function fun(){ var a=0, b=1, c=2; //等同于var a=0; var b=1; var c=2; } fun(); alert(c); //脚本报错,因为c是局部变量
3、全局对象window
var mystring = "平底斜"; console.log(mystring); console.log(window.mystring); console.log(window["mystring"]); console.log(this.mystring); console.log(this["mystring"]);//此处this就是window,针对this以后会专题讲解
全局变量都可以看做window的属性,使用方法就如以上代码:可以用"."也可以用"[]"甚至可以省略window
局部变量只有一种情况:在函数内部声明的变量拥有局部作用域
function fun(){ var mystring="平底斜"; //局部变量 console.log(mystring); } fun(); console.log(mystring); //脚本报错
冷知识:
全局变量中,使用var声明与不使用var是有区别的,var声明的变量无法删除,未声明的变量可以删除。
var mystring="平底斜"; newstring = "博客园"; delete mystring; delete newstring; console.log(mystring); //"平底斜" console.log(newstring); //脚本报错
作用域链由内向外查找变量,在内部找到变量便停止查找,否则往上一层作用域查找,直到最外层都没有找到变量则返回undefined
var myscope = "平底斜"; function fun(){ var myscope = "博客园"; console.log(myscope); //"博客园" } fun();
上面这段代码,就是因为作用域链有内向外,先在函数内部查找myscope,找到了就直接返回该变量值,并停止查找。
易错点:
var myscope = "平底斜"; function fun(){ console.log(myscope); //脚本报错 var myscope = "博客园"; console.log(myscope); //"博客园" } fun();
声明变量会在当前作用域中置顶,又叫变量提升或者声明置顶。以上代码等同于:
var myscope = "平底斜"; function fun(){ var myscope; console.log(myscope); //脚本报错 myscope = "博客园"; console.log(myscope); //"博客园" } fun();
需要注意的是变量提升是在函数 定义 时发生,并不是在函数调用时:
var myscope = "平底斜"; function fun1(){ console.log(myscope); } function fun2(){ var myscope = "博客园"; fun1(); } fun2(); //"平底斜"
如上,fun2()调用fun1()时,是先在fun1()中搜索myscope,找不到时再到父级作用域中查找。作用域的嵌套关系是在定义时产生,而不是在调用的时候。