es6基础(二)

ES6全称ECMAScript 6.0,是JavaScript的下一个版本标准,2015.06 发版。ES6 主要是为了解决 ES5 的先天不足,比如 JavaScript 里并没有类的概念。es6新特性:Symbolclass数值的扩展字符串的扩展数组的扩展对象的扩展

Symbol数据类型

  • Symbol表示独一无二的值,它是js中的第七种数据类型.

    • 基本的数据类型: null undefined number boolean string symbol bigInt
    • 引用数据类型 object
      1
      2
      3
      4
      5
      6
      7
      let s1 = Symbol('tew')
      let s2 = Symbol('tew')
      console.log(s1) // Symbol(tew)
      console.log(s2) // Symbol(tew)
      console.log(typeof s1) // symbol
      console.log(s1==s2) // false
      console.log(s1===s2) // false
  • Symbol使用注意事项

    • Symbol函数不能使用new否则会报错, 它是原始数据类型不是对象

      1
      let s3 = new Symbol('tew') // Symbol is not a constructor
    • Symbol函数接收一个字符串作为参数,表示对Symbol的描述和区分,主要是为了在控制台显示,或者转为字符串的时候,比较容易区分. 字符串只是描述,不代表其他.

    • Symbol不能隐式转换,但可以显示转换为字符串或者布尔值,转换为Number的话会报错。

      1
      2
      3
      4
      console.log(String(Symbol('tew'))) // Symbol(tew) string
      console.log(Symbol('tew').toString()) // Symbol(tew) string
      console.log(!Symbol('tew')) // false
      console.log(Number(Symbol('tew'))) // Cannot convert a Symbol value to a number
    • Symbol不能与其他值做任何运算,会报错

      1
      console.log(Symbol('tew')+'1') // Cannot convert a Symbol value to a string
    • Symbol作为对象的属性名使用时,属性不会出现在for in/of中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回,不能使用点运算符

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      let yyy = Symbol('ss')
      // 不能写成 {yyy: 'hello'} 需要加 []
      const obj = {[yyy]: 'hello', a:2}
      console.log(obj) // {a: 2, Symbol(ss): "hello"}
      console.log(obj[yyy]) // hello
      console.log(obj.yyy) // undefined
      for (const i in obj) {
      console.log(i) // a 未出现 Symbol(ss): "hello"
      }
      console.log(Object.keys(obj)) // ["a"]
      console.log(JSON.stringify(obj)) // {"a":2}
    • 在直接使用symbol作为属性名的时候,只能使用通过obj[Object.getOwnPropertySymbols(obj)[0]]

      1
      2
      3
      4
      5
      6
      7
      8
      9
      const obj = {
      [Symbol()]: 123,
      a: 22
      }
      console.log(obj) // {a: 22, Symbol(): 123}
      console.log(obj[Symbol()]) // undefined
      console.log(Object.getOwnPropertySymbols(obj)) // [Symbol()]
      console.log(Object.getOwnPropertySymbols(obj)[0]) // Symbol()
      console.log(obj[Object.getOwnPropertySymbols(obj)[0]]) // 123

Class类

传统方法是通过构造函数,定义并生成新对象,是一种基于原型的面向对象系统Es6中可以使用class声明一个类,之后以这个类来实例化对象

  • es5传统方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const Tew = function(a, b) {
    this.a = a
    this.b = b
    }
    Tew.prototype = {
    constructor: Tew,
    print: function(){
    console.log(this.a + ' ' + this.b)
    }
    }
    const tew = new Tew('hello', 'world').print() // hello world
  • es6方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Tew{
    constructor(a,b){
    this.a = a
    this.b = b
    }
    print(){
    console.log(this.a +' ' + this.b)
    }
    }
    new Tew('hello', 'world').print() // hello world
  • class使用注意事项

    • Tew中的constructor方法是构造函数,this关键字则代表实例对象,也就是说,es5中的构造函数Tew,对应Es6的Tew这个类的构造方法,主要用于初始化对象的属性
    • 定义类的方法的时候,前面不需要加上function关键字,方法之间不需要逗号分隔,加了会报错
    • 构造函数的prototype属性,在es6的类上继续存在,而且类的所有方法都定义在类的prototype属性上面
    • 定义在类中的方法都是不可以被枚举的
    • constructor方法是类的默认方法.通过new命令生成对象实例时,自动调用该方法.一个类必须有constructor方法,如没有显示定义,会默认添加一个空的contructor方法
    • 用new实例化对象,如忘记使用new,将会报错
  • es6 class类的继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Humen{
    constructor(){
    this.eyes = 2
    this.hands = 2
    }
    say(){
    console.log('I can say')
    }
    }
    let humen = new Humen()
    console.log(humen) // Humen {eyes: 2, hands: 2}
    humen.say() // I can say

    class Women extends Humen{
    say(){
    console.log('Women say')
    }
    }
    let women = new Women()
    console.log(women) // Women {eyes: 2, hands: 2}
    women.say() // Women say
    • 子类继承父类使用extends关键字,为父类指定静态方法,使用static方法名
    • 构造函数或方法是在类被实例化以后立刻调用的,可以用来传参
    • super 在构造函数中可以当一个函数来使用,相当于调用父类的构造函数
    • super.父类方法 调用父类的方法
    • super 在原型方法中,可以当一个对象来使用,相当于父类的原型对象,并且会自动绑定this到子类上
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      class Humen{
      constructor(){
      this.eyes = 2
      this.hands = 2
      }
      say(){
      console.log('I can say')
      }
      }
      class Thief extends Humen{
      constructor(){
      super() // 子类继承父类必须调用父类的构造函数 必须放在第一句
      // 子类可以增加或修改父类的属性
      this.hands = 3
      this.face = 1
      }
      // 重写父类的方法
      say(){
      super.say() // 调用父类的方法
      console.log('Thief say')
      }
      // 子类扩展的方法
      run(){
      console.log('Thief run')
      }
      }
      let thief = new Thief()
      console.log(thief) // Thief {eyes: 2, hands: 3, face: 1}
      console.log(thief.hands) // 3
      console.log(thief.face) // 1
      thief.say() // Thief say
      thief.run() // Thief run
  • 静态方法 es5中类的方法是静态方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // es5 静态方法只能通过 类名.静态方法名() 调用,不能使用对象实例调用
    function Animal(type){
    this.type = type
    this.walk = function(){ console.log('对象实例的方法') }
    }
    Animal.eat = function() { console.log('定义在类上的静态方法') }
    var dog = new Animal('dog')
    dog.walk() // 对象实例的方法
    Animal.eat() // 定义在类上的静态方法 只能通过类去调用
    dog.eat() // dog.eat is not a function

    //es6 静态方法只能通过 类名.静态方法名() 调用,不能使用对象实例调用
    class People {
    constructor(){
    this.name = name
    }
    walk (){
    console.log('普通方法')
    }
    static eat (){
    console.log('静态方法')
    }
    }
    let people = new People('tew')
    people.walk() // 普通方法
    People.eat() // 静态方法
    people.eat() // people.eat is not a function

数值的扩展

  • Math.trunc(num) 干掉小数点,返回整数部分。
  • Math.sign(num) 判断参数是正数,负数,正0还是负0,是正数时返回1 ,是负数时返回-1,0的时候返回0,-0的时候返回-0,NaN,对于非数值,会先将其转换为数值。
  • Math.hypot(3,4) 返回参数的平方和的平方根(勾股定理)
  • Math.cbrt(8) 返回参数的立方根
  • Number.isInteger(num) 判断是否是整数 数值3.0和3.00都会被认为是整数。
  • Number.isNaN(num) 用来检查一个值是否为NaN,只有NaN才返回true,非NaN返回false
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    console.log(Math.trunc(1.634)) // 1
    console.log(Math.sign(5)) // 1
    console.log(Math.sign(-5)) // -1
    console.log(Math.sign(0)) // 0
    console.log(Math.sign(-0)) // -0
    console.log(Math.sign(NaN)) //NaN
    console.log(Math.sign(null)) // 0
    console.log(Math.hypot(3,4)) // 5
    console.log(Math.cbrt(8)) // 2
    console.log(Number.isInteger(3.0)) // true
    console.log(Number.isInteger(3.1)) // false
    // Number.isNaN() 与 isNaN() 的区别,isNaN先调用Number()转换在判断, Number.isNaN() 只对数值有效
    console.log(isNaN('NaN')) // true
    console.log(Number.isNaN('NaN')) // false

字符串的扩展

  • 模板字符串 在模板字符串中使用 ${'字符串'|'运算符'|变量} ${表达式} 插值

    1
    2
    3
    4
    5
    6
    7
    let flag = true, text = '模板字符串'
    let html = `
    <ul>
    <li>${text.slice(0,2)}</li>
    <li class="${flag?'show':'hide'}">${text}</li>
    </ul>`
    console.log(html)//<ul><li>模板</li><li class="show">模板字符串</li></ul>
  • str.repeat(n) 重复n个相同的字符串

  • str.includes('a') 字符串中是否包含某字符
  • str.startsWith('a') 字符串是否以某字符开头
  • str.endsWith('a') 字符串是否以某字符结尾

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let str = 'abca'
    console.log(str.repeat(2)) // abcaabca
    console.log(str) // abca
    console.log(str.includes('a')) // true
    console.log(str.includes('d')) // false
    console.log(str.startsWith('a')) // true
    console.log(str.startsWith('b')) // false
    console.log(str.endsWith('a')) // true
    console.log(str.endsWith('b')) // false
  • str.padStart(2,'0') 向前填充字符

  • str.padEnd(2,'0') 向后填充字符
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串
    console.log('1'.padStart(2, '0')) // 01
    console.log('01'.padStart(2, '0')) // 01
    console.log('1'.padEnd(2, '0')) // 10
    console.log('10'.padEnd(2, '0')) // 10
    let date = new Date()
    console.log(date.getHours().toString().padStart(2, '0') + '时') // 09时
    console.log(date.getMinutes().toString().padStart(2, '0') + '分') // 08分
    // 如果省略第二个参数 默认使用空格补全长度
    console.log('a'.padStart(5)) // ' a'
    console.log('a'.padEnd(5)) // 'a '
    // 如果补全的字符串和原字符串的长度之和 小于指定的长度 会截去超出位数进行补全
    console.log('abc'.padStart(10, '0123456789')) // 0123456abc => 789 被截掉用 abc补全

数组的扩展

  • Array.from() 将类数组或可遍历的对象转化成真正的数组如NodeList arguments string Set Map

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let lis = document.querySelectorAll('li');
    console.log(Array.isArray(lis)) // false
    let lis2 = Array.from(lis)
    console.log(Array.isArray(lis2)) // true
    console.log(Array.from('hello')) // ['h', 'e', 'l', 'l', 'o']
    console.log(Array.from(new Set(['a', 'b']))) // ['a', 'b']
    // Array.from(arg, callback) 可以接收第二个参数,作用类似数组的map方法,对每个元素处理后放回数组中
    let items = document.querySelectorAll('.item')
    console.log(Array.from(items, s => s.innerText))
  • Array.of(e1,e2,…) 按顺序创建包含每个参数的数组,不考虑参数的数量和数据类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Array.of()和Array()区别在于处理整数参数
    // Array(n) n个长度的undefiend数组
    // Array.of(n) 一个长度的数组 [n]
    console.log(Array.of(1, 'a', {}, [], true)) // [1, "a", {…}, Array(0), true]
    console.log(Array(1, 'a', {}, [], true)) // [1, "a", {…}, Array(0), true]
    console.log(Array.of(7)) // [7]
    console.log(Array(7)) // (7) [,,,,,,]
    console.log(Array(7).length) // 7
    console.log(Array(7)[1]) // undefined
  • arr.find() 返回数组中第一个符合条件的数组元素,否则返回undefined

  • arr.findIndex() 返回数组中第一个符合条件的数组元素的索引,否则返回-1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const arr = [1, '2', '3', true]
    let resFind = arr.find((item)=>{
    return item > 1
    })
    let resFindIndex = arr.findIndex((item)=>{
    return item > 1
    })
    console.log(resFind) // '2'
    console.log(resFindIndex) // 1
  • arr.fill() 用固定值填充数组中从指定起始索引到指定终止索引内的全部元素,不包括终止索引。(会改变原数组)

    1
    2
    3
    4
    const arr = [1, '2', true]
    // console.log(arr.fill('a')) // ["a", "a", "a"]
    // console.log(arr.fill('a', 1)) // [1, "a", "a"]
    console.log(arr.fill('a', 1, 2)) // [1, "a", true]
  • arr.includes() 检测数组是否包含某元素,可判断NaN

    1
    2
    3
    4
    let arr = [1, NaN, 'a']
    console.log(arr.includes(1)) // true
    console.log(arr.includes(NaN)) // true
    console.log(arr.includes('b')) // false
  • 扩展运算符(spread)… 将类数组转为用逗号分隔的参数序列,好比rest参数的逆运算

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var arr = [1,4,7,3,2,11]
    var str = 'tew'
    console.log(...arr) // 1 4 7 3 2 11
    console.log(...str) // t e w
    console.log(Math.max.apply(null,arr)) // 11
    console.log(Math.max(...arr)) // 11 => Math.max(1,4,7,3,2,11)
    // 扩展运算符与解构赋值结合使用
    const [first, ...arr] = [1, 2, 3]
    console.log(first) // 1
    console.log(arr) // [2, 3]

对象的扩展

  • 使用扩展运算符(spread)…取出参数对象的所有可遍历属性,拷贝到当前对象之中(浅拷贝)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 展开一个对象
    let obj = {a:1, b:2}
    let obj1 = {
    c:'children',
    name:'tew',
    ...obj
    }
    console.log({...obj}) // {a: 1, b: 2} 可以浅拷贝对象
    console.log(obj1) //{c: "children", name: "tew", a: 1, b: 2}
  • 对象属性名和属性值相同时可简写, 属性可以是表达式,对象的方法简写可省略:function

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let a = 1
    let b = 'c'
    const obj = {
    a, // 属性名和值相同时可简写
    [b+a]: '3', // 属性可以使表达式
    say () { // 对象方法简写
    console.log(this.a + '--' + this[b+a])
    }
    }
    console.log(obj) // {a: 1, c1: "3", say: ƒ}
    obj.say() // 1--3
  • Object.is(a,a) 比较两个值是否相等 多数情况下Object.is等价于”===”,可以判断NaN,但-00不相等

    1
    2
    3
    4
    5
    6
    7
    console.log(Object.is(1,1))  // true
    console.log(Object.is(null,null)) // true
    console.log(Object.is(undefined,undefined)) // true
    console.log(NaN === NaN) // fasle
    console.log(Object.is(NaN,NaN)) // true
    console.log(Object.is(0,-0)) // false
    console.log(Object.is(+0,-0)) // false
  • Object.keys() 返回一个数组,数组中每一项是对象中可被遍历的键名

  • Object.values() 返回一个数组,数组中每一项是对象中可被遍历的键值
  • Object.entries() 返回一个数组,数组中每一项是对象中可被遍历的键值对数组
  • Object.getOwnPropertyNames() 返回一个数组,由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成。
  • Object.getOwnPropertyDescriptors(obj) 返回对象所有属性的描述对象
  • Object.getOwnPropertyDescriptor(obj, 'a') 返回指定属性的描述对象
  • Object.getOwnPropertySymbols(obj) 方法返回一个给定对象自身的所有Symbol属性的数组。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    let a = 1
    let b = 'c'
    const obj = {
    a, // 属性名和值相同时可简写
    [b+a]: '3', // 属性可以使表达式
    say () { // 对象方法简写
    console.log(this.a + '--' + this[b+a])
    },
    [Symbol('tew')]:'hello'
    }
    console.log(obj) // {a: 1, c1: "3", Symbol(tew): "hello", say: ƒ}
    console.log(Object.keys(obj)) // ["a", "c", "say"]
    Object.defineProperty(obj, 'a', {
    enumerable: false //是否可枚举 默认值为true
    })
    console.log(Object.keys(obj)) // ["c", "say"]
    console.log(Object.getOwnPropertyNames(obj)) // ["a", "c", "say"]

    console.log(Object.values(obj)) // ["3", ƒ]
    console.log(Object.entries(obj)) //[["c", "3"],["say", ƒ]]
    console.log(Object.getOwnPropertyDescriptors(obj))
    /* {
    a: {value: 1, writable: true, enumerable: false, configurable: true}
    c1: {value: "3", writable: true, enumerable: true, configurable: true}
    say: {writable: true, enumerable: true, configurable: true, value: ƒ}
    Symbol(tew): {value: "hello", writable: true, enumerable: true, configurable: true}
    } */
    console.log(Object.getOwnPropertyDescriptor(obj, 'a'))
    //{value: 1, writable: true, enumerable: false, configurable: true}
    console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(tew)]
  • Object.assign(target,[obj1]) 用于对象的合并,将源对象的所有可枚举属性,复制到目标对象target中,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性.String类型和 Symbol类型的属性都会被拷贝 只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false) 是浅拷贝而不是深拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let a = 1
    let obj = {
    a,
    [Symbol('tew')]:'hello',
    say () {
    console.log(this.a + '--' + this[b])
    }
    }
    console.log(Object.assign({a:3}, obj)) // {a: 1, Symbol(tew): "hello", say: ƒ}
    // 如果只有一个参数,会直接返回该参数,不是对象则会先转成对象.
    console.log(Object.assign(obj)) // {a: 1, Symbol(tew): "hello", say: ƒ}
    console.log(Object.assign(2)) // Number {2}
    // 如果一个参数是null或undefiend无法转成对象则会报错
    console.log(Object.assign(null)) // Cannot convert undefined or null to object
    // console.log(Object.assign(undefined)) //Cannot convert undefined or null to object
    // 如果
  • Object.defineProperty() 添加/修改属性 或 自定义SettersGetters(Vue2双向绑定原理就是基于此)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /* 添加/修改属性  */
    obj2 = {x: 1}
    Object.defineProperty(obj2, 'y', {
    //描述或设置了该属性的细节
    value: 100, // 设置的值
    writable: true, //是否可被改写 默认值为true
    enumerable: true, //是否可枚举 默认值为true
    configurable: true //是否可被删除 默认值为true
    })
    console.log(obj2) // {x: 1, y: 100}
    obj2.y = 200 // 改写
    for (const key in obj2) {
    //枚举属性
    console.log(key + '--' + obj2[key]) // x--1 y--200
    }
    delete obj2.y // 可删除
    console.log(obj2) // {x: 1}
    /* 自定义 Setters 和 Getters 实现简单的双向绑定 */
    //<input type="text" id="model"><br/>
    //<div id="modelText"></div>
    let user = {}
    modelText.textContent = model.value = '默认值'
    Object.defineProperty(user,"name",{ // 监听name属性改变
    get:function(){
    return defaultName
    },
    set:function(newValue){
    modelText.textContent = newValue
    }
    })
    model.addEventListener("keyup", function () {
    user.name = this.value
    }, false)
-------------本文结束感谢您的阅读-------------
0%