ES6之块级作用域

作用域

作用域指变量所作用的范围,在 Javascript 中有两种作用域:

  • 全局作用域
  • 函数作用域

变量提升

变量提升(Hoisting)被认为是, Javascript 中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。具体表现就是所有通过 var 声明的变量会提升到当前作用域的最前面。

function foo() { 
   console.log(temp); 
}

function bar() {    
    console.log(temp);  
    var temp;
}

foo(); // ReferenceError: temp is not defined
bar(); // undefined

可以看到用 var 声明了的并不会报错。因为其实函数 bar 等同于

function bar() {    
    var temp;    
    console.log(temp);
}

大多数类 C 语言语法的语言都拥有块级作用域。在一个代码块(括在一对花括号中的一组语句)中定义的所有变量在代码块的外部是不可见的。定义在代码块中的变量在代码块被执行结束后会变释放掉。这是件好事。

糟糕的是,尽管 Javascript 的代码貌似支持块级作用域,但实际上 Javascript 并不支持(就是因为有变量提升)。这个混淆之处可能成为错误之源。

所以在 ES6 中规定了 let 和 const 来支持块级作用域。但是,是不是真的提升就不存在了呢,可以看下面暂时性死区这部分。

let

let 可以理解为『更完美的 var』,使用方法很简单;

let foo = 3;

使用方法基本和 var 相同,而且声明的变量只在其块和子块中可用,这点也与 var 相同。 二者之间最主要的区别在于 var 声明的变量的作用域是整个封闭函数。

function foo() {
    if(true) {
        var temp = 5;
         console.log(temp);
    }

    console.log(temp);
}

function bar() {
    if(true) {
        let temp = 5;
        console.log(temp);
    }

    console.log(temp);
}

foo(); // 5 和 5
bar(); // 5 和 "ReferenceError: temp is not defined

let 声明的变量的作用域只是外层块,而不是整个外层函数。

我们可以利用这个特性来替代立即执行函数(IIFE)。

// IIFE
(function(){    
    var temp = xxx;    
    /*
        other code
    */}())
 
// 块级

{   
    let temp = xxx;    
     /*
        other code
    */

}

const

const 的用法跟 let 差不多,但是 const 一定要初始化, 不初始化是会报错的。

const temp = 4;// 没有初始化报错

const t; // SyntaxError: Missing initializer in const declaration

const 是块级作用域,const 跟 let 的语义相似,就是用来声明常量的,一旦声明了就不能更改。值得注意的是 const 声明的变量记录的是指针,不可更改的是指针,如果 const 所声明的是对象,对象的内容还是可以修改的。

// 重新赋值声明导致报错

const PI = 3.14;
PI = 3.1415926; // TypeError: Assignment to constant variable.

// 给对象增加属性不会导致 obj 的指针变化,所以不会报错

const obj = { foo: 2 };
obj.bar = 3;
console.log(obj); // {foo: 2, bar: 3}

暂时性死区

使用 let 或 const 声明的变量,在声明没有到达之前,访问该变量都会导致报错,就连一直以为安全的 typeof 也不再安全。

// TDZ1

function foo() {    // TDZ 开始
    console.log(typeof temp);    
    let temp = 5; // TDZ 结束
}

foo(); // ReferenceError: temp is not defined

报的错是 ReferenceError,如果使用 var 声明的话,temp 输出应该是 undefined,从 let 声明的变量的块的第一行,到声明变量之间的这个区域被称作暂时性死区(TDZ)。凡是在这个区域使用这些变量都会报错。

// TDZ2

function bar() {    
    console.log(typeof temp);
}

bar(); // undefined

看到上面两个例子仔细思考有没有觉得想到点什么?

在函数里没有用 let 声明 temp 的时候,temp 是 undefined,讲道理在 let 声明前也应该是 temp,然而 foo 函数却报了错,证明了就算是在未到达 let 声明的地方,但是在用 let 之前已经起到了作用。这是不是说明其实 let 也有提升,只是在 TDZ 使用的时候报错了,而不是 undefined。

事实上,当 JS 引擎检视下面的代码块有变量声明时,对于 var 声明的变量,会将声明提升到函数或全局作用域的顶部,而对 let 或 const 的时候会将声明放在暂时性死区内。任何在暂时性死区内访问变量的企图都会导致“运行时”错误(runtime error)。只有执行到变量的声明语句时,该变量才会从暂时性死区内被移除并可以安全使用。

禁止重复声明

在同一个块内,let 和 const 不能声明相同的标识符。禁止的情况包括:

  • let 或 const 和 let 或 const
  • var 和 let 或者 const
  • 函数参数与 let 或 const
// let 和 let
let foo = 1;
let foo = 2;

// let 和 const

let foo = 1;
const foo = 1;

// var 与 let

var foo = 1;
let foo = 1;

// 函数参数与 let

function bar(foo) {    
    let foo = 1;
}

以上情况都是会报 SyntaxError。但是在嵌套的作用域内使用 let 声明同一变量是被允许的。

var foo = 1;

{   
    // 不会报错
    let = 2;    
    // other code
}

同时因为是 let 和 const 是块级作用域,声明的变量在当前块使用完之后就会被释放,所以就算使用相同的标识符也不会覆盖外部作用域的变量, 而 var 是会覆盖外部作用域的变量的。

function foo() {    
    var bar = 1;
    {        
        let bar = 2;
    }    
    console.log(bar);
}

function zoo() {    
    var bar = 1;
    {        
        var bar = 2;
    }    
    console.log(bar);
}

foo(); // 1
zoo(); // 2

最佳实践

在 ES6 的发展阶段,被广泛认可的变量声明方式是:默认情况下应当使用 let 而不是 var 。对于多数 JS 开发者来说, let 的行为方式正是 var 本应有的方式,因此直接用 let替代 var 更符合逻辑。在这种情况下,你应当对需要受到保护的变量使用 const。

在默认情况下使用 const ,而只在你知道变量值需要被更改的情况下才使用 let 。这在代码中能确保基本层次的不可变性,有助于防止某些类型的错误。

思考题

两个思考题,我会把答案放在评论中。请点击原文链接去看答案

// 思考题 1

switch (x) {  
    case 0:    
        let foo;    
        break;  
    case 1:    
        let foo; // TypeError for redeclaration.
        break;
}

// 思考题 2
function bar(){   
    var foo = 1;   
    if (true) {      
        let foo = (foo + 2); 
   }
}
bar();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值