1、函数作用域
JS中只有函数级别的作用域,没有块级别的作用域;即,只有在进入或者退出函数的时候,作用域会发生变化。
1.1、概述
- 外部对内部可见;
- 内部对外部不可见;
- 外部内部都有,就内部优先
1.2、例子
1.2.1 外部对内部可见
var scope = 'g';
function t(){
console.log(scope); // g
console.log(scope); // g
}
t();
1.2.2 内部对外部不可见
function t(){
var scope="l";
}
t();
console.log(scope); //scope is not defined
1.2.3 都可见,内部优先
var scope = 'g';
function t(){
console.log(scope); // undefined
var scope = '1';
console.log(scope); // 1
}
t();
1.2.4 JS的作用域,都是函数级别的
// 小案例1
var scope = 'g';
if(true){
var scope = '1';
console.log(scope); //1
}
console.log(scope); //1,如果是java结果为g
// 小案例2
for(var i=0;i<10;i++){ }
console.log(i); //10
2、执行环境(EC)
2.1、概述
执行环境execution context,定义了执行期间可以访问的变量和函数
2.2、分类
2.2.1、全局执行环境
- Global Object (window)
- 从见到js代码开始创建
- 到网页关闭时销毁
2.2.2、函数执行环境
- Activation Object
- 从函数调用开始创建
- 最后到函数调用结束时销毁
3、作用域链与生成作用域链
3.1、作用域链
- 作用域[[scope]],每个函数都有
- 作用域是私有属性,只能由JS引擎访问
- 作用域链由AO和GO构成
- 所谓执行环境,就是根据作用域链一次查找变量和函数
- 找到即停
- 全部找完无果,报错
- 作用域链每个函数都有
- JS的栈在作用域链中
3.2、生成作用域链
- 函数【定义时期】拷贝父亲的作用域链;
- 函数【调用时期】生成AO将AO压入作用域链栈顶;
3.3、生成作用域链相关示例
3.3.1、代码
var g = 'g';
function fa(){
var a = 'a';
function fa(){
var b = 'b';
}
fb();
}
fa();
3.3.2、代码分析图解
3.4、生成作用域链相关思考
3.4.1、函数多次调用时,是产生相同的AO还是不同的AO?
function fa(){
console.log(a); // undefined
var a = 100;
a++;
}
fa(); // 会有一个新的Scope Chain,同时产生自己的AO
fa(); // 会有一个新的Scope Chain,同时产生自己的AO
fa(); // 会有一个新的Scope Chain,同时产生自己的AO
3.4.2、函数递归调用时,时产生相同的AO还是不同的AO?【不同的AO】
var b = 15;
function fa(x){
if(x > 2){
var a = 100;
a++;
fa(x-1);
}
return 0;
}
fa(3);
3.4.3、除了函数还有什么可以影响作用域链
// 像内部优先
var name = "weiran"
person={
name:"weiranyi",age:18,height:175,
dog:{name:"yi",age:3}
}
with(person){
console.log(name);
}
with(person.dog){
console.log(name);
}
console.log(name);
3.5、作用域链应用
3.5.1 提高效率
- 尽量少使用靠近上层的变量,多使用局部变量
3.5.2 重名,易出错
- 尽量减少不同层次函数使用相同的变量名
- 避免函数名与变量名一样
3.5.3 承上启下(函数退出后AO是否一定被释放:不一定)
function outer(){
var scope = 'outer';
function inner(){
return scope;
}
return inner;
}
var fn = outer();
console.log(fn()); // outer