ES6语法(1)—— 用let、const代替var

    学习资源地址:阮一峰大神的书

    前端面试的最后一个问题:请问你对ES6有什么了解?ok,了解一下

    1.let的使用以及块级作用域的提出

    由于let继承了var弱类型的特性,因此在大部分情况下let和var是十分相似的,但如果对javaScript的作用域以及预解析机制(在我的前端面试题一文中)有所了解的话,那么let和var简直是天壤之别。

    下面这段代码是笔试中经常会问到的,细细体会原先的函数作用域和块级作用域的区别

<html>
  <button>1</button>
  <button>2</button>
  <button>3</button>
  <button>4</button>
  <button>5</button>
  <button>6</button>
</html>
<script type="text/javascript">
  var btnArr = document.getElementsByTagName('button')
  for(var i = 0;i<btnArr.length;i++){
    btnArr[i].onclick = function(){
      console.log(i) //666666
    }
  }
  console.log(i)//6
</script>

    这里的六个按钮都会输出6,因为for循环的 ()小括号 { } 大括号都不具备划分作用域的功能,因此i被声明到了全局变量中,一不小心,你就污染了全局作用域。由于i是全局变量,因此当点击任意按钮的时候,控制台均会打印i的最终结果6,也就是去访问计算机内存给i分配的某个地址(关于地址的概念后面会用紫薯精的例子说明,不太了解的可以继续看下去)。

    ok,既然没有得到想要的结果,那来看看传统的闭包解决方式

<script type="text/javascript">
  var btnArr = document.getElementsByTagName('button')
  for(var i = 0;i<btnArr.length;i++){
    (function(i){ //这个i是形参i,相当于在闭包的作用域内申明了一个i(叫j也行) = 传入的全局i
      btnArr[i].onclick = function(){
        console.log(i)
      }
    })(i)//这个i是全局变量i,会根据for循环依次改变数值
  }
</script>

    上面这段代码,能够得到正确地结果,因为全局变量i在传入匿名函数的时候作为参数传入,并被一个叫做‘i’的同名称的小伙子给接收到了,这个参数在匿名函数内部有自己的作用域,因此匿名函数内部的同名形参'i'已经和全局i脱离了,所以这段代码会正确地打印012345。虽然解决了之前的问题,但是也会造成内存泄漏的问题(同名形参形成后立马被内部函数使用得不到释放,有兴趣了解下JS的垃圾回收机制)

    来看看ES6是怎么解决上述问题的

 

<script type="text/javascript">
  let btnArr = document.getElementsByTagName('button')
  for(let i = 0;i<btnArr.length;i++){
    btnArr[i].onclick = function(){
      console.log(i) //012345
    }
  }
  console.log(i)//报错,而非打印undefined
</script>

    可以看到,我并没有做任何操作,只是把var替换成了let,就能正确执行代码逻辑了。

    所以什么是块级作用域?简单的说,就是以{....}为新的作用域,包括for,if,function,都能生成自己的作用域,当然块级作用域也继承了之前的某些特性,如子级作用域会向上级作用域依次查询未定义的变量,同时父级作用域不能访问子级中的变量等。当然双大括号生成作用域只是一种便于记忆的方法,for循环的情况就比较特殊,需要单独讲一下。

    首先在for的小括号()中,也就是设置循环的那一部分,会生成一个特殊的父作用域,这里的变量能被循环作用域访问,但又相对独立,来看下面这个例子

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
//打印3次abc

    在上述例子中,内部变量i能被成功赋值,打印三次‘abc’,因此设置循环的部分的代码,既没有污染全局作用域,也不会影响内部同名变量,注意我说的是赋值,而不是覆盖,ES6不允许在相同作用域内,重复声明同一个变量。

    关于let的三个特性

1、不允许在相同作用域内,重复声明同一个变量(代码规范!)

  //不允许在相同作用域内,重复声明同一个变量。
  {
    let a = 1;
    let a = 2; // 报错 Uncaught SyntaxError: Identifier 'a' has already been declared
  }

2.不存在变量提升(代码规范*2)

不存在变量提升
  console.log(b) //undefined
  var b = 1
  console.log(b) //1
  {
    console.log(b) //报错 Uncaught ReferenceError: b is not defined
    let a = b
    console.log(b) 
  }

    稍微解释下这个机制,之前用var声明变量的时候,不管是函数声明还是变量声明,浏览器的预解析机制都会先拿到这部分声明,再去遍历你的代码,这就为某些先使用变量再声明变量的程序员纠正了错误,但也会导致代码逻辑混乱,因此在ES6中不允许使用未声明的变量。(强行让你规范代码的感觉)

3.暂时性死区 (新旧特性结合导致)

//暂时性死区
  let c = 1
  {
    console.log(c) //报错 c is not defined
    let c = 2
    console.log(c)
  }

    听起来很高大上的一个特性,其实只是继承了之前的特性以及结合新的特性导致的。

    之前的特性:层级关系作用域内会优先查找已经在内部声明的变量

    新的特性:所以在本例中,c未声明就打印,当然报错啦

    

2.const的使用

    基本用法:const声明的变量,不能改变!?(有点类似xxx语言的static)

    什么不能变:常规变量(String,Number,Boolean)声明并赋值后就不能改变,如果变就会报错。对象(JSON,Array)的地址不能改变。

    什么能变:对象的值可以改变

    下面来举两个例子,说明下常规变量和对象有什么区别?

<script type="text/javascript">
  const 紫薯精 = '紫薯'
    ......
  紫薯精 = '苹果' //Uncaught TypeError: Assignment to constant variable.
</script>

    第一个例子,用const 声明了 一个叫做紫薯精的变量,并赋值为'紫薯',当后续操作改变这个值的时候,就会报错。来看一下计算机是怎么执行这个操作的。

    某一天,在计算机广阔无垠的内存大地上,来了个农民,他的名字叫紫薯精,计算机给他的任务,是种紫薯,过了一段时间,紫薯精过来申请,说他要种苹果,计算机发现这个农民并没有改变种紫薯的权利,于是告诉他Assignment to constant variable(食屎啦馁)

 

<script type="text/javascript">
  const 地主 = [] 
  地主.push('紫薯精') //['紫薯精']
  地主.length = 0 //[]
  地主 =  [] //Assignment to constant variable
</script>

    第二个例子,用const声明了一个叫做地主的对象,并赋值为空,后续可以进行操作,但无法重新赋值。来看一下,计算机是怎么管理对象的。

    某一天,在计算机广阔无垠的内存大地上,来了个地主,计算机发现这个人是个地主(对象),就赋予他一片可以连续拓展的土地的起点地址,地主有权利在这片地里划分地皮,并分配给不同的农民,现在地主家的第【0】块土地分给了紫薯精,当然地主也有权利收回土地,然后有一天,地主说要申请,之前的地不要了,要申请一块新的地,计算机发现他没有权限改变这个地址,会告诉他Assignment to constant variable(傻逼吧你)

    上述两个例子大概能说清楚什么能变和什么不能变。

    当然ES6也提供了Object.freeze()方法来冻结对象

    const 地主=Object.freeze(['紫薯精'])

    就能够冻结该对象

    关于该方法请自行研究用法,const的报错机制跟vue中的watch属性有点类似,有兴趣的大神可以研究下vue的源码,看是不是能验证我的猜想。

    

 

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值