1.块级作用域绑定

本章涉及3个知识点,var、let、const,现在让我们了解3个关键字的特性和使用方法。

var

JavaScript中,我们通常说的作用域是函数作用域,使用var声明的变量,无论是在代码的哪个地方声明的,都会提升到当前作用域的最顶部,这种行为叫做变量提升(Hoisting)

也就是说,如果在函数内部声明的变量,都会被提升到该函数开头,而在全局声明的变量,就会提升到全局作用域的顶部

function test() {
    console.log('1: ', a) //undefined
    if (false) {
      var a = 1
    }
    console.log('3: ', a) //undefined
}

test()

//实际执行时,上面的代码中的变量a会提升到函数顶部声明,即使if语句的条件是false,也一样不影响a变量提升。

function test() {
    var a
    //a声明没有赋值
    console.log('1: ', a) //undefined
    if (false) {
      a = 1
    }
    //a声明没有赋值
    console.log('3: ', a) //undefined
}

在函数嵌套函数的场景下,变量只会提升到最近的一个函数顶部,而不会提升到外部函数。

//b提升到函数a顶部,但不会提升到函数test。
    function test() {
        function a() {
          if (false) {
            var b = 2
          }
        }
        console.log('b: ', b)
    }
    
    test() //b is not defined

如果a没有声明,那么就会报错,没有声明和声明后没有赋值是不一样的,这点一定要区分开,有助于我们找bug。

//a没有声明的情况
    a is not defined

let

let和const都能够声明块级作用域,用法和var是类似的,let的特点是不会变量提升,而是被锁在当前块中。
一个非常简单的例子:

    function test() {
        if(true) {
          console.log(a)//TDZ,俗称临时死区,用来描述变量不提升的现象
          let a = 1
        }
    }
    test()  // a is not defined

    function test() {
        if(true) {
          let a = 1
        }
        console.log(a)
    }    
    test() // a is not defined

唯一正确的使用方法:先声明,再访问。

function test() {
        if(true) {
          let a = 1
          console.log(a)
        }
    }
    test() // 1

const

声明常量,一旦声明,不可更改,而且常量必须初始化赋值。

const type = "ACTION"
我们试试重新声明type,看看会报什么错:

const type = "ACTION"
    type = 1
    console.log(type) //"type" is read-only
    
    const type = "ACTION"
    let type = 1
    console.log(type) //Duplicate declaration "type"

const虽然是常量,不允许修改默认赋值,但如果定义的是对象Object,那么可以修改对象内部的属性值包括新增删除键值对也是可以的。

const type = {
      a: 1
    }
    type.a = 2 //没有直接修改type的值,而是修改type.a的属性值,这是允许的。
    console.log(type) // {a: 2}
    
    type.b = 3 //拓展Object也是没有问题的
    console.log(type) // {a: 2 , b: 3}
    
    delete type.b=3 //删除整个键值对也OK的
    console.log(type) // {a: 2}
    
    //如果重新定义数据结构~常量的内存地址值发生改变,这个是不可行的。
    type={}; //Assignment to constant variable.
    type=[]; //Assignment to constant variable.

const和let的异同点

相同点:const和let都是在当前块内有效,执行到块外会被销毁,也不存在变量提升(TDZ),不能重复声明。

不同点:const不能再赋值,let声明的变量可以重复赋值。
临时死区(TDZ)

javascript引擎在扫描代码发现变量时,要么将它们提升至作用域顶部(遇到var声明),要么将说明放到临时死区TDZ)中(遇到constlet声明)。访问临时死区中的变量会触发运行时错误。只有执行过变量声明语句后,变量才会从临时死区中移出,然后方可正常访问。

上面我们也提到了TDZ的场景,那么,有什么用呢?答案就是没什么用。
临时死区的意思是在当前作用域的块内,在声明变量前的区域叫做临时死区。

if (true) {
      //这块区域是TDZ
      let a = 1
    }

块级作用域的使用场景

除了上面提到的常用声明方式,我们还可以在循环中使用,最出名的一道面试题:循环中定时器闭包的考题
在for循环中使用var声明的循环变量,会跳出循环体污染当前的函数。

for(var i = 0; i < 5; i++) {
      setTimeout(() => {
        console.log(i) //5, 5, 5, 5, 5
      }, 0)
    }
    console.log(i) //5 i跳出循环体污染外部函数
    
    //将var改成let之后
    for(let i = 0; i < 5; i++) {
      setTimeout(() => {
        console.log(i) // 0,1,2,3,4
      }, 0)
    }
    console.log(i)//i is not defined i无法污染外部函数

在全局作用域声明

如果在全局作用域使用let或者const声明,当声明的变量本身就是全局属性,比如closed。只会覆盖该全局变量,而不会替换它。

    window.closed = false
    let closed = true
    
    closed // true
    window.closed // false

最佳实践

在实际开发中,我们选择使用var、let还是const,取决于我们的变量是不是需要更新,通常我们希望变量保证不被恶意修改,而使用大量的const,在react中,props传递的对象是不可更改的,所以使用const声明,声明一个对象的时候,也推荐使用const,当你需要修改声明的变量值时,使用let,var能用的场景都可以使用let替代。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容