作用域链和预解析分析

作用域链

定义

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。

1
2
3
4
5
6
7
8
9
var name = 'xm';
function fn(){
var name = 'xh';
var sex = 'male';
function fn2(){
var name = 'xhei';
var age = 18;
}
}

以上代码有三个作用域,形成一条作用域链,它们之间的关系如下图。

此处输入图片的描述

假若我们需要打印fn2的name属性,那么输出的肯定是fn内部的name。

当我们在某在作用域中查找变量的时候,这个查找过程会沿着作用域链来进行。
首先在当前作用域进行查找,如果有则找到,没有的话就会沿着作用域链往上一层作用域进行查找,直到window对象或者找到为止。

同级的变量越内层,优先级越高。

作用域过长的话会导致,会导致查询时间过长,效率低下。所以,局部变量速度一定是快于优于全局变量的。

延长作用域链

1
2
3
4
5
6
7
8
9
10
11
var person = {}
person.name = 'xm';
person.sex = 'male';
var score = 4;

with(person){
name = 'xh'
sex = famale';
socre = 44;
}
console(score); //44

此处举例,但并不推荐使用with( )延长作用域链。

预解析

我们先来看一段代码

1
2
3
4
5
6
7
var name ='xm';
var age = 18;
function fn(argument){
console.log(name); //undefined
var name = 'xh';
var age =10;
}

为什么console.log(name)会输出undefined?因为js在解析时进行了预解析。

解析情况
window
name = undefined
age = undefined
function fn(argument){
console.log(name); //undefined
var name = ‘xh’;
var age =10;
}
fn
name = undefined
age = undefined
argument = undefined

定义

运行代码之前,会把var变量和function函数预先解析到使用环境中。

执行过程

1、读取整个源代码
2、查找到需要解析的变量和函数。
3、进行提前赋值。

预解析赋值

1、所有的变量,提前赋值:undefined;
2、所有的函数,在正式运行代码前,都赋值为整个函数块。

需要注意

1、变量名与函数名一样冲突,预解析将只保留函数。function的优先级高于var。
2、函数名与函数名一样冲突,预解析将会覆盖之前的。只保留后面的函数。
3、if、for等代码块里定义函数的话,将没有办法进行预解析。
4、只有var声明的变量和function才能被预解析。

案例分析

JS作用域问题一
案例一

1
2
console.log(fn); //function fn(){}
function fn(){}

案例二

1
2
console.log(fn); //undefined
var fn = function fn(){}

案例三

1
2
console.log(fn); //控制台报错
fn = 1;

JS作用域问题二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
console.log(a); //function a( ){console.log(4);}
var a = 1;
console.log(a); // 1
function a(){
console.log(2);
}
console.log(a); // 1
var a = 3;
console.log(a); // 3
function a( ){
console.log(4);
}
console.log(a); //3
a( ); // 报错

预解析为 function a( ){console.log(4);}

JS作用域问题三

预解析是分标签进行的。

案例一

1
2
3
4
5
6
<script>
console.log(a); // 报错
</script>
<script>
var a = 1;
</script>

案例二

1
2
3
4
5
6
<script>
var a = 1;
</script>
<script>
console.log(a); // 1
</script>

JS作用域问题四
案例一

1
2
3
4
5
6
7
var a = 1;
function fn(){
console.log(a); //undefined
var a = 2;
}
fn();
console.log(a); // 1

案例二

1
2
3
4
5
6
7
var a = 1;
function fn(){ //函数没有参数
console.log(a); // 1
a = 2;
}
fn();
console.log(a); // 2

案例三

1
2
3
4
5
6
7
var a = 1;
function fn(a){ //参数相当于局部变量
console.log(a); // undefined
a = 2;
}
fn();
console.log(a); // 2

案例四

1
2
3
4
5
6
7
var a = 1;
function fn(a){
console.log(a); // 1
a = 2;
}
fn(a); //实参a为1传入函数
console.log(a); // 1