关于JS作用域

一.JavaScript是如何执行的?

比如要执行var a=1;
1.任何一段JavaScript代码片段是通过JavaScript引擎执行的,在执行之前,它要先通过JavaScript编译器进行编译;
2.你一定很好奇,为什么var/function声明会提前吧?这是因为编译器在编译的时候会先找到该作用域所有的变量声明,因为编译器在遇到var a的时候会询问作用域是否存在该变量,如果是则忽略该声明;否则他会要求作用域在当前作用域集合中声明一个变量a;
3.编译器为引擎生成运行时需要的代码;处理a=1这个赋值操作,JavaScript引擎在运行的时候首先询问作用域,查看在当前的作用域集合中是否存在查找的变量,如果找到就会使用这个变量,在这段代码中是将1赋值给a;

也就是说:变量的赋值操作是这样的:

  • 编译器在当前作用域中声明一个变量(前提是之前这个变量没被声明,若声明过,那不会重复声明)
  • 运行时引擎会在作用域中查找这个变量,若找到则为变量赋值,未找到则会抛出异常

不难发现,编译器和声明也好,引擎的赋值也罢,都是依赖于当前作用域的,那么接下来我们来说说作用域!

二.JavaScript的作用域

作用域可以说它是一套规则,规定着变量/函数的可使用范围,即它控制着变量/函数的可见性和生命周期

1.作用域的分类

1.1 全局作用域

——在程序的任何地方都可访问到的变量/函数

  • 函数外部声明
  • 没有被声明的变量,直接赋值
  • window.xxx

1.2 函数作用域

在函数内部声明,仅函数内部可访问的变量/函数

1.3 ES6新增的块级作用域与暂时性死区

使用let/const声明的变量形成块级作用域,不存在声明提前且不可重名声明,仅在当前作用域可访问(称为暂时性死区)

与var命令的区别

  • 不可声明提前
console.log(a);//undefined
var a=1

console.log(b);//报错
let b=1
  • 不可重复声明
let a;
let a=1;
//Uncaught SyntaxError: Identifier 'a' has already been declared
  • 仅在当前块级作用域可访问
    你可能很奇怪,本来不是也有函数作用域吗?这个块级作用域和函数作用域有什么区别呢?请看看下边的例子
//1.函数内
function fun(){
    
    
 var a=0
 console.log(a)
}
fun()//0
console.log(a)//报错

function fun(){
    
    
 let a=0
 console.log(a)
}
fun()//0
console.log(a)//报错



//某个块级for循环,if-else,while等等都算块级作用域
/if(true)/{
    
    
  let a=0;
  console.log(a)// 0
}
console.log(a)// Uncaught ReferenceError: a is not defined

/if(true)/{
    
    
  let a=0;
  console.log(a)// 0
}
console.log(a)//0

let块级作用域的一个妙用:

var a=[];
for(var i=0;i<10;i++){
    
    
	a[i]=function(){
    
    
		console.log(i)
	}
}
a[5]();//10
console.log(i);//10

var b=[];
for(let i=0;i<10;i++){
    
    
	b[i]=function(){
    
    
		console.log(i)
	}
}
b[5]()//5
console.log(i)//Uncaught ReferenceError: i is not defined
  • var声明的变量,全局范围内均有效,所以在for循坏等非函数作用域中全局只有一个变量i,每一次循环,变量i的值都会发生改变,注意这个循环内被赋值给 数组a 的 函数 内部console.log(i)【在函数作用域内没有i,往上级作用域中查找最终找到全局的i】
  • let声明的变量在仅在它所在代码块内有效,在外部调用会报错;上述代码中,i若是let声明的,当前i仅在本轮循环有效,所以每一次循环的i都是一个新的变量;至于每一轮循环变量i都是在不同块级作用域中重新声明;JS引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上计算。
  • 另外,for循环设置循环变量的那部分是一个父作用域,而循环体内部就是一个单独的子作用域

三.作用域链

一般情况下,变量取值到会去创建这个变量的作用域中。

但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

猜你喜欢

转载自blog.csdn.net/carolyn30/article/details/107427227