1 变量的"作用域链"定义:
变量在当前环境now、内部环境f1、内部深层环境f2/f3....都起作用的现象形成了一个链条,这个链条就称为变量的"作用域链"
<script type="text/javascript">
//作用域链
//week变量通过"作用域链"使得其可以在各个环境被访问到。
var week = "Friday";
console.log('now:'+week);
function f1(){
console.log("f1:"+week);
function f2(){
console.log("f2:"+week);
function f3(){
console.log("f3:"+week);
}
f3();
}
f2();
}
f1();
</script>
2 作用域链的作用
2.1 变量必须"先声明、后使用", 变量预解析机制, 他会把所用声明提前(赋值留在原地)到各自的作用域的顶部。
函数可以"先使用、后声明", 原因是函数有"预加载"过程(函数声明先于其他执行代码进入内存)。本质还是函数的声明在前, 使用在后。
实例1:
<script type="text/javascript">
//作用域链作用
//① 变量必须"先声明、后使用"
// 函数可以"先使用、后声明"
// 变量预解析机制
//他会把所用声明提前(赋值留在原地)到各自的作用域的顶部
console.log('now:'+week); //undefined
var week = "Friday"; //将声明语句(var week;)提前到 console.log('now:'+week)之前, 而赋值(week = "Friday";)留在原地
var getInfo = "hello";//B 同名getInfo变量会覆盖 函数
getInfo();//C TypeError: getInfo is not a function
function getInfo(){//A
console.log("this is Friday");
}
</script>
实例2:
<script type="text/javascript">
var color = "blue";
function f1(){
var age = 20;
function f2(){
//在相对的一个环境里边, 变量必须"先声明、后使用"
console.log('颜色:'+color); //blue green 【undefined】
var color = "green";
}
f2();
}
f1();
</script>
2.2 内部环境可以访问外部环境的变量, 反之不然
<script type="text/javascript">
//作用域链作用
//② 内部环境可以访问外部环境的变量, 反之不然
var weather = "sunning"; //全局环境
function getInfo(){
//内部环境
var yesterday = "rain";
console.log('天气:'+weather);//内部访问外部的weather变量
}
getInfo();
console.log('天气2'+yesterday);//错误。外部不能访问内部变量
</script>
2.3 变量的作用域是声明时决定的, 而不是运行时
实例1:
<script type="text/javascript">
//作用域链作用
//③ 变量的作用域是"声明时"决定的, 而不是运行时
var title = "javascript study";//该变量可以被f1和f2访问
function f1(){
console.log("f1:"+title);
}
function f2(){
var title = "php study";
f1(); //【① javascript study】 ② php study
console.log("f2:"+title);//【f2:php study】
}
f2(); //f1:javascript study f2:php study
</script>
实例2:
<script type="text/javascript">
//作用域链作用
//③ 变量的作用域是"声明时"决定的, 而不是运行时
var weight = 130; //B
function f1(){ //A
console.log("f1:"+weight);
}
weight = 150; //C
f1(); //D 【150】
weight = 180; //E
f1(); //F 【180】
</script>
2.4 变量和函数编译的顺序
案例1:
<script type="text/javascript">
var a = 1;
function fn1(){
fn2();
var a = 2;
console.log(a);
function fn2(){
console.log(a);
}
}
fn1();
</script>
上述代码编译执行的顺序:
<script type="text/javascript">
var a;//预解析
a = 1;
function fn1(){
var a;
function fn2(){
console.log(a);
}
fn2(); //undefined
a = 2; //赋值语句留到原地
console.log(a);//2
}
fn1();
</script>
注意
①函数中重要的是他的调用位置而不是声明位置。
②有赋值对的变量优于函数声明, 函数声明优于没有赋值的变量。
案例2:
<script type="text/javascript">
var a = 1;
function a(){
console.log(a);
}
a(); //error, Uncaught TypeError: a is not a function
</script>
上述代码编译执行的顺序:
<script type="text/javascript">
var a; //预编译
function a(){ //预编译
console.log(a);
}
a = 1; //赋值语句在声明函数之后
a(); //err, Uncaught TypeError: a is not a function
</script>
分析:有赋值的变量优于函数声明, 函数声明优于没有赋值的变量。
当我们a()这个a指的是var a = 1; 的这个a所以此时a是一个变量他不是一个函数, 理所当然报错。