美文网首页技术码头
ES6 对象的扩展和新增方法

ES6 对象的扩展和新增方法

作者: 石菖蒲_xl | 来源:发表于2020-01-03 17:06 被阅读0次

    一、属性的简洁表示法

    ES6允许在大括号里面直接写入变量和函数,作为对象的属性和方法。
    如下:变量foo直接写在大括号,属性名就是变量名,属性值就是变量值。

    • 简写的对象方法不能用作构造函数,会报错
    const foo = "bar";
    const baz = {foo};
    console.log(baz); // =>  {foo:"bar"}
    
    // 等同于
    const baz = {foo:foo}
    // 自己使用场景
    const {dataSource} = this.props;
    this.setState({dataSource});
    
    function getPoint() {
      const x = 1;
      const y = 10;
      return {x, y};
    }
    

    方法也可以简写

    const o = {
      init(){
        console.log('Hello Word!');
      }
    }
    
    const obj = {
      f() {
        this.foo = 'bar';
      }
    };
    
    new obj.f() // 报错
    

    二、super 关键字

    this关键字总是指向函数所在的当前对象
    super关键字指向当前对象的原型对象
    super表示原型对象时,只能用在对象的方法中,用在其它地方都会报错

    const o = {
      h:"Hello"
    }
    const p = {
      h:"Word",
      find() {
        return super.h
      }
    }
    Object.setPrototypeOf(p, o);
    p.find() // "hello"
    

    三、链判断运算符

    在编程实务中,如果读取对象内部的某个属性,为了安全我们需要判定一下该对象是否存在

    var o = {
      x:1,
      y:2
    }
    
    var a = o && o.x ;
    // => undefined
    var b = o && o.z;
    // => undefined
    

    或者使用三元运算符?:,判断一个对象是否存在

    var a = o ? o.x : 10;
    

    如上两种方式,如果层次深判断起来非常麻烦,因此ES2020引入了“链判断运算符”?.

    • 直接在链式调用的时候判断,左侧的对象是否nullundefined,如果是,就不再往下运算,返回undefined
    var o = {
      x:1,
      y:2,
      z:{
        w:3
      }
    }
    var a  = o?.z?.w;
    

    使用这个运算符,有几个注意点:
    1、短路机制

    a?.[++x];
    // 等同于
    a == null ? undefined : a[++x];
    

    如果aundefinednull,那么x不会进行递增运算,也就是说,链判断运算符一旦为真,右侧的表达式就不再求值。
    2、delete 运算符

    delete a?.b
    // 等同于
    a == null ? undefined ?  delete a.b;
    

    3、括号的影响
    如果属性链有圆括号,链判断运算符对圆括号外部没有影响,只对圆括号内部有影响。

    (a?.b).c
    // 等同于
    (a == null ? undefined : a.b).c
    

    4、报错场合(以下写法是禁止的)

    // 构造函数
    new a?.()
    new a?.b()
    // 链判断运算符的右侧有模板字符串
    a?.`{b}`
    a?.b`{c}`
    // 链判断运算符的左侧是 super
    super?.()
    super?.foo
    // 链运算符用于赋值运算符左侧
    a?.b = c
    

    5、右侧不得为十进制数值
    为了兼容以前代码,?.后边紧跟一个十进制的数组,那么?.不再被看成一个完整的运算符,而会按照三元运算符进行处理,那个小数点会归属后面的十进制数字,形成一个小数。

    a?.3:0
    // 被解析成
    a ? .3 : 0
    

    四、Null 判断运算符

    读取对象属性的时候,如果某个属性值是nullundefined,有时候需要为它们指定默认值,常见的做法是通过||运算符指定默认值。

    var o = {
      x:0,
      t:"",
      s:false
    }
    var a = o.x || 200;   // => 200
    var b = o.t || "word"; // => "word"
    var c = o.s || true;   // => true
    

    上述三行代码都是通过||运算符指定默认值,但是这样写是错误的,开发者的意愿是,只要属性的值为nullundefined,默认值就会生效,但是如果属性值为0或空字符或false,默认值也会生效。
    为了避免上述情况,ES2020引入了一个新的Null判断运算符?
    它的行为类似||,但是只有运算符左侧的值为nullundefined,才会返回右侧的值。

    var a = o.x ?? 200;     // => 0
    var b = o.t ?? "word"; // => ""
    var c = o.s ?? true;   // => false
    

    ??有一个运算符优先级问题,它与&&||的优先级孰高孰低?现在的规则是,如果多个逻辑运算符一起使用,必须用括号表明优先级,否则会报错。


    五、对象新增方法

    1、Object.is()

    ES6提出同值相等算法,在所有环境中,只要两个值是一样的,它们就应该相等,Object.is()用来比较两个值是否严格相等,与严格比较运算符===的行为基本一致。

    var o = {
      x:0,
      y:0
    }
    Object.is(o.x,o.y); // => true
    

    ===不同之处在于

    +0 === -0 //true
    NaN === NaN // false
    
    Object.is(+0, -0) // false
    Object.is(NaN, NaN) // true
    

    2、Object.assign()

    基本用法
    Object.assign方法用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。

    • 第一个参数是目标对象
    • 后面的参数都是源对象
    var target = {};
    var source = {a:1,b:2};
    Object.assign(target,source); 
    target // => {a:1, b:2, c:3}
    
    • 如果目标对象与源对象有同名属性,或多个源对象有同名属性,后面的属性会覆盖前面的属性。
    var target = {a:1,c:4};
    var source = {a:2,b:3};
    Object.assign(target,source); 
    target // => {a:2,c:4,b:3}  相同的a属性被覆盖
    
    • 如果只有一个参数,Object.assign会直接返回该参数
    var o = {a:1};
    Object.is(o,Object.assign(o)); // true
    
    • 如果该参数不是对象,则会先转成对象,然后返回
    typeof Object.assign(2) // "object"
    
    • 由于undefined和null无法转成对象,所以如果它们作为参数,直接报错。
    Object.assign(undefined); 
    Object.assign(null);
    // TypeError: Cannot convert undefined or null to object
    
    • 如果非对象参数出现在源对象的位置,这些参数会转成对象,如果无法转成对象,就会跳过。
    var o = {a: 1};
    Object.assign(obj, undefined) === obj // true
    Object.assign(obj, null) === obj // true
    

    注意点:

    • 浅拷贝
      Object.assign()实现的是浅拷贝,如果源对象的某个属性值是对象,那么目标对象拷贝得到的是这个对象的引用。
    var o1 = {a:{b:1}};
    var o2 = Object.assign({},o1);
    o2.a.b = 2;
    o1.a.b; // => 2
    
    • 同名属性的替换
    var target = {a:1,b:2};
    var source = {a:"word"};
    Object.assign(target,source);
    // {a:"word",b:2}
    
    • 数组的处理
      Object.assign()可以处理数组,但是会把数组视为对象。
    Object.assign([1, 2, 3], [4, 5])
    // [4, 5, 3]
    
    // 实际执行的是
    Object.assign({0:1,1:2,2:3},{0:4,1:5});
    // 根据同名替换原则输出的是:{0:4,1:5,2:3}
    Array.from({0:4,1:5,2:3,length:3});
    // [4,5,3]
    
    • 取值函数的处理
      Object.assign()只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
    var target = {}
    var source = {
      get x () { return 1 }
    }
    Object.assign(target,source);
    // => {x:1}
    

    常用途径:

    • 为对象添加属性
    class Point {
      constructor(x,y){
        Object.assign(this,{x,y}); // 属性的简洁表示法
      }
    }
    var point = new Point(1,2);
    // {x:1,y:2};
    point instanceof Point; // => true  point 是 类 Point 的实例
    point instanceof Object; // => true 所有对象都是Object的实例
    
    • 合并多个对象
      将对象合并后返回一个新对象
    var o1 = {x:1};
    var o2 = {y:2};
    var merge = (...sources) => Object.assign({}, ...sources); // 合并函数
    var newObj = merge(o1,o2);
    // => {x:1,y:2}
    

    3、__proto__属性

    __proto__属性(前后个两个下划线),用来读取或设置当前对象的prototype对象,目前,所有浏览器(包括IE11)都部署了这个属性。
    实现上,__proto__调用的是Object.prototype.__proto__

    该属性并没有写入ES6的正文,而是附录,原因是__proto__前后的双下划线,说明它本质是一个内部属性,而不是对外的API。因此,无论是从语义角度,还是从兼容角度,都不要使用,而是用下边的代替。
    Object.setPrototypeOf()(写入)
    Object.getPrototyprOf()(读取)
    Object.create()(生成)

    Object.setPrototypeOf()用来设置一个对象的prototype对象,返回参数本身

    • 如果第一个参数是undefinednull ,会报错。
    // 格式
    Object.setPrototypeOf(object, prototype)
    
    // 实际使用
    var p = {};
    var o = {x:1};
    Object.setPrototypeOf(o,p); // 将p对象设置为o对象的原型
    p.y = 2;
    p.z = 3;
    
    "x" in o; // => true 自有属性
    "y" in o; // => true 继承原型对象属性
    "z" in o; // => true 继承原型对象属性
    

    Object.getPrototypeOf()用来读取一个对象的原型对象

    • 如果第一个参数是undefinednull ,会报错。
    var p = {x:1};
    var o = Object.create(p);
    Object.getPrototypeOf(o);
    // {x:1}
    Object.is(Object.getPrototypeOf(o),p); 
    // true
    

    4、Object.keys()

    • 返回数组
    • 数组成员是参数对象自身所有可遍历的属性的键名
    • 不返回继承的属性
    • 可以使用for ... of 循环使用
    var o = { a:1, b:2 ,c:3};
    Object.keys(o);  // => ["a","b","c"]
    
    for (let key of Object.keys(o)) {
      console.log(key); 
    }
    // => "a"
    // => "b"
    // => "c"
    

    5、Object.values()

    • 返回数组
    • 数组成员是参数对象自身所有可遍历属性的键值
    • 不返回继承属性
    • 可以使用for ... of 循环使用
    var o = { a:1, b:2 ,c:3};
    Object.values(o);  // => [1,2,3]
    
    for (let value of Object.values(obj)) {
      console.log(value); 
    }
    // => 1
    // => 2
    // => 3
    
    • 会过滤属性名为Symbol值的属性
    Object.values({ [Symbol()]: 123, foo: 'abc' });
    // ['abc']
    
    • 如果参数是一个字符串
    Object.values('abc');
    // => ["a","b","c"]
    // 字符串会先转成一个类似数组的对象如下
    Object.keys("abc");
    // ["0","1","2"];
    Object.values({0:"a",1:"b",2:"c"});
    
    • 如果参数不是对象,会先转成对象,由于数值和布尔值的包装对象,都不会为实例添加非继承的属性,所以返回空数组
    Object.values(42); // => []
    Object.values(true); // => []
    

    6、Object.entries()

    • 返回一个数组
    • 数组成员是参数对象自身所有可编辑属性的键值对数组
    • 其他行为与Object.values()基本一致
    var o = { a:1, b:2 ,c:3};
    Object.entries(o);
    // => [["a",1],["b",2],["c",3]]
    for (let [key, value] of entries(o)) {
      console.log([key, value]); 
    }
    // => ['a', 1]
    // => ['b', 2]
    // => ['c', 3]
    

    7、Object.fromEntries()

    此方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

    Object.fromEntries([["a",1],["b",2],["c",3]]);
    // { a:1, b:2 ,c:3}
    
    • 将Map结构转为对象
    var map = new Map().set("a",1).set("b",2);
    Object.fromEntries(map);
    // {a:1,b:2}
    
    • 配合URLSearchParams对象,将查询字符串转为对象
    Object.fromEntries(new URLSearchParams('a=1&b=2'))
    // { a: "1", b:"2" }
    
    Object.fromEntries(new URLSearchParams(window.location.search))
    

    相关文章

      网友评论

        本文标题:ES6 对象的扩展和新增方法

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