01、object對(duì)象(屬性 + 方法 Object.assign()、Object.create())

01、屬性 -------

01、Object.prototype屬性表示object的原型對(duì)象
幾乎所有的javascript對(duì)象都是 Object 實(shí)例,一個(gè)典型的對(duì)象繼承了 Object.prototype 的屬性(包括方法),盡管這些屬性被覆蓋。然而,一個(gè) Object 可能是故意創(chuàng)建的,這是不確定的(例如通過(guò)Object.create(null) 或者它可能被改變,所以這不再是準(zhǔn)確的(例如Object.prototypeOf)

Object原型的改變會(huì)傳播到所有對(duì)象上,除非這些屬性和方法被其他對(duì)原型鏈更里層的改動(dòng)所覆蓋。這提供了一個(gè)非常強(qiáng)大的,但有潛在危險(xiǎn)的機(jī)制來(lái)覆蓋或擴(kuò)展對(duì)象行為。
屬性:
----Object.prototype.constructor----所有對(duì)象都會(huì)從它的原型上繼承一個(gè) constructor 屬性

    /*json*/
    var obj = {}
    console.log( obj.constructor === Object) // true
    /*object*/
    var obj1 = new Object()
    console.log( obj1.constructor === Object) // true
    /*array*/
    var arr = []
    console.log( arr.constructor === Array) // true
    console.log( arr.constructor === Object) // false
    /*array*/
    var arr1 = new Array()
    console.log( arr1.constructor === Array) // true
    /*Number*/
    var n = new Number(3);
    var n1 = 3
    console.log( n.constructor === Number) // true
    console.log( n.constructor === Array) // false
    console.log( n1.constructor === Number) // true
    /*打印一個(gè)對(duì)象的構(gòu)造函數(shù)*/
    function One(name) {
        this.name = name
    }
    var one = new One('夜幕小草')
    console.log(one)
    console.log(one.constructor)
    console.log(one.name)

image.png

----Object.prototype.proto-有待研究

02、方法

-- 01、Object.assign() 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。

語(yǔ)法:
Object.assign(target, ...sources)
target:目標(biāo)對(duì)象
sources: 源對(duì)象
返回值: 目標(biāo)對(duì)象

描述:如果目標(biāo)對(duì)象中的屬性具有相同的鍵,則屬性將被源中的屬性覆蓋。后來(lái)的源的屬性將類似地覆蓋早先的屬性。
Object.assign 方法只會(huì)拷貝源對(duì)象自身的并且可枚舉的屬性到目標(biāo)對(duì)象。該方法使用源對(duì)象的[[Get]]和目標(biāo)對(duì)象的[[Set]],所以它會(huì)調(diào)用相關(guān) getter 和 setter。因此,它分配屬性,而不僅僅是復(fù)制或定義新的屬性。如果合并源包含getter,這可能使其不適合將新屬性合并到原型中。為了將屬性定義(包括其可枚舉性)復(fù)制到原型,應(yīng)使用Object.getOwnPropertyDescriptor() 和 Object.defineProperty()。

String類型和Symbol類型的屬性都會(huì)被拷貝。
在出現(xiàn)錯(cuò)誤的情況下,例如,如果屬性不可寫,會(huì)引發(fā)TypeError,如果在引發(fā)錯(cuò)誤之前添加了任何屬性,則可以更改target對(duì)象。
注意,Object.assign 會(huì)跳過(guò)那些值為null和nudefined的源對(duì)象

/*復(fù)制一個(gè)對(duì)象*/
    var obj2 = {a: 1, b: 2}
    var copy = Object.assign({}, obj2)
    console.log(obj2)
    console.log(copy)
    console.log(obj2 === copy)
image.png

深拷貝問(wèn)題

深拷貝問(wèn)題
針對(duì)深拷貝,需要使用其他方法,因?yàn)?Object.assign 拷貝的是屬性值。假如源對(duì)象的屬性值是一個(gè)指向?qū)ο蟮囊茫仓豢截惸莻€(gè)引用值。
    /*深拷貝問(wèn)題*/
    function test(){
        var ob1 = { a: 0, b: {c: 0}}
        var ob2 = Object.assign({}, ob1)
        console.log(JSON.stringify(ob1)) //{"a":0,"b":{"c":0}}
        console.log(JSON.stringify(ob2)) //{"a":0,"b":{"c":0}}

        ob2.a = 5
        console.log(JSON.stringify(ob1)) //{"a":0,"b":{"c":0}}
        console.log(JSON.stringify(ob2)) //{"a":5,"b":{"c":0}}

        ob2.b.c = 12
        console.log(JSON.stringify(ob1)) //{"a":0,"b":{"c":12}}
        console.log(JSON.stringify(ob2)) //{"a":5,"b":{"c":12}}

        var obb1 = { a: 0, b: {c: 0}}
        var obb3 = JSON.parse(JSON.stringify(obb1))
        obb3.a = 4
        obb3.b.c = 4
        console.log(JSON.stringify(obb1)) //{"a":0,"b":{"c":0}}
        console.log(JSON.stringify(obb3)) //{"a":4,"b":{"c":4}}
    }

    test()

合并對(duì)象

    var o1 = {a: 1}
    var o2 = {b: 2}
    var o3 = {c: 3}

    var o123 = Object.assign(o1, o2, o3)
    console.log(o1)  //{a: 1, b: 2, c: 3}  注意目標(biāo)對(duì)象自身也會(huì)改變
    console.log(o2)  //{b: 2}
    console.log(o3)  //{c: 3}
    console.log(o123) //{a: 1, b: 2, c: 3}
/*合并具有相同屬性的對(duì)象*/
var a1 = {a: 1, b: 1, c:1}
var a2 = {b: 2, c:3}
var a3 = {a: 5, c:4}

var a123 = Object.assign({}, a1, a2, a3)
console.log(a123) //{a: 5, b: 2, c: 4} 屬性被后續(xù)參數(shù)中具有相同屬性的其他對(duì)象覆蓋。
拷貝 symbol 類型的屬性
/*拷貝 symbol 類型的屬性*/
var b1 = { a: 1 };
var b2 = { [Symbol('foo')]: 2 };

var b12 = Object.assign({}, b1, b2);
console.log(b12); // {a: 1, Symbol(foo): 2}
console.log(Object.getOwnPropertySymbols(b12)); // [Symbol(foo)]
    /*繼承屬性和不可枚舉屬性是不能拷貝的*/
    var c1 = Object.create({foo: 1}, { // foo 是個(gè)繼承屬性。
        bar: {
            value: 2  // bar 是個(gè)不可枚舉屬性。
        },
        baz: {
            value: 3,
            enumerable: true  // baz 是個(gè)自身可枚舉屬性。
        }
    });

    var c2 = Object.assign({}, c1);
    console.log(c1); // {baz: 3, bar: 2}
    console.log(c1.foo) // 1
    console.log(c2); // { baz: 3 }

    var c4 = Object.create(null)
    c4.k = 5
    console.log(c4) //{k: 5}
    var c5 = Object.assign({}, c4)
    console.log(c5) //{k: 5}
/*原始類型會(huì)被包裝為對(duì)象*/
    var v1 = "abc";
    var v2 = true;
    var v3 = 10;
    var v4 = Symbol("foo")
    var kk = {k: 9}
    var obj = Object.assign({}, v1, null, v2, undefined, v3, v4, kk); 
    // 原始類型會(huì)被包裝,null 和 undefined 會(huì)被忽略。
    // 注意,只有字符串的包裝對(duì)象才可能有自身可枚舉屬性。
    console.log(obj); // { "0": "a", "1": "b", "2": "c", "k": 9 }

異常會(huì)打斷后續(xù)拷貝任務(wù)

var target = Object.defineProperty({}, "foo", {
    value: 1,
    writable: false
}); // target 的 foo 屬性是個(gè)只讀屬性。

Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意這個(gè)異常是在拷貝第二個(gè)源對(duì)象的第二個(gè)屬性時(shí)發(fā)生的。

console.log(target.bar);  // 2,說(shuō)明第一個(gè)源對(duì)象拷貝成功了。
console.log(target.foo2); // 3,說(shuō)明第二個(gè)源對(duì)象的第一個(gè)屬性也拷貝成功了。
console.log(target.foo);  // 1,只讀屬性不能被覆蓋,所以第二個(gè)源對(duì)象的第二個(gè)屬性拷貝失敗了。
console.log(target.foo3); // undefined,異常之后 assign 方法就退出了,第三個(gè)屬性是不會(huì)被拷貝到的。
console.log(target.baz);  // undefined,第三個(gè)源對(duì)象更是不會(huì)被拷貝到的。

拷貝訪問(wèn)器

var obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

var copy = Object.assign({}, obj); 
// { foo: 1, bar: 2 }
// copy.bar的值來(lái)自obj.bar的getter函數(shù)的返回值 
console.log(copy); 

// 下面這個(gè)函數(shù)會(huì)拷貝所有自有屬性的屬性描述符
function completeAssign(target, ...sources) {
  sources.forEach(source => {
    let descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});

    // Object.assign 默認(rèn)也會(huì)拷貝可枚舉的Symbols
    Object.getOwnPropertySymbols(source).forEach(sym => {
      let descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

---02、Object.create() 方法會(huì)使用指定的原型對(duì)象及其屬性去創(chuàng)建一個(gè)新的對(duì)象。

語(yǔ)法:
Object.create(proto[, propertiesObject])
proto: 新創(chuàng)建對(duì)象的原型對(duì)象。
propertiesObject: 可選。如果沒(méi)有指定為undefined,則是要添加到新創(chuàng)建對(duì)象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對(duì)象的屬性描述符以及相應(yīng)的屬性名稱。這些屬性對(duì)應(yīng)Object.definedProperties()的第二個(gè)參數(shù)
返回值:在指定原型對(duì)象上添加新屬性后的對(duì)象
例外:如果proto參數(shù)不是null或者一個(gè)對(duì)象,則拋出一個(gè)TypeError異常
// Shape - superclass
function Shape() {
    this.x = 2;
    this.y = 3;
}

// superclass method
Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
    console.info('Shape moved.');
    console.log(this.x)
    console.log(this.y)
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.  繼承了屬性
}

var rr = new Rectangle()
console.log(rr.x)  // 2

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.' 3 4
如果你希望能繼承到多個(gè)對(duì)象,則可以使用混入的方式。
function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// inherit one class
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// re-assign constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do a thing
};

---使用 Object.create 的 propertyObject參數(shù)

var o;

// 創(chuàng)建一個(gè)原型為null的空對(duì)象
o = Object.create(null);


o = {};
// 以字面量方式創(chuàng)建的空對(duì)象就相當(dāng)于:
o = Object.create(Object.prototype);


o = Object.create(Object.prototype, {
  // foo會(huì)成為所創(chuàng)建對(duì)象的數(shù)據(jù)屬性
  foo: { 
    writable:true,
    configurable:true,
    value: "hello" 
  },
  // bar會(huì)成為所創(chuàng)建對(duì)象的訪問(wèn)器屬性
  bar: {
    configurable: false,
    get: function() { return 10 },
    set: function(value) {
      console.log("Setting `o.bar` to", value);
    }
  }
});


function Constructor(){}
o = new Constructor();
// 上面的一句就相當(dāng)于:
o = Object.create(Constructor.prototype);
// 當(dāng)然,如果在Constructor函數(shù)中有一些初始化代碼,Object.create不能執(zhí)行那些代碼


// 創(chuàng)建一個(gè)以另一個(gè)空對(duì)象為原型,且擁有一個(gè)屬性p的對(duì)象
o = Object.create({}, { p: { value: 42 } })

// 省略了的屬性特性默認(rèn)為false,所以屬性p是不可寫,不可枚舉,不可配置的:
o.p = 24
o.p
//42

o.q = 12
for (var prop in o) {
   console.log(prop)
}
//"q"

delete o.p
//false

//創(chuàng)建一個(gè)可寫的,可枚舉的,可配置的屬性p
o2 = Object.create({}, {
  p: {
    value: 42, 
    writable: true,
    enumerable: true,
    configurable: true 
  } 
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。