• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
可爱熊
熊爱可
博客园    首页    新随笔    联系   管理    订阅  订阅

ES6对象的扩展

1. 属性的简洁表示法

  ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

  const foo = 'foo';

  const baz = {foo}

  baz  // {foo: 'foo'}

  上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。

  function f (x, y) {
    return {x, y};
  }

  f(1, 2)   // {x: 1, y: 2}

  es6中对象的方法可以这样写

  const o = {
    method() {
      return "Hello!";
    }
  };

  o.method()  // 'Hello!'

  function getPoint() {
    const x = 1;
    const y = 10;
    return {x, y};
  }

  getPoint()  // {x: 1, y: 10}

  简洁写法的属性名总是字符串,这会导致一些看上去比较奇怪的结果。

   let lastWord = 'last word';

  const a = {
    'first word': 'hello',
    [lastWord]: 'world!'
  }

  a['first word']  // "hello"

  a['last word']  // "world!"

  a[lastWord]  // "world!"

  属性名表达式与简洁表示法,不能同时使用,会报错。

  属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]。

  const keyA = {a: 1};

  const keyB = {b: 2};

  const myObject = {
    [keyA]: 'valueA',
    [keyB]: 'valueB'
  };

  myObject  // {[object Object]: "valueB"}

 

2. 方法的name属性  

  函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。方法的name属性返回函数名(即方法名)。

  const person = {
    sayName() {
      console.log('hello!');
    }
  }

  person.sayName.name  // "sayName"

 

3. Object.is()

  比较两个值是否严格相等

  Object.is(+0, -0);  // false

  Object.is(NaN, NaN);  // true

4. Object.assign()

  用于对象的合并,并把源对象的可枚举属性复制到目标对象中

  const target = {a: 1};

  const source1 = {b: 2};

  const source2 = {c: 3};

  Object.assign(target, source1, source2);

  target  // {a: 1, b: 2, c: 3}

  参数一,是目标对象,后面的参数都是源对象。

  如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

  const target = {
    a: 1,
    b: 2
  }

  const source1 = {
    b: 2,
    c: 2
  };

  const source2 = {
    c: 3
  }

  Object.assign(target, source1, source2)  // {a: 1, b: 2, c: 3}

 

  如果只有一个参数,Object.assign会直接返回该参数。

  const obj = {
    a: 1
  };

  Object.assign(obj)  // {a: 1}

  如果该参数不是对象,则会先转成对象,然后返回。

  typeof Object.assign(2)

  由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。

  如果undefined, null不是Object.assign()方法的首个参数, 则不会报错, 直接跳过。

  const v1 = 'abc';

  const v2 = true;

  const v3 = 10;

  const obj = Object.assign({}, v1, v2, v3);

  obj   // {0: "a", 1: "b", 2: "c"}

  只有字符串的包装对象,会产生可枚举属性。

  1)浅拷贝

    Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

    const obj1 = {a: {b: 1}};

    const obj2 = Object.assign({}, obj1);

    obj1.a.b = 2;

    obj2.a.b  // 2

  2)同名属性的替换

    一旦遇到同名属性,Object.assign的处理方法是替换,而不是添加。

    const target = {a: {b: 'c', d: 'e'}};

    const source = {a: {b: 'hello'}}

    Object.assign(target, source)  // {a: {b: 'hello'}}  对象a被整体替换掉

  3)数据的处理

    Object.assign()可以用来处理数组,但是会把数组视为对象

     Object.assign([1, 2, 3], [4, 5])  // [4, 5, 3]

    Object.assign把数组视为属性名为 0、1、2 的对象,因此源数组的 0 号属性4覆盖了目标数组的 0 号属性1。

  4)取值函数的处理

    Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。

    const source = {
      get foo() {
        return 1;
      }
    }

    const target = {}

    Object.assign({}, source)  // {foo: 1}

    source对象的foo属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值复制过去。

   5)常见用途

    ①为对象添加属性 

    class Point {
      constructor(x, y) {
        Object.assign(this, {x, y});
      }
    }  

    通过Object.assign方法,将x属性和y属性添加到Point类的对象实例。

    ②为对象添加方法

    Object.assign(Point.prototype, {
      someMethod(arg1, arg2) {
      },
      anotherMethod() {
      }
    })

    // {someMethod: ƒ, anotherMethod: ƒ, constructor: ƒ}

    ③克隆对象

    function clone (obj) {
      Object.assign({}, obj);
    }

    let origin = {
      name: 'xhk',
      age: 36
    }

    clone(origin)  // {name: "xhk", age: 36}

    将原始对象拷贝到一个空对象,就得到了原始对象的克隆。

    采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

    function clone (origin) {
      let originProto = Object.getPrototypeOf(origin);
      return Object.assign(Object.create(originProto, origin));
    }

    ④合并多个对象

    将多个对象合并到某个对象。

5. 属性的可枚举性和遍历

  有四个操作会忽略enumerable为false的属性。

  • for...in循环:只遍历对象自身的和继承的可枚举的属性。
  • Object.keys():返回对象自身的所有可枚举的属性的键名。
  • JSON.stringify():只串行化对象自身的可枚举的属性。
  • Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

6. 属性的遍历

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

  1) for ... in

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

  2)Object.keys(obj)

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

  const obj = {
    name: 'xhk',
    age: 36
  }

  Object.keys(obj)  //  ["name", "age"]

  3)Object.getOwnPropertyNames(obj)

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

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

  5)Reflect.ownKeys(obj)

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

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

  • 首先遍历所有数值键,按照数值升序排列。
  • 其次遍历所有字符串键,按照加入时间升序排列。
  • 最后遍历所有 Symbol 键,按照加入时间升序排列。

 7. Object.getOwnPropertyDescriptors()  

  对象的属性是赋值方法或取值的方法时, 在复制的时候回出现错误, Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法,就可以实现正确拷贝。

  Object.getOwnPropertyDescriptors方法的另一个用处,是配合Object.create方法,将对象属性克隆到一个新对象。这属于浅拷贝。

  let obj = {
    set foo(val) {
      console.log(val);
    }
  }

  const clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));

  Object.create() 方法会使用指定的原型对象及其属性去创建一个新的对象。

  Object.getOwnPropertyDescriptors方法可以实现一个对象继承另一个对象。以前,继承另一个对象,常常写成下面这样。

  const obj = {
    __proto__: prot,
    foo: '456'
  }

  //  {     foo:"456"

     __proto__: {

      foo:123

      __proto__:Object

       }

    }

8. __proto__ 属性(最好不要使用)

  用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括 IE11)都部署了这个属性。

  Object.setPrototypeOf()(写操作)

  Object.getPrototypeOf()(读操作)

  Object.create()(生成操作)

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

  如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。

  Object.setPrototypeOf(1, {})  // 1

  Object.setPrototypeOf('foo', {})  // 'foo'

  Object.setPrototypeOf(true, {})  // true

  Object.setPrototypeOf(undefined, {})  // 报错

  Object.setPrototypeOf(null, {})  // 报错

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

  function A() {}

  const a = new A();

  Object.getPrototypeOf(a) === A.prototype  // true

9. super关键字

  this关键字总是指向函数所在的当前对象, super关键字,指向当前对象的原型对象。

  只有下面的写法可以让Javascript引擎确认:

  const obj3 = {
    foo() {
      return super.foo
    }
  }

  const obj = {
    foo: super.foo
  }  // 报错

  const obj1 = {
    foo: () => super.foo
  } // 报错

  const obj2 = {
    foo: function () {
      return super.foo;
    }
  }  // 报错

  const proto = {
    x: 'hello',
      foo() {
       console.log(this.x);
      }
  }

  const obj = {
    x: 'world',
    foo() {
      super.foo();
    }
  }

  Object.setPrototypeOf(obj, proto);

  obj.foo()  // 'world'

  扩展运算符的解构赋值,不能复制继承自原型对象的属性。

  let o1 = {a: 1}

  let o2 = {b: 2}

  o2.__proto__ = o1;

  let {...o3} = o2

  o3.b // 2

  o3.a // undefined 

  扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。  

  let z = {a: 3, b: 4}

  let n = {...z}

  n   // {a: 3, b: 4}

  上面的例子只是拷贝了对象实例的属性,如果想完整克隆一个对象,还拷贝对象原型的属性,可以采用下面的写法。

  let obj = {
    find() {},
    foo: 'foo'
  }

  const clone2 = Object.assign(
    Object.create(Object.getPrototypeOf(obj)),
    obj
  )

   扩展运算符可以用于合并两个对象

  const a = {
    name: 'xhk'
  }

  const b = {
    wife: 'coco'
  }

  let ab = {...a, ...b}

  ab // {name: 'xhk', wife: 'coco'}

  let cd = Object.assign({}, a, b);

  cd // {name: 'xhk', wife: 'coco'}

  let x = 1;

  let y = 2;

  const z = {
    x = 0;
  }

  const a = {...z, x, y}

  const obj = {
    name: 'xhk',
    age: 36,
    wife: 'coco'
  }

  let b = {
    ...obj,
    age: 24
  }

  b   // {name: "xhk", age: 24, wife: "coco"}

10. Null传导运算符(?.)

  如果读取对象内部的某个属性,往往需要判断一下该对象是否存在。

  const firstName = message?.body?.user?.firstName || 'default'

  等同于

  const firstName = (message && message.body&& message.body.user && message.body.user.firstName) || 'default'

   上面代码有三个?.运算符,只要其中一个返回null或undefined,就不再往下运算,而是返回undefined。

 

是不是你的耳朵是圆的,我的话是方的,所以你听不进去呀。
posted @ 2018-01-23 16:23  熊小可  阅读(130)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3