美文网首页
【ES6 笔记】扩展对象的功能性

【ES6 笔记】扩展对象的功能性

作者: ___Jing___ | 来源:发表于2018-10-31 14:30 被阅读0次

    对象类别

    • 普通( Ordinary )对象:具有JavaScript对象所有的默认内部行为;
    • 特异( Exotic )对象:具有某些与默认行为不符的内部行为;
    • 标准( Standard )对象:ES6规范中定义的对象,例如Array、Date等。标准对象既可以是普通对象,也可以使特异对象。
    • 内建对象:脚本开始执行时存在于JavaScript执行环境中的对象,所有标准对象都是内建对象

    对象字面量语法扩展

    • 属性初始值的简写
      在我们传统的JS中,对象字面量只是简单的键值对集合,这意味着初始化属性时会有一些重复,举个例子:
    function createPerson( name, age ){
      return {
          name : name,  //name写了两遍,一遍是属性名,一遍是变量
          age : age  //age写了两遍,一遍是属性名,一遍是变量
      }
    }
    

    在ES6中我们对上面的属性初始化进行了简化,当一个对象的属性与本地变量同名时,不必再写冒号和值,简单地只写属性名即可:

    function createPerson( name, age ){
      return {
          name ,
          age
      }
    }
    /*
    * 当对象字面量里只有一个属性的名称时,JS引擎会在可以访问作用域中查找其同名变量;
    * 如果找到,则该变量的值被赋给对象字面量里的同名属性。
    * 在本例中,对象字面量属性name被赋予了局部变量name的值。
    */
    
    • 对象方法的简写语法
      在ES6之前,我们为对象添加方法,必须通过制定名称并完整定义函数:
    let person = {
        name : '欧阳不乖',
        sayName : function(){
            console.log(this.name)
      }
    }
    

    而在ES6中,语法更简洁,消除了冒号和function关键字,让我们来重写上边的例子:

    let person = {
        name : '欧阳不乖',
        sayName(){
            console.log(this.name)
      }
    }
    

    这种简洁写法与传统的定义对象方法所具有的特性全部一致,二者唯一的区别是,简写方法可以使用super关键字(稍后讨论)

    • 可计算属性名
      在早期函数中,我们如果想要通过计算得到属性名,只能用方括号代替点的方式:
    // 我们想要的效果:
    let name = 'unknown';
    let person = {};
    person[ name ] = '欧阳不乖';
    console.log(person);  // {unknown: "欧阳不乖"}
    /*
    * 这里我们要是换一种写法,就会是不一样的结果了
    * let name = 'unknown';
    * let person = {
    *      name : '欧阳不乖'
    *  };
    * console.log(person);  // {name: "欧阳不乖"}
    * 当属性被包含在一个变量中的时候,这种赋值方式和我们设想的就不一样了
    */
    

    在ES6中,可在对象字面中使用可计算属性名称,其语法与引用对象实例的可计算属性名称相同,也是使用方括号:

    let name = 'unknown';
    let person = {
        [ name ] :  '欧阳不乖'
    };
    console.log(person);  // {unknown: "欧阳不乖"}
    

    扩展:

    let suffix  = 'name';
    let person = {
        ['full-'+suffix ] :  '欧阳不乖',
        [`chinese-${suffix}`] : '欧阳不乖'
    };
    console.log(person);  //{full-name: "欧阳不乖", chinese-name: "欧阳不乖"}
    

    新增API方法

    • Object.is()方法
      Object.is()方法来弥补全等运算符的不准确运算。这个方法接受两个参数,如果这两个参数类型相同且具有相同的值,则返回true。
      其发部分运行结果与“===”运算符相同,唯一的区别在于+0和-0被识别为不相等且NaN与NaN等价。
    console.log( '欧阳不乖'==='欧阳不乖' ); // true
    console.log( Object.is('欧阳不乖','欧阳不乖') ); // true
    
    console.log( +0 === -0 ); // true
    console.log( Object.is(+0, -0) );  // false
    
    console.log( NaN === NaN ); // false
    console.log( Object.is(NaN,NaN) );  // true
    /* 具体使用哪一种比较方法,主要取决于业务需要 */
    
    • Object.assign()方法
      接受任意数量的源对象,并按指定的顺序将属性复制到接收对象中。所以如果多个源对象局哟楼同名属性,则排位靠后的源对象会覆盖排位靠前的。
    let receiver = {} ;
    Object.assign(receiver,
        {
            type : 'js' ,
            name : 'file.js'
        },{
            type : 'css'
        }
    );
    console.log( receiver ); //{type: "css", name: "file.js"}
    console.log( receiver.type ); //'css'
    console.log( receiver.name ); //'file.js'
    

    重复的对象字面量属性

    在ES5严格模式下,对象字面量属性名重复时会抛出错误
    而在ES6中,字面量属性名称如果重复的话,只会选取最后一个取值:

    let person = {
        name : 'unKnown',
        name : '欧阳不乖'
    }
    console.log(person.name); // '欧阳不乖'
    

    自由属性枚举顺序

    在ES5中未定义对象属性的枚举顺序,由Javascript引擎厂商自行决定。
    在ES6中严格规定了对象的自由属性被枚举时的返回顺序。
    自有属性枚举顺序的基本规则是:

    1. 所有数字键按升序排序
    2. 所有字符串键按照它们被加入对象的顺序排序
    3. 所有symbol键按照它们被加入对象的顺序排序
    let obj = {
        a:1,
        0:1,
        c:1,
        2:1,
        b:1,
        1:1
    }
    obj.d = 1;
    console.log(Object.getOwnPropertyNames(obj).join('')); //012acbd
    

    对于数值键,尽管在对象自绵中的顺序是随意的,但是在枚举时会被重新组合和排序
    对于for-in、Object.keys和JSON.stringify()方法暂时仍按照各引擎厂商的自行实现顺序枚举

    增强对象原型

    • 改变对象的原型
      正常情况下,对象原型是在对象被创建的时候指定的,对象原型在实例化之后保持不变。
      在ES6中添加了Object.setPrototypeOf()方法来改变对象原型,它接受两个参数:被改变原型的对象及替代第一个参数原型的对象:
    let person = {
        getGreeting(){
              return 'Hello';
        }
    };
    let dog = {
        getGreeting(){
            return 'Woof';
        }
    }
    // 以person对象为原型
    let friend = Object.create(person);
    console.log(friend.getGreeting()); // 'Hello'
    console.log(Object.getPrototypeOf(friend)===person); // true
    // 将原型设置为dog
    Object.setPrototypeOf(friend,dog);
    console.log(friend.getGreeting()); // 'Woof'
    console.log(Object.getPrototypeOf(friend)===dog); // true
    

    对象原型的真实值被存储在内部专用属性[[Prototype]]中,调用Object.getPrototypeOf()方法返回存储在其中的值,调用Object.setPrototypeOf()方法改变其中的值

    • 简化原型访问的Super引用
      ES6中引入了Super引用的特性,使用它可以更便捷地访问原型对象。
    let person = {
        getGreeting(){
              return 'Hello';
        }
    };
    let dog = {
        getGreeting(){
            return 'Woof';
        }
    }
    let friend = {
        getGreeting(){
              return super.getGreeting() + ',nice to meet you. '             
              // 等价于 Object.getPrototypeOf(this).getGreeting().call(this)
        }
    }
    

    简单来说,Super引用相当于指向对象原型的指针,实际上也就是Object.getPrototypeOf(this)的值。
    Super引用不是动态变化的,它总是指向正确的对象。
    Super方法必须在简写方法的对象中使用,其他地方引用会导致语法错误。

    正式的方法定义

    在上边我们用Super的时候指明要求只能在简写方法的对象中使用,下面我们来解释一下原因。
    在ES6中正式将方法定义为一个函数,它会有一个内部的[[HomeObject]]属性来容纳这个而方法从属的对象:

    let person = {
        // 是方法
        getGreeting(){
              return 'Hello';
        }
    }
    // 不是方法
    function shareGreeting(){
        return 'Hi !'
    }
    

    这个示例中定义了person对象,它有一个getGreeting()方法,由于直接把函数赋值给了person对象,因而getGreeting()方法的[[HomeObject]]属性值为person。而创建shareGreeting()函数时,由于未将其赋值给一个对象,因为该方法没有明确定义[[HomeObject]]属性。在大多数情况下这点小差别无关紧要,但是当使用Super引用时就变得非常重要了。
    Super的所有引用都通过[[HomeObject]]属性来确定后续的运行过程,第一步是在[[HomeObject]]属性上调用Object.getPrototypeOf()方法来检索原型的引用:然后搜寻原型找到同名函数;最后,设置this绑定并且调用相应的方法。
    注意:这里定义的是方法,而非函数,二者都是函数

    相关文章

      网友评论

          本文标题:【ES6 笔记】扩展对象的功能性

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