ES6-ES11新语法之ES6上篇

let:

  let声明变量的特点,和var有什么不同:

    1、变量不能重复声明

    2、块级作用域

    3、不存在变量提升

    4、不影响作用域链,同一个块级作用域下,声明在函数前的变量可以被函数访问到

  let小案例:

const:

  const的特点:

    1、一定要赋初始值

    2、一般常量使用大写(不是必须)

    3、常量的值不能修改

    4、块级作用域

    5、对于数组和对象的元素的修改,地址没有改变,不会报错。const定义的变量引用不能修改,值可以修改   const和Object.freeze()搭配使用

解构赋值:

    const arr = [100, 200, 300, 400]
    let [a, b, c, d] = arr
    console.log(a, b, c, d) // 100 200 300 400

    const obj = {
      name: '孙艺珍',
      age: 20,
      doo: function () {
        console.log('演电影')
      }
    }
    let { name, age, doo } = obj
    console.log(name)
    console.log(age)
    console.log(doo)
    doo()

  对象中的方法频繁调用想到可以使用结构赋值拿出该方法,调用就不用写对象名了

模板字符串:

  1、可以直接出现换行符,es5的字符串要用+拼接

  2、变量拼接

    let str = `模板字符串`
    console.log(str)

    let num = 100
    console.log(`我今年${num}岁了`)

    let mo = `
      <ul>
        <li>100</li>
        <li>100</li>
        <li>100</li>
        <li>100</li>
        <li>100</li>
      </ul>
    `
    console.log(mo)
    document.write(mo)

对象简化写法:

    let name = `"'syz'"`
    let doo = function () {
      console.log('doo')
    }
    let person = {
      name, // name: name
      doo, // doo: doo
      improve() { // 省略function关键字
        console.log('让你变漂亮')
      }
    }
    console.log(person)
    person.doo()
    person.improve()

箭头函数:

  1、this是静态的,始终指向函数声明时所在作用域下的this值

  2、不能作为构造函数实例化对象

  3、不能使用arguments变量

  4、简写    1)省略小括号:有且只有一个形参时    2)省略花括号:代码体有且只有一条语句时,此时语句的执行结果就是函数的返回值,return也必须要省略

    function fn() {
      console.log(this.name)
    }

    // 1、this是静态的,this始终指向函数声明时所在作用域下的this的值
    let fn1 = () => {
      console.log(this.name)
    }

    window.name = '孙艺珍'

    fn() // 孙艺珍
    fn1() // 孙艺珍

    let person = {
      name: '吴小明'
    }

    fn.call(person) // 吴小明
    fn1.call(person) // 孙艺珍 this始终指向函数声明时所在作用域下的this的值

    // 2、不能作为构造函数实例化对象
    let Person = (name, age) => {
      this.name = name
      this.age = age
    }

    // let p = new Person('xx', 20) // Uncaught TypeError: Person is not a constructor

    // 3、不能使用arguments变量
    function xx() {
      console.log(arguments)
    }
    xx(1, 2, 3) // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]

    let yy = () => {
      console.log(arguments)
    }

    // yy(1, 2, 3) // Uncaught ReferenceError: arguments is not defined

    // 4、简写       省略小括号:有且只有一个形参时可以省略      省略花括号:当代码体有且只有一条语句时可以省略,此时语句执行的结果就是函数的返回值,return语句也必须要省略
    let add = n => {
      return n + n
    }
    console.log(add(4)) // 8
    let add1 = n => n + n
    console.log(add1(5)) // 10

  使用场景:

    1、this指向上一级的this,函数嵌套时,里层函数中使用外层函数的this,此时可以使用箭头函数。如果使用es5的函数,第一种方法是在里层函数的上方定义变量 let _this = this 保存外层函数的this;第二种方法是调用时利用call()或apply(),如:xxx.call(this)

    2、数组的方法回调中使用箭头函数

    // 返回数组中偶数项
    let arr = [1, 2, 3, 4, 5, 6]

    const even = arr.filter(function (item) {
      return item % 2 === 0
    })

    console.log(even)

    const even1 = arr.filter(item => item % 2 === 0)

    console.log(even1)

  总结:

    1、箭头函数适合与this无关的回调,定时器,数组的方法回调

    2、箭头函数不适合与this有关的回调,事件回调,对象的方法

参数默认值:

  1、形参初始值:具有默认值的参数----一般有初始值的参数位置放在后面,如果将参数c的位置放在前面或中间此时的值是NaN,因为b的值是undefined

    function add(a, b, c = 10) {
      return a + b + c
    }

    console.log(add(1, 2))

  2、和解构赋值结合

    function connect({ host = '127.0.0.1', username, password, port }) {
      console.log(host)
      console.log(username)
      console.log(password)
      console.log(port)
    }

    connect({
      host: 'baidu.com',
      username: 'root',
      password: 'root1',
      port: 3000
    })

rest参数:

    // ES5获取实参的方式:arguments
    function fn() {
      console.log(arguments)
    }

    fn(100, '200', true) // Arguments(3) [100, "200", true, callee: ƒ, Symbol(Symbol.iterator): ƒ]

    // ES6引入 rest 参数,用于获取实参,代替arguments
    function fn1(...rest) {
      console.log(rest)
    }

    fn1(100, '200', true) // [100, "200", true]

    // rest 参数必须放到参数最后
    function fn2(a, b, ...rest) {
      console.log(a, b, rest)
    }

    fn2(100, '200', true, {}) // 100 "200" (2) [true, {…}]

注意:arguments是一个类数组,rest是一个数组

扩展运算符:

    const arr=['孙艺珍','吴小明','郭德纲']

    function fn(...rest){
      console.log(rest)
    }
    // 扩展运算符能将数组转换为逗号分隔的参数序列
    // fn(...arr) // ["孙艺珍", "吴小明", "郭德纲"]
    fn('孙艺珍','吴小明','郭德纲') // ["孙艺珍", "吴小明", "郭德纲"]

...的使用:

    // 数组的合并
    const arr = ['唐僧', '八戒']
    const arr1 = ['沙悟净', '悟空']

    const newArr = arr.concat(arr1) // ["唐僧", "八戒", "沙悟净", "悟空"]
    const newArr1 = [...arr, ...arr1] // ["唐僧", "八戒", "沙悟净", "悟空"]

    console.log(newArr)
    console.log(newArr1)

    // 数组的拷贝(浅拷贝)
    const copyArr = [...arr]
    console.log(copyArr) // ["唐僧", "八戒"]

    // 将伪数组转为真正的数组
    const divs = document.querySelectorAll('div')
    const divArr = [...divs]
    console.log(divs) // NodeList(3) [div, div, div]
    console.log(divArr) // [div, div, div]

Symbol:

    /*
      Symbol:
        ES6新引入的简单数据类型,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
      
      Symbol特点:
        1、Symbol的值是唯一的,用来解决命名冲突的问题
        2、Symbol值不能与其他数据进行运算
        3、Symbol定义的对象属性不能使用 for...in 循环病遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名
    
    */

    // 创建Symbol
    let s1 = Symbol()
    console.log(s1, typeof s1) // Symbol() "symbol"

    let s2 = Symbol('孙艺珍')
    let s3 = Symbol('孙艺珍')

    console.log(s2) // Symbol(孙艺珍)
    console.log(s3) // Symbol(孙艺珍)
    console.log(s2 == s3) // false

    // Symbol.for() 创建
    let s4 = Symbol.for('小明')
    let s5 = Symbol.for('小明')

    console.log(s4) // Symbol(小明)
    console.log(s5) // Symbol(小明)
    console.log(s4 === s5) // true

Symbol给对象中添加属性和方法的两种方式:

    // 1、利用Symbol给对象中添加方法
    let game = {
      name: '俄罗斯方块',
      up: function () { console.log('我是up') },
      down: function () { console.log('我是down') }
    }

    let methods = {
      up: Symbol(),
      down: Symbol()
    }
    // 如果直接写 game.up=function(){} 可能会替换掉 game 中原有的方法 
    game[methods.up] = function () { console.log('upupupupup') }
    game[methods.down] = function () { console.log('downdown') }

    console.log(game)

    game.up()

    // 2、Symbol() 不能直接作为键使用,可以写成 [Symbol('xxx')]
    let youxi = {
      name: '狼人杀',
      [Symbol('say')]: function () { console.log('我可以说话') },
      [Symbol('zibao')]: function () { console.log('我可以自爆') }
    }
    console.log(youxi)

Symbol内置值:

Symbol.hasInstance 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable 对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
Symbol.species 创建衍生对象时,会使用该属性
Symbol.match 当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值
Symbol.replace 当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值
Symbol.search 当该对象被str.search(myObject)方法调用时,会返回该方法的返回值
Symbol.split 当该对象被str.split(myObject)方法调用时,会返回该方法的返回值
Symbol.iterator 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
Symbol. toStringTag 在该对象上面调用toString方法时,返回该方法的返回值
Symbol. unscopables 该对象指定了使用with关键字时,哪些属性会被with环境排除
    // Symbol.hasInstance
    class Person {
      static [Symbol.hasInstance](param) {
        console.log(param) // {name: "111"}
        console.log('我被用来检测数据类型了')
        return true
      }
    }

    let obj = { name: '111' }
    let result = obj instanceof Person // true

    console.log(result)

    // Symbol.isConcatSpreadable
    let arr = [1, 2, 3]
    let arr1 = [4, 5, 6]
    arr1[Symbol.isConcatSpreadable] = false // 设置不可以展开
    let newArr = arr.concat(arr1)
    console.log(newArr) // [1, 2, 3, Array(3)]
    console.log(newArr[3]) // [4, 5, 6, Symbol(Symbol.isConcatSpreadable): false]

注意:遇到唯一性的场景时要想到Symbol

迭代器:

  遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据只要部署 Iterator 接口(对象中的一个属性),就可以完成遍历操作。

  原生具备 Iterator 接口的数据(可用for...of遍历):Array、Arguments、Set、Map、String、TypedArray、NodeList

  工作原理:

    1、创建一个指针对象,指向当前数据结构的起始位置

    2、第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员

    3、接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员

    4、每调用 next 方法返回一个包含 value 和 done 属性的对象

    // for...of 遍历值,for...in 遍历键
    let str = '123456789'

    for (item of str) {
      console.log(item)
    }

    let arr = [1, 2, 3, 4, 5]
    for (item of arr) {
      console.log(item)
    }

    let iterator = arr[Symbol.iterator]()

    console.log(iterator)
    console.log(iterator.next()) // {value: 1, done: false}
    console.log(iterator.next()) // {value: 2, done: false}
    console.log(iterator.next()) // {value: 3, done: false}
    console.log(iterator.next()) // {value: 4, done: false}
    console.log(iterator.next()) // {value: 5, done: false}
    console.log(iterator.next()) // {value: undefined, done: true}

自定义遍历数据:

    const banji = {
      name: '重点班',
      students: ['小明', '小红', '小芳', '小华'],
      // 自定义iterator接口函数
      [Symbol.iterator]() {
        let index = 0
        let _this = this
        return {
          next: function () {
            if (index < _this.students.length) {
              const result = { value: _this.students[index], done: false }
              index++
              return result
            } else {
              return { value: undefined, done: true }
            }
          }
        }
      }
    }
    for (let item of banji) {
      console.log(item)
    }

注意:需要自定义遍历数据的时候,要想到迭代器

生成器:

  生成器函数是ES6提供的一种异步编程方案,语法行为与传统函数完全不同

  特点:

    1、* 的位置没有限制

    2、生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值

    3、yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码

    4、next 方法可以传递实参,作为 yield 语句的返回值

    function * fn() {
      console.log(111)
      yield '你好呀'
      console.log(222)
      yield '我是安徽人'
      console.log(333)
      yield '你是哪里人'
      console.log(444)
    }

    let iterator = fn() // 生成迭代器对象
    console.log(iterator.next()) // {value: "你好呀", done: false}
    console.log(iterator.next()) // {value: "我是安徽人", done: false}
    console.log(iterator.next()) // {value: "你是哪里人", done: false}
    console.log(iterator.next()) // {value: undefined, done: true}

    // 遍历
    for(let item of fn()){
      console.log(item) // 返回结果为 yield 表达式后的内容
    }

生成器函数参数:

    function* gen(arg) {
      console.log(arg) // AAA
      let one = yield 111
      console.log(one) // BBB 调用 next() 时传入的参数作为 yield 语句的返回值----第二次调用 next() 传入的参数作为第一个 yield 语句的返回值
      let two = yield 222
      console.log(two) // CCC
      let three = yield 333
      console.log(three) // DDD
      let four = yield 444
      console.log(four) // undefined
    }
    let iterator = gen('AAA') // 获取迭代器对象
    console.log(iterator.next()) // {value: 111, done: false}
    console.log(iterator.next('BBB')) // {value: 222, done: false}
    console.log(iterator.next("CCC")) // {value: 333, done: false}
    console.log(iterator.next('DDD')) // {value: 444, done: false}
    console.log(iterator.next()) // {value: undefined, done: true}

小案例:

  1、异步编程:1秒后输出111,2秒后输出222,3秒后输出333

    // 第一种:回调地狱问题
    setTimeout(() => {
      console.log(111)
      setTimeout(() => {
        console.log(222)
        setTimeout(() => {
          console.log(333)
        }, 3000);
      }, 2000);
    }, 1000);

    // 第二种:利用生成器函数,获取迭代器对象,通过调用迭代器的 next() 方法一步步执行one two three
    function one() {
      setTimeout(() => {
        console.log(111)
        iterator.next()
      }, 1000);
    }

    function two() {
      setTimeout(() => {
        console.log(222)
        iterator.next()
      }, 2000);
    }

    function three() {
      setTimeout(() => {
        console.log(333)
        iterator.next()
      }, 3000);
    }

    function* gen() {
      yield one()
      yield two()
      yield three()
    }
    let iterator = gen() // 调用生成器函数,获取迭代器对象
    iterator.next()

  2、场景:请求接口当前接口需要依赖于上一次请求返回的数据,生成器函数是异步的,此处可以替代回调函数,解决回调地狱问题

    // 先拿到用户数据,再拿到订单数据,再拿到商品数据
    function getUsers() {
      setTimeout(() => {
        let data = '用户数据'
        iterator.next(data)
      }, 1000);
    }
    function getOrders() {
      setTimeout(() => {
        let data = '订单数据'
        iterator.next(data)
      }, 1000);
    }
    function getGoods() {
      setTimeout(() => {
        let data = '商品数据'
        iterator.next(data)
      }, 1000);
    }

    function* gen() {
      let users = yield getUsers()
      console.log(users)
      let orders = yield getOrders()
      console.log(orders)
      let goods = yield getGoods()
      console.log(goods)
    }

    let iterator = gen()
    iterator.next()

Promise:

  Promise是ES6引入的异步编程的新解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

Promise基本语法:

    const p = new Promise(function (resolve, reject) {
      setTimeout(() => {
        let data = '数据'
        // resolve(data)
        reject('失败')
      }, 100);
    })

    p.then(function (value) {
      console.log(value)
    }).catch(function (err) {
      console.log(err)
    })

Promise封装读取文件:

const fs = require('fs')

// 1、直接读取
// fs.readFile('./resources/插秧诗.md', (err, data) => {
//   if (err) throw err
//   console.log(data.toString())
// })

// 2、使用Promise封装
const p = new Promise(function (resolve, reject) {
  fs.readFile('./resources/为学.md', (err, data) => {
    if (err) reject(err)
    resolve(data)
  })
})

p.then(function (value) {
  console.log(value.toString())
}).catch(function (err) {
  console.log(err)
})

Promise封装ajax:

    // 1、原生ajax
    const xhr = new XMLHttpRequest()
    xhr.addEventListener('load', loadHandler) // Firefox 支持 load 事件
    xhr.open('get', 'https://api.apiopen.top/getJoke')
    xhr.send()
    function loadHandler() {
      if (xhr.readyState === 4 && xhr.status === 200) {
        // console.log(xhr.response)
      } else {
        console.error(xhr.status)
      }
    }

    // 2、Promise封装
    const p = new Promise(function (resolve, reject) {
      const xhr1 = new XMLHttpRequest()
      xhr1.addEventListener('load', loadHandler1)
      xhr1.open('get', 'https://api.apiopen.top/getJoke')
      xhr1.send()
      function loadHandler1() {
        if (xhr1.readyState === 4 && xhr1.status === 200) {
          resolve(xhr1.response)
        } else {
          reject(xhr1.status)
        }
      }
    })

    p.then(function (value) {
      console.log(value)
    }).catch(function (err) {
      console.error(err)
    })

Promise读取多个文件,避免回调地狱:

const fs = require('fs')

// 1、使用回调,会有回调地狱问题
// fs.readFile('./resources/为学.md', (err, data) => {
//   fs.readFile('./resources/插秧诗.md', (err, data1) => {
//     fs.readFile('./resources/观书有感.md', (err, data2) => {
//       const result = data + '
' + data1 + '
' + data2
//       console.log(result)
//     })
//   })
// })

// 2、使用 Promise 实现
const p = new Promise((resolve, reject) => {
  fs.readFile('./resources/为学.md', (err, data) => {
    resolve(data)
  })
})

p.then((value) => {
  return new Promise((resolve, reject) => {
    fs.readFile('./resources/插秧诗.md', (err, data) => {
      resolve([value, data])
    })
  })
})
  .then((value) => {
    return new Promise((resolve, reject) => {
      fs.readFile('./resources/观书有感.md', (err, data) => {
        value.push(data)
        resolve(value)
      })
    })
  })
  .then((value) => {
    console.log(value.join('
'))
  })

  

x

原文地址:https://www.cnblogs.com/wuqilang/p/14046608.html