js作用域
1.对js作用域的理解。
作用域
作用域分为全局作用域和函数作用域,我们可以理解为变量的生存环境(空间)。全局作用域包含函数作用域,函数作用域里的变量可以访问到全局作用域中的变量,但是反之则不行。
变量提升
在js作用域中还有变量提升的现象(只有var 声明的变量才会有变量提升,window声明的不会),赋值语句最后生效。当我定义一个变量,如果它没有被赋值,它是属于undefined;
变量提升的优先级
函数声明 > 函数形参(函数的形参属于函数作用域;) > 自定义变量
延长作用域,闭包(return function(){alert(...);})
闭包核心思想:函数调用时,在该函数被声明的地方,通过作用域一层一层往外找;
1)
window.a = 1;
var a = 2; //全局作用域
function test() {
var a = 3; //函数作用域
alert(a);
}
alert(a);
如上所示,alert(a)中的a变量寻找的顺序是 函数作用域—全局作用域,在test函数内部找到了,则弹出值为3;第二个alert,在全局作用域中寻找a,弹出值为2;
2)
var a = 2;
function test2() {
//var a;
alert(a);
var a = 4;
}
对于test函数内部,存在声明的变量a,但是a的赋值操作在alert函数后面。则考虑在执行函数时,会在函数头部首先声明该函数内部使用到的所有变量,且不会被赋值。所以弹出值为undifined;
3)自定义变量 PK 声明函数
function test3(a) {
//function a(){}; //同样提升到函数头部的变量,因为变量名相同,按照优先级的关系,alert的弹出值为函数a的函数体;
//a = 7;
//var a;
alert(a);
var a = 5;
function a() {
}
}
test3(7);
4)参见 HOW THIS WORK IN JAVASCRIPT中的function pattern
var obj = {
name:'aoao',
getName:function() {
alert(this.name);
}
}
obj.getName(); //1
var test5 = obj.getName;
test5();//2
注意比较标注1与标注2的区别;
对于标注1:函数getName在obj内部声明,调用时this指向obj这个对象;
对于标注2:函数getName的函数体赋值给了test5这个变量,相当于是:
var test5 = function() {
alert(this.name);
}
注意!此时函数声明在window对象下,this指向window对象;
5) 声明函数 PK 函数表达式
//function name() {alert(3);};
name();
function name() {alert(3);}
与
//var name;
name2();
var name2 = function() {alert(2);};
声明函数会把整个函数声明放到头部,函数表达式会把其函数名的变量提升到头部,因此使用声明函数更加安全;
6)函数形参 PK 声明函数
var f = (function(f) { function f() { return 1} return f(); function f() { return 3} f = 2; })(4); console.log(f);//3
我们来一步步解析上方代码的执行顺序,
f == 4 (f作为实参)
==>>两个相同函数名的声明函数 按照后来居上原则,return 1的被 return 3的干掉 , 且声明函数权重大于函数形参,所以在自执行函数中的变量f指向return 3 的函数块(堆内存中)
== >> return f();
所以控制台输出值为3。对于表达式 f = 2;我们不需要理会,因为程序是自上而下解析的,在执行到return语句时,当前函数就执行完毕了,不会执行到该赋值语句;