## 作用域链
当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会为其创建一个作用域,又称为执行上下文。
在页面加载后,会首先创建一个全局作用域,然后每执行一个函数,会建立一共对应的作用域,从而形成一条作用域链,每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域
作用域链的作用是解析标识符,当创建函数的时候,会将this/ arguments/命名参数和该函数中的所有局部变量添加到当前作用域中,当JavaScript需要查找变量的时候(这个过程称为变量解析),他会首先会从作用域链中的链尾(也就是当前作用域)查找是否有该变量属性.如果没有找到就顺着作用域链(也就是全局作用域链)继续查找,直到查到链头,如果仍然未找到该变量,就认为这段代码的作用域链上不存在该变量,并抛出一共引用错误的异常。
作用域链需要明确:
1.1ES6之前定义变量通过var ES6之后定义变量用let
1.2.ES6之前没有块级作用域,只有全局作用域和局部作用域
ES6新增加了块级作用域 但是通过let定义变量并无差异(都是局部作用域)
1.3.ES6之前函数大括号外都是全局作用域
1.4.ES6之前函数大括号中都是局部作用域
ES6之前作用域
2.1全局作用域我们又称为0级作用域
2.2定义函数开启的作用域就是1/2/3…级作用域
2.3JavaScript会将这些作用域链接在一起形成一个链条,这个链条就是作用域链
0---->1----->2------>3
2.4.除0级作用域外,当前作用域级别等于上级+1
变量在作用域链查找规则
3.1在当前找,找到就使用当前作用域找到的
3.2如果当前作用域没找到,就去上一级作用域找
3.3依次类推到0级为止,如果0级作用域没找到就报错
var在相同作用域下声明变量可以同名,后声明的覆盖先声明的
let不可以在相同作用域下声明同名变量,会报错
预解析规则
1.将变量声明和函数声明提升到当前作用域最前面
2.将剩余代码按照书写顺序依次放到后面
注意点:通过let定义的变量不会被提升(不会被预解析)
ES6之前定义函数的格式
say();
//ES6之前的这种定义函数的格式,是会被预解析的,所以可以提前调用
function say(){
console.log("hellow it666")
}
//预解析之后的代码
function say(){
console.log("hellow it666")
}
say();
二:
say();//say is not a function
//如果将函数赋值给一个var定义的变量,那么函数不会被预解析,只有变量会被预解析
var say = function(){
console.log("hellow it666")
}
//预解析之后的代码
var say // undefined
say();
say = function(){
console.log("hellow it666")
}
三:
ES6定义函数
不会被预解析 //say is not defined
let say = () => {
console.log("hellow it666")
}
预解析练习
1.
var num = 123;
fun();
function fun(){
console.log(num)
var num = 666
}
//预解析后
var num
function fun(){
var num //undefined
console.log(num) //undefined
num = 666
}
num = 123;
fun();
2.
var a = 666;
test();
function test(){
var b = 777;
console.log(a);
conso.log(b);
console.log(c);
var a = 888;
let c = 999;
}
//预解析之后
var a;
function test(){
var b;
var a;
b = 777;
console.log(a); //undefined
conso.log(b); //777
console.log(c); //报错
a = 888;
let c = 999;
}
a = 666;
test();
3.
//在ES6之前没有块级作用域 ,所以没有将这两个函数定义到其他函数中
所以这两个是全局作用域
//1.在高级浏览器中,不会对{}中定义的函数进行提升
//只有在低级浏览器中才会正常解析
if(true){
function demo(){
console.log("hellow demo1111")
}
}else{
function demo() {
console.log("hello demo2222")
}
}
4.
//如果变量名称和函数名称同名,那么函数的优先级高于变量
//企业开发中 变量名称和函数名称不能重名
console.log(value);
var value = 123;
function value(){
console.log("fn value");
}
console.log(value)
//预解析之后
function value(){
console.log("fn value");
}
console.log(value);//函数的定义
var value
value = 123;
console.log(value)//123