1. 10. Object.keys() Object.values() Object.entries()
    1. keys() 返回一个数组, 成员是参数对象自身的(不含继承的) 所有可遍历(enumerable)属性的键名。
      1. var obj = { foo: 'bar', baz: 42 }; Object.keys(obj) // ["foo", "baz"]
      2. let {keys, values, entries} = Object; let obj = { a: 1, b: 2, c: 3 }; for (let key of keys(obj)) { console.log(key); // 'a', 'b', 'c' } for (let value of values(obj)) { console.log(value); // 1, 2, 3 } for (let [key, value] of entries(obj)) { console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3] }
    2. values() 方法返回一个数组,成员是参数对象自身的 (不含继承的)所有可遍历(enumerable)属性的键值。
      1. const obj = { 100: 'a', 2: 'b', 7: 'c' }; Object.values(obj) // ["b", "c", "a"]
      2. const obj = Object.create({}, {p: {value: 42}}); Object.values(obj) // []
      3. const obj = Object.create({}, {p: { value: 42, enumerable: true } }); Object.values(obj) // [42]
    3. entries() 方法返回一个数组, 成员是参数对象自身的(不含继承的) 所有可遍历(enumerable)属性的键值对数组。
      1. let obj = { one: 1, two: 2 }; for (let [k, v] of Object.entries(obj)) { console.log( `${JSON.stringify(k)}: ${JSON.stringify(v)}` ); } // "one": 1 // "two": 2
  2. 11. 对象的扩展运算符(...)
    1. 1 解构赋值
      1. const [a, ...b] = [1, 2, 3]; a // 1 b // [2, 3]
      2. let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
    2. (2)扩展运算符 扩展运算符(...)用于取出参数对象的所有可遍历属性, 拷贝到当前对象之中。
      1. let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 }
      2. let aClone = { ...a }; // 等同于 let aClone = Object.assign({}, a);
  3. 1. 属性的简介写法
    1. const foo = 'bar'; const baz = {foo}; baz // {foo: "bar"} // 等同于 const baz = {foo: foo};
    2. function getPoint() { const x = 1; const y = 10; return {x, y}; }
    3. 允许直接写入变量和函数,作为对象的属性和方法
  4. 2. 属性名表达式
    1. 方法一是直接用标识符作为属性名,
      1. // 方法一 obj.foo = true; // 方法二 obj['a' + 'bc'] = 123;
    2. 方法二是用表达式作为属性名,这时要将表达式放在方括号之内。
      1. let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123 };
    3. 允许把表达式放在括号内
      1. let lastWord = 'last word'; const a = { 'first word': 'hello', [lastWord]: 'world' }; a['first word'] // "hello" a[lastWord] // "world" a['last word'] // "world"
    4. 表达式可以用于定义方法名
      1. let obj = { ['h' + 'ello']() { return 'hi'; } }; obj.hello() // hi
    5. 注意,属性名表达式与简洁表示法,不能同时使用,会报错。
      1. // 报错 const foo = 'bar'; const bar = 'abc'; const baz = { [foo] }; // 正确 const foo = 'bar'; const baz = { [foo]: 'abc'};
    6. 注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心
      1. const keyA = {a: 1}; const keyB = {b: 2}; const myObject = { [keyA]: 'valueA', [keyB]: 'valueB' }; myObject // Object {[object Object]: "valueB"}
  5. 3. 方法的name属性
    1. 返回函数名 xxx.funcxx.name
      1. const person = { sayName() { console.log('hello!'); }, }; person.sayName.name // "sayName"
    2. getter setter函数名取值方法 xxx.get.name
      1. const obj = { get foo() {}, set foo(x) {} }; obj.foo.name // TypeError: Cannot read property 'name' of undefined const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo'); descriptor.get.name // "get foo" descriptor.set.name // "set foo"
    3. bind方法的name
      1. doSomething.bind().name // "bound doSomething"
    4. function构造函数创造的函数 -返回anonymous
      1. (new Function()).name // "anonymous"
  6. 4. Object.is() 比较两个值是否相等
    1. 同值相等
      1. Object.is('foo', 'foo') // true Object.is({}, {}) // false
    2. 不同之处只有两个: 一是+0不等于-0, 二是NaN等于自身。
      1. +0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
    3. 源代码
      1. Object.defineProperty(Object, 'is', { value: function(x, y) { if (x === y) { // 针对+0 不等于 -0的情况 return x !== 0 || 1 / x === 1 / y; } // 针对NaN的情况 return x !== x && y !== y; }, configurable: true, enumerable: false, writable: true });
  7. 5. Object.assign 对象合并
    1. 将源对象的所有可枚举属性, 复制到目标对象
      1. const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
    2. 注意,如果目标对象与源对象有同名属性, 或多个源对象有同名属性, 则后面的属性会覆盖前面的属性。
      1. const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
    3. 如果只有一个参数, Object.assign会直接返回该参数。
      1. const obj = {a: 1}; Object.assign(obj) === obj // true
    4. 如果该参数不是对象,则会先转成对象
      1. typeof Object.assign(2) // "object"
      2. 由于undefined和null无法转成对象, 所以如果它们作为参数,就会报错
        1. Object.assign(undefined) // 报错 Object.assign(null) // 报错
      3. 如果undefined和null不在首参数,就不会报错
        1. let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true
    5. 拷贝属性
      1. 只拷贝源对象的自身属性(不拷贝继承属性invisible), 也不拷贝不可枚举的属性(enumerable: false)
      2. 注意点
        1. 浅拷贝
          1. Object.assign属于浅拷贝, 即如果源对象某个属性的值是对象, 那么目标对象拷贝得到的是这个对象的引用。
          2. const obj1 = {a: {b: 1}}; const obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2
        2. 同名属性的替换
          1. const target = { a: { b: 'c', d: 'e' } } const source = { a: { b: 'hello' } } Object.assign(target, source) // { a: { b: 'hello' } }
        3. 数组的处理
          1. Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
        4. (4)取值函数的处理
          1. const source = { get foo() { return 1 } }; const target = {}; Object.assign(target, source) // { foo: 1 }
    6. 常见用途
      1. 1. 为对象添加属性
        1. class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
      2. (2)为对象添加方法
        1. Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同于下面的写法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
      3. (3)克隆对象
        1. function clone(origin) { return Object.assign({}, origin); }
        2. 深度克隆,保持原型链方法
          1. function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
      4. (4)合并多个对象
        1. 返回旧的对象 const merge = (target, ...sources) => Object.assign(target, ...sources);
        2. 返回新的对象 const merge = (...sources) => Object.assign({}, ...sources);
      5. (5)为属性指定默认值
        1. const DEFAULTS = { logLevel: 0, outputFormat: 'html' }; function processContent(options) { options = Object.assign({}, DEFAULTS, options); console.log(options); // ... }
        2. 防止属性值被覆盖
          1. const DEFAULTS = { url: { host: 'example.com', port: 7070 }, }; processContent({ url: {port: 8000} }) // { // url: {port: 8000} // }
  8. 6. 属性的可枚举性和遍历
    1. 可枚举性
      1. 枚举描述对象 Object.getOwnPropertyDescriptor
      2. enumerable 可枚举属性
      3. 四个操作会忽略枚举属性
        1. for...in 自身和继承可枚举
        2. Object.keys() 自身可枚举键名
        3. JSON.stringify() 对象自身可枚举
        4. Object.assign() 拷贝自身可枚举
    2. 可遍历
      1. (1) for...in 遍历自身和继承
      2. (2) Object.keys(obj) 遍历自身
      3. (3) Object.getOwnPropertyNames(obj) 遍历自身
      4. (4) Object.getOwnPropertySymbols 自身symbol
      5. (5)Reflect.ownKeys(obj) 返回自身所有属性包括symbol和不可枚举属性和普通
  9. 7. Object.getOwnPropertyDescriptors()
    1. 带了S, 返回对象所有自身属性
      1. 实现代码
        1. function getOwnPropertyDescriptors(obj) { const result = {}; for (let key of Reflect.ownKeys(obj)) { result[key] = Object.getOwnPropertyDescriptor(obj, key); } return result; }
    2. 不带S 返回单个属性 Object.getOwnPropertyDescriptor(target,obj)
    3. 引入目的,解决Object.assign()无法正确拷贝get和set属性的问题
      1. const source = { set foo(value) { console.log(value); } }; const target2 = {}; Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source)); Object.getOwnPropertyDescriptor(target2, 'foo') // { get: undefined, // set: [Function: foo], // enumerable: true, // configurable: true }
      2. 优化写法 const shallowMerge = (target, source) => Object.defineProperties( target, Object.getOwnPropertyDescriptors(source) );
    4. +create 将对象克隆到新对象(浅拷贝)
      1. const clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)); // 或者 const shallowClone = (obj) => Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) );
  10. 8. __proto__属性
    1. Object.setPrototypeOf()
      1. 用来设置一个对象的prototype对象, 返回参数对象本身 推荐使用
        1. // 格式 Object.setPrototypeOf(object, prototype) // 用法 const o = Object.setPrototypeOf({}, null);
        2. let proto = {}; let obj = { x: 10 }; Object.setPrototypeOf(obj, proto); proto.y = 20; proto.z = 40; obj.x // 10 obj.y // 20 obj.z // 40
      2. 如果第一个参数不是对象, 会自动转为对象,函数还是返回第一个对象, 转不了则报错
        1. Object.setPrototypeOf(undefined, {}) // TypeError: Object.setPrototypeOf called on null or undefined Object.setPrototypeOf(null, {}) // TypeError: Object.setPrototypeOf called on null or undefined
        2. Object.setPrototypeOf(1, {}) === 1 // true Object.setPrototypeOf('foo', {}) === 'foo' // true Object.setPrototypeOf(true, {}) === true // true
    2. Object.getPrototypeOf()
      1. 用于读取一个对象的原型对象。
        1. function Rectangle() { // ... } const rec = new Rectangle(); Object.getPrototypeOf(rec) === Rectangle.prototype // true Object.setPrototypeOf(rec, Object.prototype); Object.getPrototypeOf(rec) === Rectangle.prototype // false
      2. 如果不是对象则会自动转为对象
        1. // 等同于 Object.getPrototypeOf(Number(1)) Object.getPrototypeOf(1) // Number {[[PrimitiveValue]]: 0} // 等同于 Object.getPrototypeOf(String('foo')) Object.getPrototypeOf('foo') // String {length: 0, [[PrimitiveValue]]: ""} // 等同于 Object.getPrototypeOf(Boolean(true)) Object.getPrototypeOf(true) // Boolean {[[PrimitiveValue]]: false} Object.getPrototypeOf(1) === Number.prototype // true Object.getPrototypeOf('foo') === String.prototype // true Object.getPrototypeOf(true) === Boolean.prototype // true
    3. __proto__
      1. 用来读取当前对象的prototype属性
        1. // es6 的写法 const obj = { method: function() { ... } }; obj.__proto__ = someOtherObj; // es5 的写法 var obj = Object.create(someOtherObj); obj.method = function() { ... };
  11. 9. SUPER关键字
    1. 指向当前对象的原型对象
      1. const proto = { x: 'hello', foo() { console.log(this.x); }, }; const obj = { x: 'world', foo() { super.foo(); } } Object.setPrototypeOf(obj, proto); obj.foo() // "world"
  12. 12. NULL 传导运算符
    1. const firstName = (message && message.body && message.body.user && message.body.user.firstName) || 'default';
    2. 四种写法
      1. obj?.prop // 读取对象属性 obj?.[expr] // 同上 func?.(...args) // 函数或对象方法的调用 new C?.(...args) // 构造函数的调用