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)
----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)
深拷貝問(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
}
});