JavaScript作用域和this关键字
1.JS的作用域分为全局作用域和函数作用域
全局作用域内定义的变量可以在全局和函数体内访问,函数作用域内定义的变量只能在自己的函数作用域内访问。如果变量前没有加var,无论在哪定义都会成为全局变量。
1 //全局作用域 2 var globalVal = "global"; //全局变量 3 4 (function func (){ 5 //函数作用域 6 var localVal = "local"; 7 globalVal2 = "global too"; 8 9 alert(globalVal); //global 10 11 })(); 12 13 alert(localVal); //localVal is not defined 14 alert(globalVal2); //global too
上面代码中的函数为立即执行函数,不经过调用就会自己执行,方便看测试结果,另一个重要作用稍后解释。
另外,13行处报错not defined和JS的undefined类型是完全不同的两个概念。前者表示这个变量没有声明过,是不存在的或者不在可访问的作用域内,程序会产生运行时错误并终止运行;后者是JS的基本数据类型,表示此变量声明过,但未被定义,或被赋值为undefined,这个值可以显示、比较、运算,不会报错。
2.JS没有块级作用域
C++、Java等语言都有块级作用域,如for循环while循环等,JS却是没有块级作用域的!
1 for(var i=0;i<3;i++) 2 { 3 alert(i); //0,1,2 4 } 5 alert(i); //3
上面5行代码处i的值是3,也就是说 var i; 写在for的里面和外面效果是一样的。C++之所以无法在for结束之后访问到i,是因为在一个块级作用域执行完它的垃圾回收机制就启动了,把块级作用域内不用的变量释放了。
3.构造函数创建函数的作用域是全局
1 var globalVal = "global"; 2 3 (function func (){ 4 //函数作用域 5 var localVal = "local"; 6 7 var func2 = new Function("alert(globalVal)"); 8 var func3 = new Function("alert(localVal)"); 9 func2(); //global 10 func3(); //localVal is not defined 11 })(); 12 13 func2(); //func2 is not defined
上面代码显示,由构造函数创建的函数可以访问到全局变量globalVal,但访问不到局部变量localVal。第13行可能产生误解,new Function创建的函数作用域是全局的,把它赋值给局部变量func2,外部访问func2时未定义是正常的。
4.使用立即执行函数创建函数作用域
如1节所示,使用立即执行函数很大的用处是创建函数作用域,避免产生全局变量,因为全局变量重名可能产生覆盖等一些难以排查的问题。
立即执行函数的4种写法:
1 (function func(a){ 2 var i = a; 3 console.log(i); 4 })(1); 5 6 (function func(a){ 7 var i = a; 8 console.log(i); 9 }(2)); 10 11 !function func(a){ 12 var i = a; 13 console.log(i); 14 }(3); 15 16 void function func(a){ 17 var i = a; 18 console.log(i); 19 }(4);
5.this关键字
this是一个总指向调用者的指针。以下是this指向的不同情况:
- 作为对象方法调用,this是对象 :point.move()
- 作为函数调用(包括立即执行函数),this是window :move()
- 作为内部函数,即声明在函数中的函数,this是window that=this
- 作为构造函数调用,即用new,this指向新生成的对象
node.js中没有window对象,这种情况都指向null。
6.ES6箭头函数中的this
this总是指向被调用者,再也不需写var that=this这类代码。