ES6深入学习(一)块级作用域详解
栏目: JavaScript · 发布时间: 5年前
内容简介:JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。 注意:只有声明本身被提升,而任何赋值或者其他执行逻辑都被留在原处。 函数声明会被提升,但函数表达式不会函数声明和变量声明都会被提升,但(可以拥有多个“重复”声明的代码中出现)是,函数会优先被提升。 考虑这段代码:注意var foo2是一个重复的(因此被无视),即使它出现在function foo2()...声明之前。因为函数声明是在普通变量之前被提升的。但后续的声明会覆盖前一个。
JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。 注意:只有声明本身被提升,而任何赋值或者其他执行逻辑都被留在原处。 函数声明会被提升,但函数表达式不会
foo() //Function foo function foo(){ console.log('Function foo') } foo2() //TypeError: foo2 is not a function var foo2 = function() { console.log('Function foo2') } 复制代码
函数声明和变量声明都会被提升,但(可以拥有多个“重复”声明的代码中出现)是,函数会优先被提升。 考虑这段代码:
foo2() //2 var foo2 = function() { console.log(1) } function foo2(){ console.log(2) } foo2()//1 复制代码
注意var foo2是一个重复的(因此被无视),即使它出现在function foo2()...声明之前。因为函数声明是在普通变量之前被提升的。但后续的声明会覆盖前一个。
var声明及变量提升(Hoisting)机制 在函数作用域或全局作用域中,通过关键字var声明的变量,无论实际上在哪声明的,都会被当成在当前作用域顶部声明的变量。
function getValue(flag){ //var value,变量value的声明被提升至函数顶部,而初始化操作停留在原处执行 if(flag){ var value = "true"; }else{ return null } //此处可以访问变量value,值为undefined } 复制代码
块级声明
块级作用域(也被称为词法作用域)存在于函数内部、块中({}之间的区域)
- let声明的用法与var相同,用let代替var来声明可以把变量的作用域限制在当前代码块中。let声明不会被提升,假设作用域中已经存在某个标识符,在使用let关键字声明则会抛出错误。
var a = 1; let a = 2;//Uncaught SyntaxError var b = 3; if(true){ let b = 4;//不会抛出错误 } 复制代码
-
const声明一个常量,其值一旦被设定后不可更改,因此通过const声明的常量必须进行初始化。
-
对于复合类型的变量,const声明不允许修改绑定,但允许修改值。变量名不指向数据,而是指向数据所在的地址,const命令只是保证变量名指向的地址不变,并不能保证该地址的数据不变,急可以修改该对象的属性值。
const b = 'b'; b = 'c';//Uncaught SyntaxError: const obj = {}; obj.a = 'a'; console.log(obj);//{a:'a'} 复制代码
临时死区(Temporal Dead Zone)与var不同,let和const声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,即使相对安全的typeof操作符也会触发引用错误
if(true){ console.log(typeof a)//Uncaught ReferenceError let a = 1; } 复制代码
由于console.log(typeof a)语句会抛出错误,因此用let定义并初始化变量a的语句不会被执行,此时a还位于所谓的临时死区(TDZ)中;将let换成const会有相同的效果。 JavaScript引擎在运行代码是发现变量声明时,要么将它们提升至作用域顶部(var声明),要么将声明放到TDZ中(let和const声明)。访问TDZ中的变量会触发运行是的错误,只有执行过变量声明语句后,变量才会从TDZ中移出,然后方可正常访问。
循环中的块作用域绑定
for(var i = 0;i<3;i++){ console.log(i)//0,1,2 } console.log(i)//3 //由于var声明提升,变量i在循环结束后仍可以访问。如果换用let声明,循环结束后访问i则会抛出一个错误 复制代码
循环中的函数:
var data = []; for(var i = 0;i<10;i++){ data[i] = function(){ console.log(i) return i } } data[1]();//10 复制代码
**循环里的每次迭代同时共享着变量i,循环内部创建的函数保留了对相同变量的引用,循环结束时变量i的值为10,所以每次调用console.log(i)时就会输出是在10。
为解决这个问题,通常会使用立即调用函数表达式(IIFE),以强制生成计数器变量的副本
var data = []; for(var i = 0;i<10;i++){ data[i] = function(){ console.log(i); return i }() } data[5];//5 复制代码
循环中的let声明let声明模仿上述示例中IIFE所做的一切来简化循环过程,每次迭代都会创建一个新变量,并以之前迭代中同名变量的值将其初始化(即删除IIFE之后仍可得到预期的效果)
var arr = []; for(let i = 0;i<10;i++) { data[i] = function(){ return i } } data[1]();//1 复制代码
全局作用域绑定
let和const与var的另一个区别是它们在全局作用域中的行为,当var被用于全局作用域时,会创建一个新的全局变量作为全局对象(浏览器中的window对象)的属性,这意味着var可能会无意覆盖一个已经存在的全局属性
//浏览器中 var RegExp = "hello"; console.log(window.RegExp);//hello 复制代码
即使全局对象RegExp定义在window上,也不能幸免于var声明覆盖。如果使用let或const,会在全局作用一下创建一个新的绑定,但该绑定不会添加为全局对象的属性,即不会覆盖全局变量,只能遮蔽它。
let RegExp = "hello"; console.log(RegExp)//"hello" console.log(window.RegExp === RegExp);//false,不会破坏全局作用域 复制代码
以上所述就是小编给大家介绍的《ES6深入学习(一)块级作用域详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Elasticsearch 存储深入详解
- Elasticsearch 写入原理深入详解
- Elasticsearch Nested 类型深入详解
- 深入Nginx + PHP 缓存详解
- 深入详解 Jetpack Compose 实现原理
- KVM详解,太详细太深入了,经典
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。