zoukankan      html  css  js  c++  java
  • Object的原型拷贝-create、assign、getPrototypeOf 方法的结合

    总结:

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

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

    $.extend(true, obj4, obj1);通过这种方法好像可以实现深拷贝,但是如果obj4和obj1都是同一个原型拷贝出来的结果就不可以了,
    Object.create()结合Object.getPrototypeOf()、Object.assign()上面的的这三种方法是原型拷贝,所以是浅拷贝,其中给一个添加方法另一个也会有的,所谓浅拷贝就是脱离了原形链,使其给其中一个加方法或属性时不受影响

    一、实现原型拷贝

        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
                    }
                 });
    复制代码
  • 相关阅读:
    php 扩展编译linux
    PHP 单态设计模式
    Apache 支持.htaccess
    Apache 禁止访问目录
    jQuery 获取父元素、子元素、同级元素
    CentOS 配置防火墙操作实例(启、停、开、闭端口):
    CentOS 安装 lamp(转)
    火狐浏览器 js 1到9月份 new DATE不返回时间
    web 打开子窗口提交数据或其他操作后 关闭子窗口且刷新父窗口实现
    jquery on 绑定多个事件 多个元素
  • 原文地址:https://www.cnblogs.com/chaoyuehedy/p/8000214.html
Copyright © 2011-2022 走看看