块级作用域绑定
之前的变量声明var
无论在哪里声明的都被认为是作域顶部声明的,由于函数是一等公民,所以顺序一般是function 函数名()
、var 变量
。
块级声明
块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域存在于:
- 函数内部
- 块中(字符和
{
和}
之间的区域)
临时死区
javascript引擎在扫描代码发现变量声明时,要么将它们提升至作用域顶部,要么放到TDZ中。访问TDZ的变量会触发运行时错误。只有执行过变量声明后,变量才会从TDZ中移出,然后访问可正常访问。
if(condition){
console.log(typeof value) // 引用错误
let value = "blue";
}
// 以下的value并不在TDZ中
console.log(typeof value); // "undefined"
if(condition){
let value="blue"
}
循环中的块作用域绑定
使用let
变量只存在于for循环中,一旦循环结束,无法访问这个变量
for(let i=0;i<10;i++){
process(items[i]);
}
// i 在这里不可访问,抛出一个错误
console.log(i);
循环中的函数
var
声明让开发者在循环中创建函数变得异常困难,因为变量到了循环之外仍能访问。
var funs = [];
for(var i=0;i<10;i++){
funs.push(function(){
console.log(i)
})
}
funcs.forEach(function(func){
func(); // 输出10次数字10
})
为了解决这个问题,开发者们在循环中使用立即调用函数表达式,以强制生成计数变量的副本。IIFE表达式为接受的每一个变量i都创建一个副本并存储为变量value。这个变量的值就是相应迭代创建的函数所使用的值,因此调用每个函数
var funs = [];
for(var i=0;i<10;i++){
funs.push((function(value){
return function(){
console.log(i)
}
})(i))
}
funcs.forEach(function(func){
func(); // 输出0,1,2...
})
循环中的let声明
let
声明模仿上述所做的一切来简化循环过程,每次迭代循环都分创建一个新变量,并以之前迭代中同名变量的值将其初始化。也适合于for-in
for-of
for-each
var funs = [];
for(let i=0;i<10;i++){
funs.push(function(){
console.log(i)
})
}
funcs.forEach(function(func){
func(); // 输出0,1,2...
})
let声明在循环内的行为是标准中专门定义的,它不一定与let的不提升特性相关,理解这一点至关重要。事实上,早期let实现中不包含这一行为。是后来加入的。
循环中使用const
在for(const i=0;i<10;i++)
会报错,因为i++
时试图改变常量i的值。而在for-in
和for-of
中因为没有去试图改原i值的操作。而是新创建了一个变量。所以执行会跟使用let
声明一样
全局作用域绑定
let
和const
与var
的另外一区别是它们在全局作用域中的行为。当var被用于全局作用域时,它会创建一个新的全局变量作为全局对象的属性。这意味着var很有可能会无意中覆盖一个已经存在的全局变量。而使用let
和const
不能覆盖全局变量,而只能遮蔽它。so
let RegExp = 'Hello world'
console.log(window.RegExp === RegExp)
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4308