一、实现原型拷贝

1.1、代码

        tips:为了体现原型链,写了继承实现的代码,这部分可跳过~
    

         <script>
/* 创建包含原型链的实验对象obj1-- start */
function inheritPrototype(subType, superType) {
var prototype = Object(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
} function SuperType(name) {
this.name = name;
this.colors = ['red', 'yellow', 'black'];
} SuperType.prototype.sayName = function() {
alert(this.name);
} function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
} inheritPrototype(SubType, SuperType); SubType.prototype.sagAge = function() {
alert(this.age);
}; var obj1 = new SubType('puppy', 12);
/* 完成实验对象obj1的创建 --end */ /* 原型拷贝-- start */
var obj2 = Object.getPrototypeOf(obj1);
var obj3 = Object.assign(Object.create(obj2), obj1);
/* 原型拷贝-- end */ console.log(obj1);
console.log(obj2);
console.log(obj3);
</script>
    以上代码用于验证原型链的拷贝,代码分析如下。

1.2、代码分析

        step1:设置拥有原型链的实例obj1,其属性如下:
        
        其中,自身属性:age、colors、name;原型链属性:sayAge、sayName;可忽略部分为对象的默认原型属性,本实验不考察。
 
        step2:使用 Object.getPrototypeOf() 取得实例对象obj1的原型属性对象obj2,属性如下:
        
 
        step3:使用 Object.create() 将原型属性对象obj2设置成新对象的原型属性
 
        step4:使用 Object.assign() 实现自身属性的拷贝,将其叠加到拥有原型属性的新对象上,形成obj3。
        
        如上,通过step2-step4的过程,实现了对obj1的原型链拷贝,形成新的对象obj3。

1.3、拷贝代码整合(浅拷贝、深拷贝、原型拷贝)

            function clone(origin) {
return Object.assign({}, origin);
} function moreClone(origin) {
let oriProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(oriProto), origin);
}
    函数clone为简单复制,得到原对象自身可枚举属性的拷贝;
    函数moreClone可拷贝原始对象的继承链及自身可枚举的属性。   
   tips:这里所用的拷贝方法为浅拷贝。深拷贝、浅拷贝简单说就是看源、目标的所有属性是否相互影响(自身属性、或者原型属性是否指向同一个地址),如果影响就是浅拷贝,如果不影响则为深拷贝。如果origin内有复杂类型的数据,会使得属性指向相同地址,从而使得源、目标对象之间相互影响。   

    

    如上图,对obj1的colors数据插入一个值,数组的length增1;同时,发现obj3的length也增加了1。浅拷贝得证。

    jquery的$.extend实现的深度拷贝可通过for...in实现,也就是其深拷贝是对自身的与继承的可枚举属性进行~其丢掉了原型链。所以,原型拷贝与深拷贝之间有所区别,可根据需要进行选择。在使用原生JS的环境下,可通过for...in来实现深拷贝。

    将obj1深拷贝给obj4,如下:

            let obj4 = {};
$.extend(true, obj4, obj1);
console.log(obj4);

    chrome控制台输出如下:

    

    该结构与通过for...in输出的obj1的结构相同,其丢失了obj1当中的继承的原型属性。(此处的__proto__为对象基础类型的原型属性,而非继承自自类的原型属性)。

    

    对obj1复杂类型colors插入值,obj4不受影响。深拷贝,得证。

    所以,通过for...in可实现深拷贝、Object.create()结合Object.getPrototypeOf()、Object.assign()实现原型拷贝。

    

二、Object方法深入了解

    以上用到了对象的三种方法,来实现原型链的拷贝。依照第一节中的实验代码,加深对这些方法的理解:

2.1、Object.getPrototypeOf(obj1)

        概念:返回指定对象的prototype(原型);
        如1.2 step2中的图可知,其返回的原型为obj1的原型。

2.2、Object.create(proto, [propertiesObject])

            概念:是一种新的对象创建的方法,其有两个参数:
                第一个proto,为要创建的对象的原型;
                第二个propertiesObject,为对象的属性描述符,与Object.definePropertyOf()同。
            如图:
            
            上图通过 Object.create() 分别创建 obj1 与 obj2 对应的新对象,从图中可得出以下结论:
              第一个参数:作为新对象的原型对象”__proto__”;
                  第二个参数:为属性描述符对象。(通过Object.defineProperties(obj, props)的第二个参数了解)
      所以,Object.create(proto, [propertiesObject]) 可创建一个带有原型属性的新对象。

2.3、Object.assign(target, …sources)

        概念:将一个或多个源对象自身的所有可枚举属性 复制 到目标对象。
        如图:
            
        将obj1复制给一个空对象,可以看到obj1的原型属性未被复制。由于原型属性并非对象自身的属性,未被复制。
    

三、附加Object.defineProperty(obj, prop, descriptor)

    概念:直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
    参数:obj,被操作对象;
                prop:要定义或修改的属性的名称;
                descriptor:将被定义或修改的属性的描述符。
    属性的描述符相关描述如下:
        
 
    看实例:
            var obj = {};
Object.defineProperty(obj, ‘test', {
configurable: false,
enumerable: false,
get() {
return this._value;
},
set(value) {
this._value = value + ' yeap';
return true;
}
});
console.log(obj.property1) //undefined
obj.test = 2
console.log(obj.property1) // 2 yeap
    可以看到,给obj.test赋值时,会先通过属性描述符进行处理;通过set方法,将value处理以后,赋值给_value;当取值时,返回_value的值。
    如上,通过设置 set() 和 get() ,可对属性值的存取进行处理。该属性操作方法已广泛用于数据双向绑定的一些MVVM框架中,其中VUE就使用了该方法。其通过Object.defineProperty方法,实现setter和getter,形成依赖追踪,从而在数据被访问或修改时通知变化。
 
    tips:Object.defineProperties(obj, props)是Object.defineProperty(obj, prop, descriptor)的扩展,可一次设置多个属性的描述符。
    示例:
            Object.defineProperties(obj, {
test1: {
configurable: false,
enumerable: false,
get() {
return this._value;
},
set(value) {
this._value = value + ' yeap';
return true;
}
},
test2: {
value: ‘cutcut’,
writable: true
}
});
    
    
    
    
    
        

Object的原型拷贝-create、assign、getPrototypeOf 方法的结合的更多相关文章

  1. Object.setPrototypeOf() 与Object.getPrototypeOf() 方法的使用

    Object.setPrototypeOf 方法的使用 [1] 将一个指定的对象的原型设置为另一个对象或者null(既对象的[[Prototype]]内部属性). 语法 Object.setProto ...

  2. Object.create()的使用方法

    Object.create()的使用方法:https://blog.csdn.net/wang252949/article/details/79109437

  3. [js高手之路]原型对象(prototype)与原型链相关属性与方法详解

    一,instanceof: instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型. 我在之前的两篇文章 [js高手之路]构造函数的基本特性与优缺点 [js高手 ...

  4. JavaScript 中 Object ,Prototype 相关的属性和方法

    span { font-family: 'Consolas'; font-size: 10pt; color: #ffffff; } .sc0 { } .sc2 { color: #c0c0c0; } ...

  5. JavaScript: 认识 Object、原型、原型链与继承。

    目录 引用类型与对象 类与对象 成员组成 成员访问 实例方法 / 属性 引用类型与对象 JavaScript 存在着两种数据类型:"基本数据类型" 与 "引用数据类型&q ...

  6. Object.prototype 原型和原型链

    Object.prototype 原型和原型链 原型 Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,有些属性是隐藏的.换句话说,在对象创建 ...

  7. 为什么Object.prototype在Function的原型链上与Function.prototype在Object的原型链上都为true

    关于javascript的原型链有一个问题我一直很疑惑:为什么 Function instanceof Object 与 Object instanceof Function都为true呢? Func ...

  8. JS中定义对象原型的两种使用方法

    第一种: function Person() { this.username = new Array(); this.password = "123"; } Person.prot ...

  9. Mac OSX Versions输入username按1下都会出现2个字符,并且不能create,解决方法

    我的系统,安装的versions1.3.2,下载地址:http://www.jb51.net/softs/193467.html 安装好了以后Versions输入username按1下都会出现2个字符 ...

随机推荐

  1. django系列5.3--ORM数据库的多表操作

    首先来创建一个模型,数据库的关系就清楚了 models.py from django.db import models # Create your models here. class Author( ...

  2. “全栈2019”Java异常第十二章:catch与异常匹配

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  3. AtcoderExaWizards 2019题解

    传送门 \(A\ Regular\ Triangle\) 咕咕 \(B\ Red\ or\ Blue\) 咕咕咕 \(C\ Snuke\ the\ Wizard\) 我可能脑子真的坏掉了-- 容易发现 ...

  4. Java 文件本地上传、下载和预览的实现

    以下方法为通用版本 实测图片和pdf 都没有问题 上传方法需要前端配合post请求 ,下载前端用a标签就可以,预览 前端使用ifrme标签   ,就可以实现基本功能... 1.文件本地上传 publi ...

  5. 关闭tomcat端口号

    一. CentOS 关闭tomcat端口号 1. 首先保证liunx下 ps -ef | grep java 2. 会显示如下信息 我使用的是IDEA打包的war包.tomcat是自带的 3. 查看未 ...

  6. 确定 RN 中方法的 queue

     如果不指定,每一个模块,都会生成自己的一个串行队列. 可以通过强行声明一个队列来指定所有方法都在这个队列执行 - (dispatch_queue_t)methodQueue { return di ...

  7. spring cloud ribbon源码解析(一)

    我们知道spring cloud中restTemplate可以通过服务名调接口,加入@loadBalanced标签就实现了负载均衡的功能,那么spring cloud内部是如何实现的呢? 通过@loa ...

  8. AssertJ断言系列-----------<数据库断言二>

    那么,在实际的接口测试中,我们除了要断言响应的数据正确之外,可能有的还需要断言数据层是否数据真的有入库. assertj db是可以直接对数据库进行断言和操作的. 一.创建一个students表 CR ...

  9. Springmvc之表单验证

    1.需要的相关jar 这里采用的是hibernate-validator-5.2.4.Final 和validation-api-1.1.0.Final 两个jar包.Hibernate Valida ...

  10. 1.需要对txt存放的测试数据做去重处理,代码如下

    采用集合去重,在新文件里逐行写入,达成目的 old_file = "D:/testdata/memberId.txt" #old result_file = "D:/te ...