前端javascript高级程序设计(第四版)第三章节语言基础 第(26下-29)页 2022/9/20

书中有这句话,声明冗余报错和使用了let和var没有关联,这两个关键字只是说他们声明的变量标识符的值在哪个作用域的范围,避免声明的变量哪里都可以访问到,除非你可以做到整个程序一个重复的单词也不重复,但是那样不太现实,不是吗。
1.暂时性死区:let不会像var那样存在变量提升:只要声明了,就会在函数最开始的地方默认赋值undefined。let可不会那样,哪里开始声明,在声明的地方才能访问到let声明的变量,再let声明的前面可找不到这个声明的变量。对了还有一点let声明的不会成为window对象的属性,2.var声明的变量会成为window的属性。let声明的虽然不能被window所接纳,但是它还是在页面的生命周期存在的,所以不要去重复声明,因为它依然存在,再声明它会破环它,所以会报错。

<script>
    let name = "Nicholse"
    let age = 16
</script>
<script>
    if (typeof name !== "undefined") {//可以读取到上面的name,不是undefined为真
        let name = 666  //赋值了666给他
        console.log(name);//正常打印
    }
    console.log(name);//不是赋值了吗为什么这里还是原来的,因为它被限制在if的{}块作用域里面了,这样就可以用来处理那些希望得到参数,但是不希望改变原始参数的地方

    try {
        console.log(age);//可以正常访问16
    }
    catch (error) {
        let age //这里它就限制在了catch(){}内部,虽然不会执行,书的作者只是打个比方
    }
    age = 8515
    console.log(age);
</script>

里面说到的3.条件式声明:因为条件块中let声明仅限于该块,所以不能使用条件式声明,条件式声明就是,根据if或者其它条件判断类进行声明虽然它不会报错,但是修改的变量值只能在{}内部使用,外部无法使用,因为被限制在条件的块作用域内部了。
4.for循环中的let声明

  for (var i = 0; i < 5; ++i) {

    }
    console.log(i);//5

因为var声明的变量只能在函数内声明才可以被限制住不被渗透到外面,没有函数的约束,所以它会一直迭代,保留最后的结果,最后渗透出去,所以后面的程序打印i可以答应出5,即使是i++也是5,因为会执行完i++才会执行下面的console.log(i),这个相加的过程不可见。但是如果把for循环的var改成let,那就会限制在for循环之内,外面就无法访问到了。这解决了一个问题,明明我的变量不是这个怎么使用的时候是这样的,其实很有可能是使用for循环内部的var导致的,刚好凑巧和你在for循环之前的变量是同一个变量名字
比如下面这种事情可能就会发生,偷偷摸摸改我变量干么呢

 	var i = 66
    for (var i = 0; i < 5; ++i) {
	//这里啥也不写也能跑
    }
    console.log(i);//5

书本中的这个代码

for (var i = 0; i < 5; ++i) {//同步代码
        setTimeout(() => console.log(i), 2000) //异步代码
    }
    console.log(i);//5 //同步代码

程序会先跑同步代码,先不跑里面的每个异步代码,所以会执行完最后一次加到5之后,打印i等于5的值,然后再走异步代码,异步代码向上拿值,已经是迭代后的变量值5了,2秒所有当时没执行的异步代码一起计时开始启动了,就得到了5,题外话:少用大量setTimeout不然一起计时电脑会卡。不信你就试试把把i<5改成99999999,这样你可能F12都打不开。
如果使用let ,javascript引擎会在后台为每个循环声明新的迭代变量,先当与这个let i和下个let i是不同的,不会报错各自独立改变的值会被保留在这里外面或者别的迭代无法访问,只能是当前循环内的{}内的语句才可以访问

<script>
    var i = 66
    for (let i = 0; i < 5; ++i) {
        setTimeout(() => console.log(i), 2000) //异步 ,2秒后打印0,1,2,3,4,5
    }
    console.log(i);//66
</script>
<script>
    var i = 66
    for (let i = 0; i < 99; ++i) {
        let i = 999
        setTimeout(() => console.log(i), 2000) //异步,2秒后打印五个999
    }
    console.log(i);//66
</script>
为什么会打印五个999,可以理解为如果没有i=999,那它这一层就没有i就会向上找去,找到i当时保存的值,但是如果你写了i=999,执行异步的时候,他就向上找到了这一层直接打印999
再来一个变种
var i = 66
    for (var i = 0; i < 99; ++i) {//最后的结果还是渗透出去了
        let i = 999
        setTimeout(() => console.log(i), 2000) //异步,但是999打印了,因为上面一层的let建立了块作用域限制了向外取i的值,使用它声明的i的值
    }
    console.log(i);//99

3.3.3 const声明:和let基本相同,但是多个要求,必须初始化变量,且不能修改它的变量值,否则会报错,但是赋值对象没关系,因为赋值对象,只会将对象的地址赋值给它,后续修改对象的值不会造成报错。也不允许重复声明,也有块作用域。
const声明的限制适用于指向变量的引用,这就涉及堆和栈了,引用就是这个数据再内存中的哪个位置,基本数据的引用地址是固定的,所以改变变量的基本数据类型会导致引用地址发生变化,造成报错,对象赋值给变量const是将对象名的地址给了它,但是对象名内的属性存储的值改变并不会影响到它的对象名。不能用const来声明迭代变量,因为,最后进行的++会违反它声明后不能修改的规则:

var i = 66
    for (const i = 0; i < 9; i++) {
        console.log(i);
        //上面一行执行完成打印0后,会进行隐形的++就会触发Assignment to constant variable(赋值给常量变量)
    }
    console.log(i);//99

但是如果只是创建,但是进行条件判断后不修改这个值是可以使用的,书中有写,只是声明,但是不会修改它。书中用for in (循环对象属性名)和for of(循环数组项),他们都是对象对象的地址不会变化,所以用const没问题
3.3.4太困了,明天继续。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值