Object.assign()

  • 用于将所有可枚举属性(属性能否被for…in查找遍历到)的值从一个或多个源对象复制到目标对象,返回目标对象

  • 语法:

    1
    
    Object.assign(target, ...sources)
    

    target目标对象;source源对象

  • 如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的属性。

  • 只会拷贝源对象自身的并且可枚举的属性到目标对象。

  • 为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()Object.defineProperty()。深拷贝?

  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    // 复制一个对象
    const obj = { a: 1 };
    const copy = Object.assign({}, obj);
    console.log(copy); // { a: 1 }
    
    // 合并对象
    const o1 = { a: 1 };
    const o2 = { b: 2 };
    const o3 = { c: 3 };
    
    const obj = Object.assign(o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
    
    // 合并具有相同属性的对象
    const o1 = { a: 1, b: 1, c: 1 };
    const o2 = { b: 2, c: 2 };
    const o3 = { c: 3 };
    
    const obj = Object.assign({}, o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    
    // 继承属性和不可枚举属性是不能拷贝的
    const obj = Object.create({foo: 1}, { // foo 是个继承属性。
        bar: {
            value: 2  // bar 是个不可枚举属性。
        },
        baz: {
            value: 3,
            enumerable: true  // baz 是个自身可枚举属性。
        }
    });
    
    const copy = Object.assign({}, obj);
    console.log(copy); // { baz: 3 }
    
  • 深拷贝问题

    针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    let obj = { a: 0 , b: { c: 0}}; 
    let copy = Object.assign({}, obj1); 
    console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 
    
    // 改变源对象属性值,拷贝的属性值不变
    obj.a = 1; 
    console.log(JSON.stringify(obj)); // { a: 1, b: { c: 0}} 
    console.log(JSON.stringify(copy)); // { a: 0, b: { c: 0}} 
    
    // 改变拷贝的属性值,也不会改变源对象的属性值
    copy.a = 2; 
    console.log(JSON.stringify(obj)); // { a: 1, b: { c: 0}} 
    console.log(JSON.stringify(copy)); // { a: 2, b: { c: 0}}
    
    // 改变拷贝对象中的深层属性值,将会彻底改变该属性值
    copy.b.c = 3; 
    console.log(JSON.stringify(obj)); // { a: 1, b: { c: 3}} 
    console.log(JSON.stringify(copy)); // { a: 2, b: { c: 3}} 
    
    // Deep Clone 
    obj = { a: 0 , b: { c: 0}}; 
    let depClone = JSON.parse(JSON.stringify(obj1)); 
    obj.a = 4; 
    obj.b.c = 4; 
    console.log(JSON.stringify(depClone)); // { a: 0, b: { c: 0}}
    

Object.is()

  • 判断两个值是否是相同的值,返回布尔值

  • 语法:

    1
    
    Object.is(value1, value2)
    
  • 在以下情况下,返回true

    • 两个值均为undefinednulltruefalse
    • 两个值都是由相同个字符按照相同顺序组成的字符串
    • 两个值都指向同一个对象
    • 两个值都是数字并且
      • 都是正零+0或负零-0
      • 都是NaN
      • 都是除零和NaN外的其它同一个数字
  • ==运算符的区别

    这种相等性判断逻辑和传统的 ==运算不同,==运算符会对它两边的操作数做隐式类型转换(如果它们类型不同),然后才进行相等性比较,(所以才会有类似 "" == false 返回 true 的现象),但 Object.is 不会做这种类型转换。Object.is()比较严格。

    这与===运算符的判定方式也不一样。===运算符(和==运算符)将数字值 -0+0 视为相等,并认为 Number.NaN不等于NaN

  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    Object.is('foo', 'foo');     // true
    Object.is(window, window);   // true
    
    Object.is('foo', 'bar');     // false
    Object.is([], []);           // false 与两个对象同理 指向不同
    
    const foo = { a: 1 };
    const bar = { a: 1 };
    Object.is(foo, foo);         // true
    Object.is(foo, bar);         // false 指向不同
    
    Object.is(null, null);       // true
    
    // 特例
    Object.is(0, -0);            // false
    Object.is(0, +0);            // true
    Object.is(-0, -0);           // true
    Object.is(NaN, 0/0);         // true
    

Object.prototype.hasOwnProperty()

  • 判断对象自身属性中是否具有指定属性(是否有指定的键)

  • 语法:

    1
    
    obj.hasOwnProperty(prop)
    

    prop要检测的属性的String字符串形式表示的名称,或者Symbol

  • 所有继承了Object的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和in运算符不同,该方法会忽略掉那些从原型链上继承到的属性。

  • 即使属性的值是 nullundefined,只要属性存在,hasOwnProperty 依旧会返回 true

  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    o = new Object();
    o.hasOwnProperty('prop'); // 返回 false
    o.prop = 'exists';
    o.hasOwnProperty('prop'); // 返回 true
    
    // 对待自身属性和继承属性的区别:
    o = new Object();
    o.prop = 'exists';
    o.hasOwnProperty('prop');             // 返回 true
    o.hasOwnProperty('toString');         // 返回 false
    o.hasOwnProperty('hasOwnProperty');   // 返回 false
    

Object.keys()

  • 会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用for...in循环遍历该对象时返回的顺序一致。

  • 语法:

    1
    
    Object.keys(obj)
    
  • 返回一个表示给定对象的所有可枚举属性的字符串数组

  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    // 对于简单的数组
    const arr = ['a', 'b', 'c'];
    console.log(Object.keys(arr)); // console: ['0', '1', '2']
    
    // 类数组对象
    const obj = { 0: 'a', 1: 'b', 2: 'c' };
    console.log(Object.keys(obj)); // console: ['0', '1', '2']
    
    // key的顺序随机的对象,会排序后返回
    const anObj = { 100: 'a', 2: 'b', 7: 'c' };
    console.log(Object.keys(anObj)); // console: ['2', '7', '100']
    
    // getFoo是一个不可枚举的属性
    let myObj = Object.create({}, {
      getFoo: {
        value: function () { return this.foo; }
      } 
    });
    myObj.foo = 1;// myObj = { foo: 1, getFoo: funtion }
    console.log(Object.keys(myObj)); // console: ['foo']
    

Object.getOwnPropertyNames()

  • 与Object.keys()方法类似,但更强大。

  • 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。

  • 语法:

    1
    
    Object.getOwnPropertyNames(obj)
    
  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    // 对于简单的数组
    const arr = ["a", "b", "c"];
    console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"] // 居然还有length...
    
    // 类数组对象
    var obj = { 0: "a", 1: "b", 2: "c"};
    console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
    
    // 使用Array.forEach输出属性名和属性值
    Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
      console.log(val + " -> " + obj[val]);
    });
    // 输出
    // 0 -> a
    // 1 -> b
    // 2 -> c
    
    //不可枚举属性
    var my_obj = Object.create({}, {
      getFoo: {
        value: function() { return this.foo; },
        enumerable: false
      }
    });
    my_obj.foo = 1;
    
    console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]
    

Object.values()

  • 会返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同(区别在于for...in循环枚举原型链中的属性)。与Object.keys()十分相似。

  • 语法:

    1
    
    Object.values(obj)
    
  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    // 对于一般对象
    const obj = { foo: 'bar', baz: 42 };
    console.log(Object.values(obj)); // ['bar', 42]
    
    // 对于类数组对象
    const obj = { 0: 'a', 1: 'b', 2: 'c' };
    console.log(Object.values(obj)); // ['a', 'b', 'c']
    
    // 键顺序随机的类数组对象
    // 键的数字顺序决定返回值在数组中的顺序 
    const an_obj = { 100: 'a', 2: 'b', 7: 'c' };
    console.log(Object.values(an_obj)); // ['b', 'c', 'a']
    
    // getFoo是一个不可枚举属性
    let my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } });
    my_obj.foo = 'bar';
    console.log(Object.values(my_obj)); // ['bar']
    
    // 非对象作为参数将被强制转换为对象 
    console.log(Object.values('foo')); // ['f', 'o', 'o']
    

Object.getOwnPropertyDescriptor()

  • 方法返回指定对象中的一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

  • 语法:

    1
    
    Object.getOwnPropertyDescriptor(obj, prop)
    

    obj需要查找的目标对象;prop目标对象内的属性名称

  • 如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回undefined

  • 在 Javascript 中, 属性由一个字符串类型的“名字”(name)和一个“属性描述符”(property descriptor)对象构成。一个属性描述符是一个记录,由下面属性当中的某些组成的:

    • value:该属性的值
    • writable:当且仅当属性的值可以被改变时为true
    • get:获取该属性的访问器函数(getter)
    • set:获取该属性的设置器函数(setter)
    • configurable:当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为true
    • eunmerable:当且仅当指定对象的属性可以被枚举出时,为true
  • 示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    var o = { get foo() { return 17; } };
    var d = Object.getOwnPropertyDescriptor(o, "foo");
    // d {
    //   configurable: true,
    //   enumerable: true,
    //   get: /*the getter function*/,
    //   set: undefined
    // }
    
    var o = { bar: 42 };
    var d = Object.getOwnPropertyDescriptor(o, "bar");
    // d {
    //   configurable: true,
    //   enumerable: true,
    //   value: 42,
    //   writable: true
    // }