美文网首页
JS基础知识总结(十三):ES6 对象的扩展

JS基础知识总结(十三):ES6 对象的扩展

作者: 前端老道 | 来源:发表于2020-07-01 14:21 被阅读0次

    “ 关注 前端开发社区 ,回复"1"即可加入 前端技术交流群,回复 "2"即可免费领取 500G前端干货!

    作者:前端林子 https://cloud.tencent.com/developer/article/1380512

    上一节主要是总结了ES6中和数组有关的内容。本节主要总结ES6中对象的扩展,具体内容包括以下几个方面:

    会介绍以下内容:

    image

    1.ES6对象字面量

    1.1简化对象属性定义

    验证(1):

    简化属性定义:

    // ES5
    function test(name, age) {
        return {
            name: name,
            age: age
        }
    }
    // 等价于
    function test(name, age) {
        return {
            name,
            age
        }
    }
    

    当一个对象的属性和本地变量同名时,可以简单地中写属性名。

    1.2 对象方法简写

    验证(2):

    对象方法可以简写,去掉冒号和function关键字:

    // ES5
    var person = {
        name: "Peter",
        age: 26,
        showAge: function () {
            console.log('age is', this.age)
        }
    }
    // 等价于
    var person = {
        name: "Peter",
        age: 26,
        showAge() {
            console.log('age is', this.age)
        }
    }
    

    1.3同一个对象定义多个同名属性不报错

    验证(3):

    同一个对象定义多个同名属性不报错

    var person = {
        name:'Peter',
        name:'Tom'
    }
    console.log(person.name) // Tom
    

    ES5在严格模式下会去校验是否有同名属性,ES6则无论在严格模型下,还是非严格模式下,都不会去校验属性是否重复。

    2. Object.is() 和Object.assing()

    2.1 Object.is()

    有些像“===”运算符,可接受两个参数进行比较。如果两个参数的类型一致,并且值也相同,则返回true。

    验证:

    console.log(Object.is(1,"1")); // false 
    Object.is()和===运算符的区别:
    
    console.log(Object.is(+0, -0)); // false
    console.log(+0 === -0); // true
    
    console.log(Object.is(NaN, NaN)) // true
    console.log(NaN === NaN) // false
    

    2.2 Object.assign(target,source1,source2,...)

    返回第一个接收对象,可以接受任意个源对象,如果多个源对象有相同的属性,则后面的会覆盖前面的。

    验证(1):

    var target = {};
    Object.assign(target, {
        name: 'tony',
        age: '24'
    })
    console.log(target) // {name: "tony", age: "24"}    
    

    验证(2):

    如果后面的多个源对象source1,source2有同名的属性,则后面的源对象会覆盖前面的

    var target = {};
    Object.assign(target, {
        name: 'tony',
        age: '24'
    }, {
            age: '28'
        })
    console.log(target) // {name: "tony", age: "28"}
    

    验证(3):

      var target = {};
      function source() { }
      source.prototype = {
          constructor: source,
          hello: function () { console.log('hello~~') }
      }
      Object.assign(target, source.prototype)
      target.hello(); //hello~~   
    

    验证(4):

    忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

    var target = {};
    var source1 = {
        age: '24'
    }
    function Person(name) {
        this.name = name;
    }
    Person.prototype.hello = function () {
        console.log(this.name)
    }
    var source2 = new Person("tony");
    // 使用Object.defineProperty()为source2对象定义一个名为hobby的属性,且设定为可枚举的
    Object.defineProperty(source2, "hobby", {
        enumerable: true,
        value: 'reading'
    })
    
    Object.assign(target, source1, source2)
    console.log(target) // {age: "24", name: "tony", hobby: "reading"} 
    

    去掉上述enumerable属性(默认为false),再看下结果:

    var target = {};
    var source1 = {
        age: '24'
    }
    function Person(name) {
        this.name = name;
    }
    Person.prototype.hello = function () {
        console.log(this.name)
    }
    var source2 = new Person("tony");
    // 使用Object.defineProperty()为source2对象定义一个名为hobby的属性,且设定为不可枚举的
    Object.defineProperty(source2, "hobby", {
        value: 'reading'
    })
    
    Object.assign(target, source1, source2)
    console.log(target) // {age: "24", name: "tony"}    
    

    可以看出Object.assign()会忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

    【补充】有四个操作会忽略enumerable为false的属性,即不可枚举的属性:

    • for...in循环:只遍历对象自身的和继承的可枚举的属性。

    • Object.keys():返回对象自身的所有可枚举的属性的键名。

    • JSON.stringify():只串行化对象自身的可枚举的属性。

    • Object.assign():只拷贝对象自身的可枚举的属性。

    3.定义了自身属性枚举顺序

    自有属性枚举顺序的基本规则:

    • 1,所有数字键按升序排序;

    • 2,所有字符串键按它们被加入对象的顺序排序;

    • 3,所有symbol键按照它们被加入对象的顺序排序;

    验证(1):

    可以用Object.getOwnPropertyNames(obj)方法查看对象自身的所有属性(不含Symbol属性,包含不可枚举属性)的键名。

    var obj = {
        2: 1,
        name: 'tony',
        0: 1,
        age: '24',
        hobby: 'reading',
        1: 1
    }
    console.log(Object.getOwnPropertyNames(obj)) // ["0", "1", "2", "name", "age", "hobby"]
    

    可以看出,字符串键是跟在数值键之后,数值键按升序排序,字符串键按加入对象的顺序排序。

    【补充】:

    ES6 一共有 5 种方法可以遍历对象的属性。

    • for...in

    for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。

    • Object.keys(obj)

    Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

    • Object.getOwnPropertyNames(obj)

    Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

    • Object.getOwnPropertySymbols(obj)

    Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

    • Reflect.ownKeys(obj)

    Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

    以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。

    4.创建对象后修改对象原型:Object.setPrototypeOf()

    Object.setPrototypeOf()方法的作用:改变任意指定对象的原型,接受两个参数:

    -- 被改变原型的对象

    -- 替代第一个参数原型的对象

    验证(1):

    var dog = {
        hello() {
            console.log('a dog barks')
        }
    }
    var person = {
        hello() {
            console.log('say hello')
        }
    }
    
    // 以person为原型
    var person1 = Object.create(person);
    person1.hello(); // say hello
    console.log(person.isPrototypeOf(person1)) // true
    
    // 将person1的原型设置为dog
    Object.setPrototypeOf(person1, dog)
    person1.hello(); // a dog barks
    console.log(person.isPrototypeOf(person1)) // false
    console.log(dog.isPrototypeOf(person1)) // true
    

    说明:person1的原型原本是person,通过Object.setPrototypeOf(person1,dog)后,把person1的原型设置为了dog。

    5.super关键字

    ES5中,this关键字总是指向函数所在的当前对象。

    ES6 中的关键字super,指向当前对象的原型对象。

    验证(1):

    可以用super更方便地访问对象的原型,来引用对象原型上所有的方法。

    ES5:

      var dog = {
          hello() {
              return 'a dog barks'
          }
      }
      var person = {
          hello() {
              return 'say hello'
          }
      }
      var friend = {
          hello() {
              let msg = Object.getPrototypeOf(this).hello.call(this)
              console.log(msg);
          }
      }
      Object.setPrototypeOf(friend, dog);
      friend.hello(); // a dog barks
      Object.setPrototypeOf(friend, person);
      friend.hello(); // say hello
    

    Object.getPrototypeOf(this)就是指向对象的原型,ES6中可以用super替换:

    Object.getPrototypeOf(this).hello.call(this)
    
    // 等价于
    super.hello()
    var dog = {
        hello() {
            return 'a dog barks'
        }
    }
    var person = {
        hello() {
            return 'say hello'
        }
    }
    var friend = {
        hello() {
            let msg = super.hello()
            console.log(msg);
        }
    }
    Object.setPrototypeOf(friend, dog);
    friend.hello(); // a dog barks
    Object.setPrototypeOf(friend, person);
    friend.hello(); // say hello
    
    

    从结果可以看出效果是一样的。

    验证(2)

    必须要在简写方法的对象中使用super,其他地方声明中使用则会报语法错误。

    Uncaught SyntaxError: 'super' keyword unexpected here
    

    还是上面的示例:

     var dog = {
            hello() {
                return 'a dog barks'
            }
        }
        var person = {
            hello() {
                return 'say hello'
            }
        }
        var friend = {
            hello: function () {
                let msg = super.hello()
                console.log(msg);
            }
        }
        Object.setPrototypeOf(friend, dog);
        friend.hello();
        Object.setPrototypeOf(friend, person);
        friend.hello(); // Uncaught SyntaxError: 'super' keyword unexpected here
    

    6.小结

    本节内容主要总结了ES6中对象的一些扩展。包括对象字面量上的变更、Object.is()(注意下和===的区别)、Object.assign()方法,对象自身属性的枚举属性的顺序、Object.setPrototypeOf()方法可以在创建对象后改变它的原型,以及可以通过super关键字调用对象原型的方法。

    往期:

    JS基础知识总结(十一):ES6 类与继承

    JS基础知识总结(十):ES6基本知识点(2)

    JS基础知识总结(九):ES6基本知识点(1)

    请各位帅哥美女多多支持帅编,回复“1”即可加入前端技术交流群,回复"2"即可领取 500G 前端干货

    image

    相关文章

      网友评论

          本文标题:JS基础知识总结(十三):ES6 对象的扩展

          本文链接:https://www.haomeiwen.com/subject/kviyfktx.html