zoukankan      html  css  js  c++  java
  • ES6类型扩展对象扩展

    对象类别

    一直以来对象的术语描述没有统一的标准,于是ES6规范定义了每一个类别的对象,对象的类别如下:

    1、普通(Ordinary)对象
    具有JS对象所有的默认内部行为

    2、特异(Exotic)对象
    具有某些与默认行为不符的内部行为

    3、标准(Standard)对象
    ES6规范中定义的对象,例如,Array、Date等。标准对象既可以是普通对象,也可以是特异对象

    4、内建对象
    脚本开始执行时存在于JS执行环境中的对象,所有标准对象都是内建对象

    对象简写

    属性简写

    当一个对象的属性与本地变量同名时,只写属性名即可

    let name = 'wmui', age = 10
    let obj = {name,age}
    
    // 等价于 
    let obj = {name: "wmui", age: 10}
    

    方法简写

    对象的方法也可以简写,消除了冒号和function关键字

    let obj = {
      name: 'wmui',
      sayName() {
       return this.name
      }
    }
    
    // 等价于
    let obj = {
      name: 'wmui',
      sayName: function() {
       return this.name
      }
    }
    

    两者的唯一区别是,简写方法可以使用super关键字,普通方法不可以

    可计算属性名

    在ES5中是无法为对象字面量定义可计算属性名的,比如说属性名是一个变量。但在ES6中可以通过为属性名加一对方括号来定义可计算属性名。

    let suffix = ' name'
    let obj = {
      ['first' + suffix]: 'wang',
      ['last' + suffix]: 'li'
    }
    
    console.log(obj['first name']) // wang
    console.log(obj['last name']) // li
    

    判断相等

    在JS中,判断两个值是否相等,通常会使用相等运算符或全等运算符,但是有时候即使使用全等运算符也不一定完全靠得住

    console.log(+0 === -0);//true
    console.log(NaN === NaN);//false
    

    ES6引入了Object.is()方法来弥补全等运算符的不准确运算。这个方法接受两个参数,如果这两个参数类型相等且具有相同的值,则返回true,否则返回false

    console.log(Object.is(+0, -0)) // false
    console.log(Object.is(3, '3')) // false
    console.log(Object.is([], [])) // false
    console.log(Object.is(NaN, NaN)) // true
    

    对象合并

    ES6新增了Object.assign()方法用于对象合并,该方法的第一个参数是目标对象,后面的参数是源对象,源对象的数量不限。

    Object.assign()方法可以把源对象按照顺序将属性复制到目标对象中,如果目标对象与源对象有同名属性,或者源对象与源对象有同名属性,那么后面的属性会覆盖前面的属性。

    注意: 属性的复制实际上是浅拷贝的过程,并且只拷贝源对象自身的属性,对于继承属性和不可枚举属性是不拷贝的

    let target = { a: 1, b: 1 };
    let source1 = { b: 2, c: 2 };
    let source2 = { c: 3 };
    
    Object.assign(target, source1, source2);
    target // {a:1, b:2, c:3}
    
    let o = {};
    Object.defineProperty(o, 'name', {
      enumerable: false,
      value: 'wmui'
    })
    
    console.log(Object.assign({a: 1},o)) // {a: 1}
    
    let o = {a: {b: 2}};
    let o2 = Object.assign({}, o)
    o.a.b = 3
    console.log(o2.a.b) // 3
    

    属性名重复

    在ES6中,无论是在严格模式还是非严格模式下,代码不再检查重复属性,对于每一组重复属性,都会选取最后一个取值

    如果是在ES5严格模式下,当同时存在多个同名属性时会抛出错误

    let o = {
      name: 'li',
      name: 'wang'
    }
    console.log(o.name) // wang
    

    枚举顺序

    ES6严格规定了对象的自有属性被枚举时的返回顺序,这会影响到Object.getOwnPropertyNames()方法及Reflect.ownKeys返回属性的方式,自有属性枚举顺序的基本规则如下:

    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"
    

    对象原型

    __proto__属性,用来读取或设置当前对象的prototype对象,目前所有浏览器都部署了该属性。

    标准规定,只有浏览器必须部署__proto__属性。开发过程中最好不要直接使用该属性,而是使用Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)来代替

    Object.getPrototypeOf()

    Object.getPrototypeOf(obj)方法用于获取一个对象的原型对象

    Object.setPrototypeOf()

    Object.setPrototypeOf()方法与proto作用相同,可以改变任意指定对象的原型。该方法接收两个参数:要改变原型的对象和替代第一个参数原型的对象

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       return 'li'
      }
    }
    
    let p = Object.create(person)
    console.log(p.sayName()) // wang
    console.log(Object.getPrototypeOf(p) === person) // true
    
    // 改变原型
    Object.setPrototypeOf(p,friend)
    console.log(p.sayName()) // li
    console.log(Object.getPrototypeOf(p) === friend) // true
    

    对象原型的真实值被储存在内部专用属性[[protơtype]]中,调用Object.getPrototypeOf()方法返回储存在其中的值,调用Object.setPrototypeOf()方法改变其中的值。然而,这不是操作[[prototype]]值的唯一方法

    super引用

    ES6引入了super引用,使开发者可以更便捷的访问对象原型。

    如果想重写对象实例的方法,又需要调用与它同名的原型方法,利用super引用可以这样写

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       return super.sayName() + ' and li are good friends';
      }
    }
    Object.setPrototypeOf(friend,person)
    console.log(friend.sayName()) // wang and li are good friends
    console.log(Object.getPrototypeOf(friend) === person) // true
    

    super引用相当于指向对象原型的指针,实际上也就是Object.getPrototypeOf(this)的值

    如果用es5来写这个示例,就要复杂一些,而且不容易理解

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       // 注意这里
       return Object.getPrototypeOf(this).sayName.call(this) + ' and li are good friends';
      }
    }
    Object.setPrototypeOf(friend,person)
    console.log(friend.sayName()) // wang and li are good friends
    console.log(Object.getPrototypeOf(friend) === person) // true
    

    Super引用在多重继承情况下非常有用,因为在这种情况下,使用Object.getPrototypeOf()方法将会出现问题

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       return Object.getPrototypeOf(this).sayName.call(this) + ' and li are good friends';
      }
    }
    Object.setPrototypeOf(friend,person)
    
    let p = Object.create(friend)
    console.log(p.sayName()) // Uncaught RangeError: Maximum call stack size exceeded
    

    当执行p.sayName()方法时,会调用friend.sayName()方法,而此时的this值为p。Object.getPrototypeOf(this)又会返回friend对象。所以就会进入递归调用直到触发栈溢出报错

    如果使用super引用就不会有这种问题

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       return super.sayName() + ' and li are good friends';
      }
    }
    
    Object.setPrototypeOf(friend,person)
    
    let p = Object.create(friend)
    console.log(p.sayName()) // wang and li are good friends
    

    super引用不是动态变化的,无论有多少其他方法继承了sayName()方法,super.sayName()始终指向person.sayName()方法

    方法定义

    在ES6以前从未正式定义过"方法"的概念,方法仅仅是一个具有功能而非数据的对象属性。而在ES6中正式将方法定义为一个函数,它会有一个内部的[[HomeObject]]属性来容纳这个方法从属的对象

    let person = {
      sayName() {
       return 'wang'
      }
    }
    
    let friend = {
      sayName() {
       return super.sayName() + ' and li are good friends';
      }
    }
    
    Object.setPrototypeOf(friend,person)
    console.log(friend.sayName()) 
    

    当调用friend.sayName()方法时,该方法内部的[[HomeObject]]属性值是friend,friend的原型是person,所以super.sayName()等价于person.sayName().call(this)

    对象遍历

    ES5 引入了Object.keys()方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名

    let obj = { a: 1, b: 2, c: 3 };
    console.log(Object.keys(obj)) // ["a", "b", "c"]
    
    for (let key of Object.keys(obj)) {
      console.log(key);
    }
    // a
    // b
    // c
    

    ES8引入了Object.values和Object.entries,作为遍历一个对象的补充手段,供for...of循环使用

    Object.values()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值

    let obj = { a: 1, b: 2, c: 3 };
    console.log(Object.values(obj)) // [1, 2, 3]
    
    for (let value of Object.values(obj)) {
      console.log(value);
    }
    // 1
    // 2
    // 3
    

    Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组

    let obj = { a: 1, b: 2, c: 3 };
    console.log(Object.entries(obj)) // [["a", 1], ["b", 2], ["c", 3]]
    
    for (let [key, value] of Object.entries(obj)) {
      console.log([key, value]);
    }
    // ["a", 1]
    // ["b", 2]
    // ["b", 3]
    
    优秀文章首发于聚享小站,欢迎关注!
  • 相关阅读:
    内置对象,监听器,过滤器
    20169201 使用Metaspoit攻击MS08-067实验
    20169201 2016-2017-2《网络攻防》课程总结
    20169201 2016-2017-2 《网络攻防》第十四周作业
    20169201 2016-2017-2 《网络攻防实践》第11周学习总结
    20169201 2016-2017-2 《移动平台开发实践》第10周学习总结
    20169201 2016-2017-2 《网络攻防实践》第10周学习总结
    20169201 实验三 敏捷开发与XP实践报告
    20169201 2016-2017-2 《网络攻防实践》 实验二
    20169201 2016-2017-2 实验一 网络攻防实验环境的搭建与测试
  • 原文地址:https://www.cnblogs.com/yesyes/p/15352140.html
Copyright © 2011-2022 走看看