The Object.create () and deep copy

  1. Syntax:
    Object.create (proto, [propertiesObject])
    // method to create a new object, using the existing object to provide an object of the newly created proto .
  2. parameter:
  • proto: must. It represents the new object's prototype object, that this parameter will be assigned to the target object (ie a new object, or should we say the object was last returned) on the prototype. This parameter can be null, 对象a function of prototype属性(creates an empty object to be passed when null, otherwise it will throw TypeErroran exception).
  • propertiesObject: Optional. Added to the newly created object may be enumerated attribute (i.e., its own properties, rather than the prototype chain enumerated attribute) property of the object descriptor and the corresponding attribute name. These properties correspond to Object.defineProperties()the second parameter.
    Return value:
    adding an object after the new attributes on the specified prototype object.
  1. Case Description:

1) to create objects in different ways

new Object () to create the object by the constructor, the attribute is added under its own instance.
Object.create () es6 Another way to create objects, inheritance can be understood as an object, add the property is in the prototype.

// new Object() 方式创建
var a = {  rep : 'apple' }
var b = new Object(a) console.log(b) // {rep: "apple"} console.log(b.__proto__) // {} console.log(b.rep) // {rep: "apple"} // Object.create() 方式创建 var a = { rep: 'apple' } var b = Object.create(a) console.log(b) // {} console.log(b.__proto__) // {rep: "apple"} console.log(b.rep) // {rep: "apple"} 

The Object.create () method creates an object, the following property is the prototype can also directly access b.rep // {rep: "apple" },
case b the value is not it's own, it is through the prototype chain proto access to the value of b.



2) create different object properties of nature

// 创建一个以另一个空对象为原型,且拥有一个属性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 

The Object.create () to create a non-null object by the second argument descriptor attribute defaults to false, the object property constructor method to create or literal descriptors default is true. See the figure analysis:


 
 



3) When you create a different space objects

 
 

When using the constructor creates an empty object or object literal method, it is an object prototype attributes, namely _proto_ ;
when creating empty object with the Object.create () method, an object is no prototype property.

 



4) __proto__property
JavaScript object inheritance is achieved through the prototype chain. ES6 provided a method of operating more prototype object.
__proto__Attributes (two underscores before and after), the prototype object to read or set the current object. At present, only the browser environment must be deployed has the property, other operating environment does not have to be deployed, it is not recommended to use this property, but the use of these below to Object.setPrototypeOf()(write), Object.getPrototypeOf()(read), (generatingObject.create() operation) instead.

  • Object.create()
    Description: This method creates a new object, an existing object used to provide the newly created object __proto__;
    Format: Object.create (proto [, propertiesObject] )
    Usage: If the attribute is added to give an object in a conventional manner prototype and methods, through __propt__implementation
var proto = {
    y: 20,
    z: 40, showNum(){} }; var o = Object.create(proto); 
 
 

If it is not Object, create () method, the prototype of how we add properties and methods to the object?
------ constructor or by class, for example:

//创建一个构造函数或者类
var People = function(){} People.prototype.y = 20 People.prototype.showNum = function() {} //通过构造函数创建实例 var p = new People(); console.log(p.__proto__ === People.prototype) // true 
 
 
 
 

There are Object.create () will simply more

 

  • Object.setPrototypeOf
    Description: The effect of the method of __proto__the same, used to set a target prototypeobject, and returns the parameter object itself. It is recommended setting ES6 official prototype object.
    Format: Object.setPrototypeOf (object, prototype)
    Usage:
var proto = {
    y: 20,
    z: 40 }; var o = { x: 10 }; Object.setPrototypeOf(o, proto); 
 
 

Output seen, the method of addition is in the prototype. It is similar to

obj.__proto__ = proto;

 

  • Object.getPrototypeOf()
    描述:用于读取一个对象的原型对象;
    格式:Object.getPrototypeOf(obj);
    用法:
Object.getPrototypeOf('foo') === String.prototype // true
Object.getPrototypeOf(true) === Boolean.prototype // true 



4.1)原型属性的继承
这里结合一个例子来说说这几个方法的使用:
场景:拷贝一个构造函数的实例。

var triangle = {a: 1, b: 2, c: 3}; function ColoredTriangle() { this.color = 'red'; } //ColoredTriangle.prototype = triangle; //ColoredTriangle.prototype.constructor === ColoredTriangle// false Object.assign(ColoredTriangle.prototype, triangle) //ColoredTriangle.prototype.constructor === ColoredTriangle// true var c = new ColoredTriangle(); 

打印出 实例c 看看结构是怎样的


 
 

其中 color 属性在实例上,而其他的原型上。
现在来拷贝一个 实例 c2

var c2 = Object.assign({},c)
console.log(c2.color); //red
console.log(c2.a); //undefined 

因为 Object.assing 是不能拷贝到继承或原型上的方法的。所以 实例c2 没有 a 这个属性。那要怎么要才能拷贝到原型上的方法呢?

4.1.1)第一种方法

var originProto = Object.getPrototypeOf(c);
var originProto2 = Object.create(originProto);
var c2 = Object.assign(originProto2, c); //var c2 = Object.assign(Object.create(Object.getPrototypeOf(c)), c) console.log(c2.color); // red console.log(c2.a); // 1 

这样就实现了原型属性的拷贝。
Object.getPrototypeOf(c) 既 originProto 得到的是原型上的 //{a: 1, b: 2, c: 3};
Object.create(originProto) 既 originProto2 既是创建了一个 {a: 1, b: 2, c: 3} 在原型上的新对象;
Object.assign(originProto2, c) 在源对象originProto2 上合并对象 c;

4.1.2)第二种方法 (推荐)

var c = new ColoredTriangle();
var c2 = Object.create(Object.getPrototypeOf(c), Object.getOwnPropertyDescriptors(c)); console.log(c2.color); // red console.log(c2.a); // 1 

可以把Object.create()的参数理解为:第一个参数是放在新对象的原型上的,第二个参数是放在新对象的实例上的。
所以上面例子
Object.getPrototypeOf() 得到的是 c 对象的原型,然后作为第一个参数,所以会在新对象c2 的原型上。
Object.getOwnPropertyDescriptors() 得到是 c 对象自身的可枚举属性,作为第二个参数,放在 c2 的实例上。

为什么说推荐这个方法呢?因为Object.assign() 方法不能正确拷贝 get ,set 属性。

例如,我们给 c 实例添加一个 "colorGet" 属性,并设置该属性的get 描述符:

var c = new ColoredTriangle();
Object.defineProperty(c,'colorGet', {
    enumerable: true, // 设为可枚举,不然 Object.assign 方法会过滤该属性 get(){ return "Could it return " + this.color } }); var c3 = Object.assign(Object.create(Object.getPrototypeOf(c)), c) 

结果如下:


 
 

这里没有拷贝到 "colorGet" 的 get 描述符,而是直接把获取到的值赋值给 "colorGet" 。

那对于 get 描述符要怎么获取呢? Object.getOwnPropertyDescriptors就专为解决这问题而生。
而又因为要拷贝原型上的属性,所以结合Object.create、Object.getPrototypeOf 方法一起使用。即上面的第二种实现方法,如下:

var c = new ColoredTriangle();
Object.defineProperty(c,'colorGet', {
    enumerable: true, // 设为可枚举,不然 Object.assign 方法会过滤该属性 get(){ return "Could it return " + this.color } }); var c3 = Object.create(Object.getPrototypeOf(c), Object.getOwnPropertyDescriptors(c)); 

结果如下:


 
 

此时已经成功的拷贝到了get描述符啦。
虽然说实际开发上很少会要去修改 get 描述符,但是知道多一种方法,遇到这种情况时就知道该怎么去解决了。

注意:这些都只是一个层级的深拷贝。

 




上面实现 原型属性拷贝 中的两种方法中用到了 Object.getOwnPropertyDescriptorsObject.assing()Object.createObject.getPrototypeOf()方法,通常这几种方法都有一起结合使用。
如果上面的例子还不理解,这里把他简单的拿到 对象的继承 来讲解。理解的话就可以忽略啦。



4.2)原型属性的继承
以前,继承另一个对象,常常写成下面这样。

const obj = {
  __proto__: prot,
  foo: 123,
};

ES6 规定__proto__只有浏览器要部署,其他环境不用部署。如果去除__proto__,可以用 Object.create() 和 Object.assign() 来实现。

//现在可以这样写 方法1
const obj = Object.create(prot);
obj.foo = 123;


// 或者 方法2 const obj = Object.assign( Object.create(prot), { foo: 123, } ); // 或者 方法3 const obj = Object.create(prot,Object.getOwnPropertyDescriptors({ foo: 123 })); 

但是 Object.assign() 无法正确拷贝get属性和set属性的问题。例如:

var prot = {x: 1, y: 2} var obj = { __proto__: prot, foo: 100, bar(){ return this.foo}, get baz() {return this.foo} }; var obj2 = Object.assign(Object.create(prot), obj) 
 
 

上图中,obj 对象的 foo 属性是一个取值函数,Object.assign不会复制这个取值函数,只会拿到值以后,将这个值赋上去。

而 Object.getOwnPropertyDescriptors() 可以解决这个问题 实现get 、set 属性的正确拷贝,即方法3 ,如下:

var prot = {x: 1, y: 2} var obj = { __proto__: prot, foo: 100, bar(){ return this.foo}, get baz() {return this.foo} }; var obj2 = Object.create(prot, Object.getOwnPropertyDescriptors(obj)) 
 
 



说了那么多种拷贝方法,怎么去选择呢,还是要看实际应用中的情况:

如果只是拷贝 自身可枚举属性,就可以只用 Object.assign 方法;
如果是要拷贝原型上的属性,就需要 Object.assign , Object.create, Object.getPrototypeOf 方法结合使用
如果是拷贝get /set 属性,就需要 结合 Ojbect.getOwnPropertyDescriptors 方法

 

Guess you like

Origin www.cnblogs.com/zhilin/p/11402064.html