ES6~ES13新特性(一)

1 ECMA新描述概念

2 let、const的使用

3 let、const和var区别

4 块级作用域的使用

5 模板字符串的详解

6 ES6函数的增强用法

一个执行上下文关联两个环境。词法环境和变量环境。

词法环境是由let和const创建;变量环境是由var创建的。

let-const的基本使用、不能重复声明变量

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // ES6之前
    var message1 = "Hello World"
    message1 = "Hello Coderwhy"
    message1 = "aaaaa"
    console.log(message1)

    // ES6开始
    // 1.let
    let message2 = "你好, 世界"
    message2 = "你好, why"
    message2 = 123
    console.log(message2)

    // 2.const
    // const message3 = "nihao, shijie"
    // message3 = "nihao, why"

    // 赋值引用类型
    const info = {
      name: "why",
      age: 18
    }
    // info = {}
    info.name = "kobe"
    console.log(info)




     // 1.var变量可以重复声明
    // var message = "Hello World"
    // var message = "你好, 世界"


    // 2.let/const不允许变量的重复声明
    // var address = ""
    let address = "广州市"
    // let address = "上海市"
    const info = {}
    // const info = {}


  </script>

</body>
</html>

let-const的作用域提升

 // 1.var声明的变量会进行作用域的提升
    // console.log(message)
    // var message = "Hello World"

    // 2.let/const声明的变量: 没有作用域提升
    // console.log(address)
    console.log(address)
    let address = "广州市"
    const info = {}

let-const的暂时性死区

 // 1.暂时性死区
    // function foo() {
    //   console.log(bar, baz)

    //   console.log("Hello World")
    //   console.log("你好 世界")
    
    // 暂时性死区是let声明变量之前的范围。
    //   let bar = "bar"
    //   let baz = "baz"
    // }
    // foo()

    // 2.暂时性死区和定义的位置没有关系, 和代码执行的顺序有关系
    // function foo() {
    //   console.log(message)
    // }

    // let message = "Hello World"
    // foo()
    // console.log(message)

    // 3.暂时性死区形成之后, 在该区域内这个标识符不能访问
    let message = "Hello World"
    function foo() {
      // 这里因为函数体里面有message,打印的地方又在message之前,会报错。
      // 如果函数里面没有message,那就会去找函数外面的message。
      console.log(message)  

      const message = "哈哈哈哈"
    }

    foo()

1

let-const不添加window

 // 1.var定义的变量是会默认添加到window上的
    // var message = "Hello World"
    // var address = "广州市"

    // console.log(window.message)
    // console.log(window.address)

    // 2.let/const定义的变量不会添加到window上的
    // let message = "Hello World"
    // let address = "广州市"
    
    // console.log(window.message)
    // console.log(window.address)

    // 3.let/var分别声明变量
    var message = "Hello World"
    let adress = "广州市"

    function foo() {
      debugger
    }
    foo()

let-const的块级作用域

  // 1.在ES5以及之前, 只有全局和函数会形成自己的作用域
    // 代码块
    // function foo() {
    //   console.log("Hello World")
    // }
    // 下面这个是没有作用域的,包括if(){}也是没有自己的作用域。所以在{}外面可以拿到里面的参数值
    // {
    //   var message = "Hello World"
    // }
    // console.log(message)


    // 2.从ES6开始, 使用let/const/function/class声明的变量是有块级作用域
    
    // console.log(message)
    // foo()
    {
      var message = "Hello World"
      let age = 18
      const height = 1.88

      class Person {}

      function foo() {
        console.log("foo function")
      }
    }

    // console.log(age)
    // console.log(height)
    // const p = new Person()
    foo()

let-const块级作用域应用

 一旦块级作用域里面定义的let变量执行结束后就会销毁掉

 上图块级作用域里面的height还能查找到,但是title和info不能查找到了。

下图这里为什么${i}只会返回4?  是因为for这里没有作用域,${i}在function里面查找不到,会去上级作用域查找,这里上级作用域是window,在这里查找到的i是在for循环结束之后的,值已经是4了。

 上图解决办法:

1、

2、利用立即执行函数

3、let变量,通过词法环境会放到环境记录了吗保存每次i的值。

 // 1.形成的词法环境
    // var message = "Hello World"
    // var age = 18
    // function foo() {}
    // let address = "广州市"

    // {
    //   var height = 1.88

    //   let title = "教师"
    //   let info = "了解真相~"
    // }

    // 2.监听按钮的点击
    const btnEls = document.querySelectorAll("button")
    // [btn1, btn2, btn3, btn4]
    // for (var i = 0; i < btnEls.length; i++) {
    //   var btnEl = btnEls[i];
    //   // btnEl.index = i
    //   (function(m) {
    //     btnEl.onclick = function() {
    //       debugger
    //       console.log(`点击了${m}按钮`)
    //     }
    //   })(i)
    // }

    
    for (let i = 0; i < btnEls.length; i++) {
      const btnEl = btnEls[i];
      btnEl.onclick = function() {
        console.log(`点击了${i}按钮`)
      }
    }

    // console.log(i)

1

模板字符串的详细使用

 // 1.基本用法
    // 1.1.ES6之前
    // const info = "my name is" + name + ", age is " + age

    // 1.2.ES6之后
    const info = `my name is ${name}, age is ${age}`
    console.log(info)


    // 2.标签模板字符串的用法
    function foo(...args) {
      console.log("参数:", args)
    }

    // foo("why", 18, 1.88)
    foo`my name is ${name}, age is ${age}, height is ${1.88}`

函数增强-默认参数用法

  // 注意: 默认参数是不会对null进行处理的
    function foo(arg1 = "我是默认值", arg2 = "我也是默认值") {
      // 1.两种写法不严谨
      // 默认值写法一:
      // arg1 = arg1 ? arg1: "我是默认值"

      // 默认值写法二:
      // arg1 = arg1 || "我是默认值"

      // 2.严谨的写法
      // 三元运算符
      // arg1 = (arg1 === undefined || arg1 === null) ? "我是默认值": arg1
      
      // ES6之后新增语法: ??
      // arg1 = arg1 ?? "我是默认值"

      // 3.简便的写法: 默认参数
      console.log(arg1)
    }

    foo(123, 321)
    foo()
    foo(0)
    foo("")
    foo(false)
    foo(null)
    foo(undefined)

函数增强-默认参数注意

   // 1.注意一: 有默认参数的形参尽量写到后面
    // 2.有默认参数的形参, 是不会计算在length之内(并且后面所有的参数都不会计算在length之内)
    // 3.剩余参数也是放到后面(默认参数放到剩余参数的前面)
    function foo(age, name = "why", ...args) {
      console.log(name, age, args)
    }

    foo(18, "abc", "cba", "nba")

    console.log(foo.length)

函数增强-默认参数解构

 // 1.解构的回顾
    // const obj = { name: "why" }
    // const { name = "kobe", age = 18 } = obj

    // 2.函数的默认值是一个对象
    // function foo(obj = { name: "why", age: 18 }) {
    //   console.log(obj.name, obj.age)
    // }

    function foo({ name, age } = { name: "why", age: 18 }) {
      console.log(name, age)
    }

    function foo({ name = "why", age = 18 } = {}) {
      console.log(name, age)
    }

    foo()

函数增强-箭头函数补充

  // 1.function定义的函数是有两个原型的:
    // function foo() {}
    // console.log(foo.prototype) // new foo() -> f.__proto__ = foo.prototype
    // console.log(foo.__proto__) // -> Function.prototype

    // 2.箭头函数是没有显式原型
    // 在ES6之后, 定义一个类要使用class定义
    var bar = () => {}
    // console.log(bar.__proto__ === Function.prototype)
    // 没有显式原型
    // console.log(bar.prototype)
    // var b = new bar()

展开语法-展开基本使用

注意区分什么是剩余参数,什么是展开运算符

 // 1.基本演练
    // ES6
    const names = ["abc", "cba", "nba", "mba"]
    const str = "Hello"

    // const newNames = [...names, "aaa", "bbb"]
    // console.log(newNames)

    function foo(name1, name2, ...args) {
      console.log(name1, name2, args)
    }

    foo(...names)
    foo(...str)

    // ES9(ES2018)
    const obj = {
      name: "why",
      age: 18
    }
    // 不可以这样来使用
    // foo(...obj) // 在函数的调用时, 用展开运算符, 将对应的展开数据, 进行迭代
    // 可迭代对象: 数组/string/arguments

    const info = {
      ...obj,
      height: 1.88,
      address: "广州市"
    }
    console.log(info)

引用赋值-浅拷贝-深拷贝

浅拷贝的意思就是只拷贝一份新的,包含第一层的参数,第二层开始的参数就没有创建新的。通过下图可以看得出来。

深拷贝顾名思义就是对象里面的对象也一样创建一份新的出来,两个对象内容一样,但是修改其中一个对象的值不会影响另外一个的参数。

 const obj = {
      name: "why",
      age: 18,
      height: 1.88,
      friend: {
        name: "curry"
      }
    }

    // 1.引用赋值
    // const info1 = obj

    
    // 2.浅拷贝
    // const info2 = {
    //   ...obj
    // }
    // info2.name = "kobe"
    // console.log(obj.name)
    // console.log(info2.name)
    // info2.friend.name = "james"
    // console.log(obj.friend.name)


    // 3.深拷贝
    // 方式一: 第三方库
    // 方式二: 自己实现
    // function deepCopy(obj) {}
    // 方式三: 利用先有的js机制, 实现深拷贝JSON
    const info3 = JSON.parse(JSON.stringify(obj))
    console.log(info3.friend.name)
    info3.friend.name = "james"
    console.log("info3.friend.name:", info3.friend.name)
    console.log(obj.friend.name)

数字表示-进制和长数字

// 1.进制
    console.log(100)
    console.log(0b100)
    console.log(0o100)
    console.log(0x100)

    // 2.长数字的表示
    const money = 100_00_00_0000_00_00

Symbol-基本使用过程

 // ES6之前存在的问题
    // const obj = {
    //   name: "why",
    //   fn: "aaa"
    // }

    // // 添加一个新的属性 name
    // function foo(obj) {
    //   obj.why = function() {}
    // }
    // foo(obj)
    // console.log(obj.fn)


    // ES6之后可以使用Symbol生成一个独一无二的值
    const s1 = Symbol()
    // const info = { name: "why" }
    const obj = {
      [s1]: "aaa" 
    }
    console.log(obj)

    const s2 = Symbol()
    obj[s2] = "bbb"
    console.log(obj)

    function foo(obj) {
      const sKey = Symbol()
      obj[sKey] = function() {}
      delete obj[sKey]
    }

    foo(obj)

Symbol-额外知识补充

 const s1 = Symbol() // aaa
    const s2 = Symbol() // bbb

    // 1.加入对象中
    const obj = {
      name: "why",
      age: 18,
      [s1]: "aaa",
      [s2]: "bbb"
    }

    // const obj1 = {}
    // obj1[s1] = "aaa"
    // obj2[s2] = "bbb"

    // const obj2 = {}
    // Object.defineProperty(obj, s1, {
    //   value: "aaa"
    // })

    // 2.获取symbol对应的key和对应的值
    console.log(Object.keys(obj))
    console.log(Object.getOwnPropertySymbols(obj))
    const symbolKeys = Object.getOwnPropertySymbols(obj)
    for (const key of symbolKeys) {
      console.log(obj[key])
    }

    // 3.description
    // 3.1.Symbol函数直接生成的值, 都是独一无二
    const s3 = Symbol("ccc")
    console.log(s3.description)
    const s4 = Symbol(s3.description)
    console.log(s3 === s4)

    // 3.2. 如果相同的key, 通过Symbol.for可以生成相同的Symbol值
    const s5 = Symbol.for("ddd")
    const s6 = Symbol.for("ddd")
    console.log(s5 === s6)

    // 获取传入的key
    console.log(Symbol.keyFor(s5))

Set-Map-Set的基本使用---就是集合

set可以用在数组去重上面。

 // 1.创建Set
    const set = new Set()
    console.log(set)

    // 2.添加元素
    set.add(10)
    set.add(22)
    set.add(35)
    set.add(22)
    console.log(set)

    const info = {}
    const obj = {name: "obj"}
    set.add(info)
    set.add(obj)
    set.add(obj)
    console.log(set)

    // 3.应用场景: 数组的去重
    const names = ["abc", "cba", "nba", "cba", "nba"]
    // const newNames = []
    // for (const item of names) {
    //   if (!newNames.includes(item)) {
    //     newNames.push(item)
    //   }
    // }
    // console.log(newNames)
    const newNamesSet = new Set(names)
    //  转成数组形式
    const newNames = Array.from(newNamesSet)
    console.log(newNames)

    // 4.Set的其他属性和方法
    // 属性
    console.log(set.size)
    // 方法
    // 4.1. add方法
    set.add(100)
    console.log(set)
    // 4.2. delete方法
    set.delete(obj)
    console.log(set)
    // 4.3. has方法
    console.log(set.has(info))
    // 4.4. clear方法
    // set.clear()
    // console.log(set)
    // 4.5. forEach
    set.forEach(item => console.log(item))

    // 5.set支持for...of
    for (const item of set) {
      console.log(item)
    }

Set-Map-WeakSet的使用

由于数组里面有对三个对象的引用,所以垃圾回收不会因为三个对象赋值null而清除掉。通过weakset可以解决上面的问题。但是weakset不能枚举遍历。单纯set找不到。

  // 1.Weak Reference(弱引用)和Strong Reference(强引用)
    let obj1 = { name: "why" }
    let obj2 = { name: "kobe" }
    let obj3 = { name: "jame" }

    // let arr = [obj1, obj2, obj3]
    // obj1 = null
    // obj2 = null
    // obj3 = null

    // const set = new Set(arr)
    // arr = null

    // 2.WeakSet的用法
    // 2.1.和Set的区别一: 只能存放对象类型
    const weakSet = new WeakSet()
    weakSet.add(obj1)
    weakSet.add(obj2)
    weakSet.add(obj3)

    // 2.2.和Set的区别二: 对对象的引用都是弱引用


    // 3.WeakSet的应用
    const pWeakSet = new WeakSet()
    class Person {
      constructor() {
        pWeakSet.add(this)
      }

      running() {
        if (!pWeakSet.has(this)) {
          console.log("Type error: 调用的方式不对")
          return
        }
        console.log("running~")
      }
    }

    let p = new Person()
    // p = null
    p.running()
    const runFn = p.running
    runFn()
    const obj = { run: runFn }
    obj.run()

 Map的基本使用

  const info = { name: "why" }
    const info2 = { age: 18 }

    // 1.对象类型的局限性: 不可以使用复杂类型作为key
    // const obj = {
    //   address: "北京市",
    //   [info]: "哈哈哈",
    //   [info2]: "呵呵呵"
    // }
    // console.log(obj)

    // 2.Map映射类型
    const map = new Map()
    map.set(info, "aaaa")
    map.set(info2, "bbbb")
    console.log(map)

    // 3.Map的常见属性和方法
    // console.log(map.size)
    // 3.1. set方法, 设置内容
    map.set(info, "cccc")
    console.log(map)
    // 3.2. get方法, 获取内容
    // console.log(map.get(info))
    // 3.3. delete方法, 删除内容
    // map.delete(info)
    // console.log(map)
    // 3.4. has方法, 判断内容
    // console.log(map.has(info2))
    // 3.5. clear方法, 清空内容
    // map.clear()
    // console.log(map)
    // 3.6. forEach方法
    // map.forEach(item => console.log(item))

    // 4.for...of遍历
    for (const item of map) {
      const [key, value] = item
      console.log(key, value)
    }

WeakMap的使用

 let obj1 = { name: "why" }
    let obj2 = { name: "kobe" }

    // 1.WeakMap的基本使用
    const weakMap = new WeakMap()
    // weakMap.set(123, "aaa")
    weakMap.set(obj1, "aaa")
    weakMap.set(obj2, "bbb")

    obj1 = null
    obj2 = null

猜你喜欢

转载自blog.csdn.net/weixin_56663198/article/details/131667342