ES6深入学习(一)块级作用域详解

栏目: JavaScript · 发布时间: 6年前

内容简介: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深入学习(一)块级作用域详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

GWT in Action

GWT in Action

Robert Hanson、Adam Tacy / Manning Publications / 2007-06-05 / USD 49.99

This book will show Java developers how to use the Google Web Toolkit (GWT) to rapidly create rich web-based applications using their existing skills. It will cover the full development cycle, from ......一起来看看 《GWT in Action》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具