对象的扩展

154 阅读3分钟

属性的简洁表示法

可直接写入变量和函数作为对象的属性和方法

let foo = '123';
let baz = { foo }; // baz——{foo: 123}
// 等同于
baz = { foo: foo };

let o = {
    method() {
        .....
    }
}
// 等同于
let o = {
    method: function () {
        .....
    }
}

如果某个方法的值是一个 Generator 函数,则需要在其前面加上星号

let obj = {
    * m() {
        yield 'hello world';
    }
}

属性名表达式

定义对象的属性有两种方法:

let obj = {};
obj.foo = true;
obj['a' + 'bc'] = 123;

表达式还可以用于定义方法名:

let obj = {
    ['h' + 'ello']() {
        return 'hi!';
    }
}

Object.is()

用来不叫你两个值是否严格相等,与( === )的行为基本一致,除了以下两点:

  • +0 不等于 -0
  • NaN等于自身
Object.is(+0, -0); // false

Object.assign()

用来将源对象的所有可枚举属性(不复制继承属性)复制到目标对象中,采用的是浅复制。如果源对象某个属性的值是对象,目标对象复制得到的是这个对象的引用。

let obj1 = {a:1};
let obj2 = Object.assign({},obj1);
obj1.a = 2;
obj2.a // 1

let obj3 = { a: { b: 1} };
let obj4 = Object.assign({}, obj3);
obj3.a.b = 2;
obj4.a.b // 2

第一个参数为目标对象,后边的参数是源对象:

  • 只有一个参数:如果该参数为对象,直接返回该参数;如果不是对象,转成对象后返回,undefined 和 null 无法转为对象,报错

    let obj = { a: 1};
    Object.assign({ a: 1 }) === obj; // true
    
  • 多个参数:源对象参数不是对象,转为对象(无法转为对象则跳过,不报错)。数值、字符串、布尔值只有字符串会以数组的形式复制到目标对象,其他值没有效果

    let v1 = 'abc';
    let v2 = true;
    let v3 = 10;
    Object.assign({}, v1, v2, v3); // {'0': 'a', '1': 'b', 2: 'c'}
    

属性的可枚举性

Object.getOwnPropertyDescriptor() 方法可以获取属性的描述对象,其中的 enumerable 属性为可枚举性。所有 Class 的原型的方法都是不可枚举的。

let obj = { foo: "123" };
Object.getOwnPropertyDescriptor(obj, 'foo');
// { configurable: true, enumerable: true, value: "123", writable: true }
Object.getOwnPropertyDescriptor(class { foo() {} }.prototype, 'foo').enumerable; // false

属性的遍历

  1. for ... in:对象自身和继承的可枚举属性(不包括 Symbol 属性)
  2. Object.keys(obj):对象自身的可枚举属性(不包括 Symbol 属性)
  3. Object.getOwnPropertyNames(obj):对象自身的所有属性(包括不可枚举属性,但不包括 Symbol 属性)
  4. Object.getOwnPropertySymbols(obj):对象自身的所有 Symbol 属性
  5. Reflect.ownKeys(obj):对象自身的所有属性(包括 Symbol 属性和不可枚举属性)

以上方法遍历属性时遵循下列顺序:

  • 首先遍历属性名为数值的属性,按照数字由小到大排序;
  • 其次遍历属性名为字符串的属性,按照对象中位置从前到后排序;
  • 最后遍历属性名为 Symbol 值的属性,按照对象中位置从前到后排序

__proto__属性、Object.setPrototypeOf()、Object.getPrototypeOf()

__proto__属性用来读取或设置当前对象的 prototype 对象。(尽量用以下两种代替)

Object.setPrototypeOf() 用来设置一个对象的 prototype 对象。参数不是对象时自动转换为对象。

Object.getPrototypeOf() 用来读取一个对象的 prototype 对象。参数不是对象时自动转换为对象。

Object.getPrototypeOf(1) === Number.prototype ; // true
Object.getPrototypeOf('foo') === String.Prototype; // true
Object.getPrototypeOf(true) === Boolean.Prototype; // true

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 返回指定对象的所有属性(不包括继承属性)的描述对象

Null 传导运算符

假如想获取对象 obj 内部的 name 属性,安全的写法是:

let name = (obj && obj.person && obj.person.user && obj.person.user.name) || 'default' ;

Null 传导运算符可以简化上述操作:

let name = obj?.person?.user?.name || 'default' ;

“ ?. ” 表示只要其中有一个返回 null 或者 undefined ,就不再继续运算,返回 undefined。

其中,有以下4种用法:

  • obj?.prop:读取对象属性
  • obj?.[prop]:读取对象属性
  • func?.(...args):函数或对象方法的调用
  • new Person?.(...args):构造函数的调用