过一遍ES6知识点(一)

2019-04-14 17:13发布

本文具体内容:
  1. let的相关用法以及所需要注意的问题
  2. const的相关用法
  3. 声明变量的6中方式
  4. 加深对块级作用域的理解
  5. 顶层对象(如何在不同环境中获取顶层对象)

let 和 const 命令

let 的使用
  • let 用来声明变量,只在let命令所在的代码块中有效。【代码块:使用花括号包住的内容称为代码块{}】

    利用let只在当前代码块中有效的特性 解决 for 循环中的问题:
    这里写图片描述
    这里写图片描述
    总结:
    - var声明的变量在全局范围内都有效,全局变量只有一个i,所以每一次的循环,变量i的值度会发生改变。在数组a的函数内部的变量i指向的就是全局的i。所以无论执行数组a的哪一个成员最终所打印出的i均为10
    - let 声明的变量在块级作用域内有效,即在循环中,当前的i只在本轮循环有效。所以每一轮循环都是全新的变量i。
    问题:
    每一轮的i重新声明,那么怎么知道上一轮循环的值,从而计算出本轮循环的值?
    解答:JavaScript引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮的循环基础上进行计算
    注意: 这里写图片描述
    for循环有一个特别之处:设置循环变量的部分是一个父作用域,而循环体内部是一个单独的子作用域
  • let不存在变量提升
    变量提升: 即变量在声明之前可以使用,值为undefined
    若使用let来声明,在声明之前使用变量将会报错
    这里写图片描述
  • let =>暂时性死区
    即只要在这个{块级作用域}中使用let来定义变量,则所声明的变量将“绑定”这个区域,不会受外部(全局变量)的影响。
    【全局变量的名称与块级作用域的名称一致时,则全局变量将不会在块级作用域中起作用。】
    这里写图片描述
    let变量声明之前的部分均属于let变量的死区,只要在之前使用了let变量均会报错
    这里写图片描述
    隐蔽的死区
  • 下图代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。如果y的默认值是x,就不会报错,因为此时x已经声明了。 这里写图片描述
  • let声明x变量时,还没有声明完成之前,使用变量将会报错
    这里写图片描述
  • 不允许重复声明
    不允许在相同作用域内重复声明同一个变量【不能在函数内部重新声明参数】
    这里写图片描述
    这里写图片描述
const的使用
1.基本规则
  • 声明只读常量
  • 声明后不可修改
  • 一旦声明,必须马上初始化
  • 若只声明不初始化将报错
  • 只在声明所在的块级作用域内有效
  • 声明的常量不提升,存在暂时性死区,只能在声明的位置后面使用
  • const声明的常量,与let一样不可重复声明(不管使用var、let、还是const声明均不可)
2.本质
  • 并不是值不可变动,而是变量指向的内存地址所保存的数据不得改动
  • 对于简单类型的数据(数值、字符串、布尔值),值保存在变量所指向的内存地址,因此等同于变量。
  • 对于复合类型的数据(对象与数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证指针是固定的,即总指向另一个固定的地址,并不能控制其地址中所存的数据。所以将对象声明为常量时需要小心。
    这里写图片描述
    这里写图片描述
  • 将对象冻结,使得添加新属性将不起作用,在严格模式下将会报错
    这里写图片描述
  • 将对象属性也冻结,即将对象彻底冻结
    这里写图片描述

声明变量的六种方式

es5:
- var
- function
es6:
- let
- const
- import
- class

为什么出现块级作用域

  1. 内层变量可能覆盖外层变量
    这里写图片描述
    调用f()函数之后打印出的结果为undefined。这是由于var声明的变量存在变量提升,导致内层的tmp覆盖了外层的tmp变量。打印结果时内层变量并没有赋值
  2. 用来计数的循环变量泄露为全局变量
    这里写图片描述
    变量i只用来控制循环,但是循环结束之后,i变量并没有消失,而是泄露成了全局变量

ES6的块级作用域

  1. 两个代码块中的同名变量不相互影响
  2. 外层作用域无法读取内层作用域的变量
  3. 内层作用域可以定义外层作用域的同名变量,但二者不相互影响

块级作用域与函数声明

  1. 在ES6中,允许在块级作用域之中声明函数
  2. 块级作用域中,函数声明语句在块级作用域之外不可引用
  3. 在浏览器ES6的环境中,块级作用域内声明的函数,行为类似于var声明的变量,会提升到所在的块级作用域的头部。但是在其他环境中还是将块级作用域的函数声明当做let来处理
  4. ES6允许在块级作用域中声明函数,条件是使用{}
    这里写图片描述
    代码示例:
    这里写图片描述
    上图代码在浏览器ES6环境中,会报错。其实际运行的是下面的代码:
    这里写图片描述
    注意:避免在块级作用域内声明函数,若需要,可以写成函数表达式的形式

顶层对象模型

  1. 顶层对象概念:
    浏览器中指window对象
    node环境中指global对象
    在ES5,顶层对象的属性与全局变量是等价
    这里写图片描述
*浏览器中,顶层对象是window,但Node和Web Worker是没有window的 *浏览器和Web Worker里面,self也指向顶层对象,但是Node没有self *Node里面,顶层对象是global,但其他环境都不支持 同一段代码为了可以在各种环境都能取到顶层对象,目前一般使用this变量,但是具有局限性 *全局环境中,this会返回顶层对象,但是在Node模块和ES6模块中,this返回的是当前模块 *函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象,但是严格模式下,this此时返回的是undefined *无论是严格模式还是普通模式,new Function(‘return this’)(),总是会返回全局对象。但是如果浏览器使用CSP(Content Security Policy,内容安全策略),那么evalnew Function这些方法都可能无法使用 勉强可以使用下图中的方式,在所有情况下,都取到顶层对象:
这里写图片描述
11. 全局变量与顶层对象等价引发的问题
* 没有办法在编译时报出未声明的错误,只有运行时才知道是否未声明。
(全局变量可能是由顶层对象的属性创造的,而属性的创造是动态的)
* 在不知觉中我们可能就创建了全局变量
* 顶层对象的属性可以到处读写,不利于模块化编程
window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,是不合适的
12. ES6针对这一现象所做的改变
*保持兼容性:var和function命令声明的全局变量依旧是顶层对象的属性
*let、const、class所声明的全局变量,不属于顶层对象的属性。也就是说,ES6开始,全局变量将逐步与顶层对象的属性脱钩
例如:
这里写图片描述

global对象

  • 目前有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。
  • 垫片库system.global模拟了这个提案,可以在所有环境拿到global
    这里写图片描述