JS中的作用域以及作用域链
作用域
-
全局作用域:最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。
-
局部作用域:局部作用域一般只在固定的代码段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部。在ES6之前,只有函数可以划分量作用域,所以在函数的外面无法访问函数内的变量。
-
块级作用域:凡是代码块就可以划分变量的作用域,这种作用域的规则就叫块级作用域。 块级作用域,函数作用域,词法作用域的区别:
-
块级作用域和函数作用域描述的是:什么东西可以划分变量的作用域
-
词法作用域描述的是:变量的查找规则 块级作用域,函数作用域,词法作用域的联系:
-
块级作用域包含函数作用域
-
词法作用域和块级作用域,函数作用域之间没有任何交集。他们是从两个角度去描述作用域的规则。
-
在ES6之后,JS采取块级作用域+词法作用域
<script>
//let声明的变量具有块级作用域
let a = 123 //全局变量
function fn(){
let b = 1234 //函数作用域
console.log(a);// 123
}
console.log(b); //报错 b is not defined,再块级作用域外无法访问块级作用域内部的变量
fn()
</script>
let,var,const声明的区别
let和var的区别
let所声明的变量只在let命令所在的代码块内有效。(块级作用域)
<script>
function fn(){
let a = 123
var b = 1234
}
//let 声明的变量存在块级作用域,var声明的变量不存在块级作用域
console.log(a)//报错:a is not defined
console.log(b)//1234
</script>
let命令不存在变量提升
<script>
//var的情况
console.log(a)//undefind
var a = 123
//let的情况
console.log(b)//报错:ReferenceError
let b = 1234
</script>
let声明变量存在暂时性死区(即变量会绑定某个区域,不受外部影响)
暂时性死区(简称TDZ):ES6中规定,如果区块中存在let和const命令,区块会对这些命令声明的变量,从一开始就形成一个封闭的作用域。凡是在变量被声明之前就使用这些变量,就会报错。简而言之,在代码块内使用let声明变量之前,该变量是不可使用的。语法上称为暂时性死去。
<script>
if(1){
//TDZ开始
//a = 123 //报错:Cannot access 'a' before initialization
//console.log(a) //报错:Cannot access 'a' before initialization
//在let声明变量a之前,都属于a的暂时性死区
let a
//TDZ结束
console.log(a) //undefined
a = 123
console.log(a) //123
}
</script>
- let命令不允许重复定义但是var可以而且后定义的变量会覆盖掉前面的变量。因此,不能在函数内部重新声明参数,但是可以在函数内部不同块级作用域内声明同名参数。
<script>
//报错
function fn(){
let a = 123
var a = 234
}
//报错
function fun(){
let a = 123
let a = 234
}
var a = 123
var a = 234
console.log(a) // 234
</script>
const
const声明一个只读的常量。一旦声明,常量的值就不能改变。const声明的变量不得改变值,这意味着,const一但声明,就必须立即初始化,不能留到以后赋值。
特点:
const的作用域与let命令相同:只在声明所在的块级作用域内有效。const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。const声明的常量,也与let一样不可重复声明。
<script>
const a = 123
a = 4 //报错
//报错
if(true){
a = 234
const a
}
const a //报错
</script>
作用域链
什么是作用域链?
当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)。由子级作用域返回父级作用域中寻找变量,就叫做作用域链。 作用域链中的下一个变量对象来自包含环境(外部环境),而再下一个变量对象则来自下一个包含环境,一直延续到全局执行环境。
全局执行环境的变量对象始终都是作用域链中的最后一个对象,作用域链的前端始终都是当前执行的代码所在环境的变量对象。
可以将作用域链理解为一种查询变量的机制。使用变量时,在当前作用域未找到,会沿着作用域链一层层的查找外部环境,直到全局环境。
内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数
<script>
let a =123
if(a){
let a =1234 //如果将内部环境定义的a注释,则会去当前环境的外部环境寻找变量
console.log(a) //1234
}
</script>