01、屬性 -------
01、Object.prototype屬性表示object的原型對象
幾乎所有的javascript對象都是 Object 實例,一個典型的對象繼承了 Object.prototype 的屬性(包括方法),盡管這些屬性被覆蓋。然而,一個 Object 可能是故意創(chuàng)建的,這是不確定的(例如通過Object.create(null) 或者它可能被改變,所以這不再是準確的(例如Object.prototypeOf)
Object原型的改變會傳播到所有對象上,除非這些屬性和方法被其他對原型鏈更里層的改動所覆蓋。這提供了一個非常強大的,但有潛在危險的機制來覆蓋或擴展對象行為。
屬性:
----Object.prototype.constructor----所有對象都會從它的原型上繼承一個 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òu)造函數(shù)*/
function One(name) {
this.name = name
}
var one = new One('夜幕小草')
console.log(one)
console.log(one.constructor)
console.log(one.name)

----Object.prototype.proto-有待研究
02、方法
-- 01、Object.assign() 方法用于將所有可枚舉屬性的值從一個或多個源對象復(fù)制到目標對象。它將返回目標對象。
語法:
Object.assign(target, ...sources)
target:目標對象
sources: 源對象
返回值: 目標對象
描述:如果目標對象中的屬性具有相同的鍵,則屬性將被源中的屬性覆蓋。后來的源的屬性將類似地覆蓋早先的屬性。
Object.assign 方法只會拷貝源對象自身的并且可枚舉的屬性到目標對象。該方法使用源對象的[[Get]]和目標對象的[[Set]],所以它會調(diào)用相關(guān) getter 和 setter。因此,它分配屬性,而不僅僅是復(fù)制或定義新的屬性。如果合并源包含getter,這可能使其不適合將新屬性合并到原型中。為了將屬性定義(包括其可枚舉性)復(fù)制到原型,應(yīng)使用Object.getOwnPropertyDescriptor() 和 Object.defineProperty()。
String類型和Symbol類型的屬性都會被拷貝。
在出現(xiàn)錯誤的情況下,例如,如果屬性不可寫,會引發(fā)TypeError,如果在引發(fā)錯誤之前添加了任何屬性,則可以更改target對象。
注意,Object.assign 會跳過那些值為null和nudefined的源對象
/*復(fù)制一個對象*/
var obj2 = {a: 1, b: 2}
var copy = Object.assign({}, obj2)
console.log(obj2)
console.log(copy)
console.log(obj2 === copy)

深拷貝問題
深拷貝問題
針對深拷貝,需要使用其他方法,因為 Object.assign 拷貝的是屬性值。假如源對象的屬性值是一個指向?qū)ο蟮囊?,它也只拷貝那個引用值。
/*深拷貝問題*/
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()
合并對象
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} 注意目標對象自身也會改變
console.log(o2) //{b: 2}
console.log(o3) //{c: 3}
console.log(o123) //{a: 1, b: 2, c: 3}
/*合并具有相同屬性的對象*/
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ù)中具有相同屬性的其他對象覆蓋。
拷貝 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 是個繼承屬性。
bar: {
value: 2 // bar 是個不可枚舉屬性。
},
baz: {
value: 3,
enumerable: true // baz 是個自身可枚舉屬性。
}
});
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}
/*原始類型會被包裝為對象*/
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);
// 原始類型會被包裝,null 和 undefined 會被忽略。
// 注意,只有字符串的包裝對象才可能有自身可枚舉屬性。
console.log(obj); // { "0": "a", "1": "b", "2": "c", "k": 9 }
異常會打斷后續(xù)拷貝任務(wù)
var target = Object.defineProperty({}, "foo", {
value: 1,
writable: false
}); // target 的 foo 屬性是個只讀屬性。
Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意這個異常是在拷貝第二個源對象的第二個屬性時發(fā)生的。
console.log(target.bar); // 2,說明第一個源對象拷貝成功了。
console.log(target.foo2); // 3,說明第二個源對象的第一個屬性也拷貝成功了。
console.log(target.foo); // 1,只讀屬性不能被覆蓋,所以第二個源對象的第二個屬性拷貝失敗了。
console.log(target.foo3); // undefined,異常之后 assign 方法就退出了,第三個屬性是不會被拷貝到的。
console.log(target.baz); // undefined,第三個源對象更是不會被拷貝到的。
拷貝訪問器
var obj = {
foo: 1,
get bar() {
return 2;
}
};
var copy = Object.assign({}, obj);
// { foo: 1, bar: 2 }
// copy.bar的值來自obj.bar的getter函數(shù)的返回值
console.log(copy);
// 下面這個函數(shù)會拷貝所有自有屬性的屬性描述符
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 默認也會拷貝可枚舉的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() 方法會使用指定的原型對象及其屬性去創(chuàng)建一個新的對象。
語法:
Object.create(proto[, propertiesObject])
proto: 新創(chuàng)建對象的原型對象。
propertiesObject: 可選。如果沒有指定為undefined,則是要添加到新創(chuàng)建對象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應(yīng)的屬性名稱。這些屬性對應(yīng)Object.definedProperties()的第二個參數(shù)
返回值:在指定原型對象上添加新屬性后的對象
例外:如果proto參數(shù)不是null或者一個對象,則拋出一個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
如果你希望能繼承到多個對象,則可以使用混入的方式。
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)建一個原型為null的空對象
o = Object.create(null);
o = {};
// 以字面量方式創(chuàng)建的空對象就相當于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo會成為所創(chuàng)建對象的數(shù)據(jù)屬性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar會成為所創(chuàng)建對象的訪問器屬性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});
function Constructor(){}
o = new Constructor();
// 上面的一句就相當于:
o = Object.create(Constructor.prototype);
// 當然,如果在Constructor函數(shù)中有一些初始化代碼,Object.create不能執(zhí)行那些代碼
// 創(chuàng)建一個以另一個空對象為原型,且擁有一個屬性p的對象
o = Object.create({}, { p: { value: 42 } })
// 省略了的屬性特性默認為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)建一個可寫的,可枚舉的,可配置的屬性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});