01、属性 -------
01、Object.prototype属性表示object的原型对象
几乎所有的javascript对象都是 Object 实例,一个典型的对象继承了 Object.prototype 的属性(包括方法),尽管这些属性被覆盖。然而,一个 Object 可能是故意创建的,这是不确定的(例如通过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
/*打印一个对象的构造函数*/
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() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
语法:
Object.assign(target, ...sources)
target:目标对象
sources: 源对象
返回值: 目标对象
描述:如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor() 和 Object.defineProperty()。
String类型和Symbol类型的属性都会被拷贝。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。
注意,Object.assign 会跳过那些值为null和nudefined的源对象
/*复制一个对象*/
var obj2 = {a: 1, b: 2}
var copy = Object.assign({}, obj2)
console.log(obj2)
console.log(copy)
console.log(obj2 === copy)
深拷贝问题
深拷贝问题
针对深拷贝,需要使用其他方法,因为 Object.assign 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
/*深拷贝问题*/
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} 属性被后续参数中具有相同属性的其他对象覆盖。
拷贝 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 }
异常会打断后续拷贝任务
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
// 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。
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函数的返回值
console.log(copy);
// 下面这个函数会拷贝所有自有属性的属性描述符
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() 方法会使用指定的原型对象及其属性去创建一个新的对象。
语法:
Object.create(proto[, propertiesObject])
proto: 新创建对象的原型对象。
propertiesObject: 可选。如果没有指定为undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.definedProperties()的第二个参数
返回值:在指定原型对象上添加新属性后的对象
例外:如果proto参数不是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参数
var o;
// 创建一个原型为null的空对象
o = Object.create(null);
o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
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函数中有一些初始化代码,Object.create不能执行那些代码
// 创建一个以另一个空对象为原型,且拥有一个属性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
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});