美文网首页
继承 继承

继承 继承

作者: nwzk41 | 来源:发表于2016-12-01 20:19 被阅读0次

    属性拷贝

    继承不单单能通过原型链实现,也能通过其他方式实现,属性拷贝就是其中一种方法。

    通过属性拷贝也能实现继承
    子对象会继承父对象原型链上所有的自身属性

    函数代码在此:

    function extend2(Child,Parent) {
                var c = Child.prototype;
                var p = Parent.prototype;
    
                // 循环遍历 Parent 中的属性,复制给 Child
                for (var i in p){
                    c[i] = p [i];
                };
                // uber 属性实现子级能找到父级的属性
                Child.uber = Parent.prototype;
            }
    

    此时创建父级子级的构造函数及对象,调用函数形成继承关系

    function Person(){}
            Person.prototype.description = "人类";
            Person.prototype.age = 0;
            Person.prototype.hobby = ["权利","金钱"]
            Person.prototype.say = function(){
                return "我的年龄:" +this.age;
            }
    
            function Student(){}
            // 实现继承关系,调用函数
            extend2(Student,Person);
            // 此时不需要更改 construtor 属性
            Student.prototype.description = "学生";
            Student.prototype.age= 18;
    
            var stu = new Student();
            console.log(stu.description);//学生
            console.log(stu.say());//我的年龄:18
            stu.hobby.pop()
            console.log(stu.hobby);//["权利"]
    
            var per = new Person();
            console.log(per.description);//人类
            console.log(per.say());//我的年龄:0
            console.log(per.hobby);//["权利"]
    

    此时实现了继承的效果,stu 能访问 per 的属性

    如图所示:

    属性拷贝2.png

    注意:该方法只针对于基本数据类型有效,JS中对象的传递大多数都是引用传递,仅仅是传递对象的地址,子对象修改,父对象中也相应地会改变


    对象之间的继承

    到目前来说。我们都是通过构造函数实现的继承

    其实,我们完全可以不使用构造函数就实现继承关系,直接使用对象完成继承关系的建立

    函数代码如下:

    function extend3(parent,child) {
                // 如果child参数传进来,就是外面有已知对象给 child 赋值,
                //如果没有 Child 参数传进来,函数会创建一个空对象并返回,此空对象继承自 parent
                child = child || {};
                for (var i in parent){
                    child[i] = parent[i];
                }
                child.uber = parent;
                return child;
            }
    

    现在我们直接创建父级子级对象,调用函数实现继承,代码如下:

    var  per = { 
                description:"人类",
                age:0,
                hobby:["金钱","权利"],
                say:function(){
                    return "我的年龄是:" +this.age;
                },
            }
    
            function Student(){}
    
            var stu = new Student();
            // 建立继承关系(让一个已知的对象继承自 per)
            extend3(per,stu);
            stu.description = "学生";
            console.log(stu.description);//学生
            console.log(stu.age);//0
            stu.hobby.pop();
            console.log(stu.hobby);//["金钱"]
            console.log(stu.say());//我的年龄是:0
            console.log(per.hobby);//["金钱"]
            // 子对象访问父对象属性
            console.log(stu.uber.description);//人类
    
    
            // 创建一个继承自 per的对象
    
            var t = extend3(per);
            console.log(t.description);
            console.log(t.say());
    

    实现了子级继承父级的效果,同时,我们还能通过此函数直接创建子级对象


    深拷贝

    上面两种方式虽然都能调用函数,但是如果修改对象的值,是直接修改父级对象的值,原来父级的属性就被替换了

    extend2 和 extend3 都是浅拷贝

    深拷贝:内存拷贝,将内存完整的拷贝一份

    浅拷贝:引用拷贝,只复制对象的地址

    如果想实现深拷贝

    1.我们会用hasOwnProperty() 方法判断该属性是否需要复制的
    2.子对象不会影响到父对象中的属性值
    

    实现深拷贝的函数代码如下:

    function deepCopy(parent,child){
                child = child || {};
                // 遍历父对象属性
                for(var i in parent){
                    // 判断自身属性
                    if(parent.hasOwnProperty(i)){
                        // 判断自身属性
                        if(/*对象类型*/typeof parent[i] === "object"){
                            // 判断属性是否是数组
                            child[i] = Array.isArray(parent[i]) ? [] : {};
                            // 把 parent[i]里的属性赋值给child[i]里面去
                            deepCopy(parent[i],child[i]);
                        }else{
                        // 基本数据类型
                        child[i] = parent[i];
                        }
                    }
                }
                // child.uber = parent;
                return child;
            }
    

    这次直接创建对象看看效果

    var  per = { 
                description:"人类",
                age:0,
                hobby:["金钱","权利"],
                say:function(){
                    return "我的年龄是:" +this.age;
                },
            }
    
            //  t 继承自 per
            var t = deepCopy(per);
            // t.description = "学生";
            console.log(t.description);//人类
            console.log(per.description);//人类
            t.hobby.pop();
            console.log(t.hobby);//["金钱"]
            console.log(per.hobby);//["金钱", "权利"]
    

    深浅拷贝的原理


    深浅拷贝.png

    t 如果不修改 description 属性默认继承父级属性,同时,t修改数组,对 per 的数组值没有影响


    原型继承与属性拷贝的混合应用

    原型继承和拷贝继承混用的方式,能将两个父对象的属性用不同的方式继承下来
    先创建两个对象 per 和 base ,作为父对象
    代码如下:

    var  per = { 
                description:"人类",
                age:0,
                hobby:["金钱","权利"],
                say:function(){
                    return "我的年龄是:" +this.age;
                },
            }
    
            var base = {
                name:"二雷",height:180,weight:100,
            }
    

    混用函数代码如下:

    function extend(p1,p2) {
                var child;
                var F = function(){};
                F.prototype = p1;
                child =  new F();
    
                for(var i in p2){
                    child[i] = p2[i];
                }
                return child;
            }
    

    创建子级,看一下效果:

    
    
    var t = extend(per,base);
            console.log(t.name);//二雷
            console.log(t.hobby);//["金钱", "权利"]
    

    实现了


    多重继承

    其实,n个对象的属性也可以通过函数实现继承于1个子对象中,也就是一个子对象能继承到那个对象的属性

    要实现这个方法,需要使用函数的 arguments 属性

    父级对象的创建:

    // 能继承多个对象的属性,创建多个对象
            var per1 = {
                name:"二雷",
            }
            var per3 = {
                age:20,
            }
            var per5 = {
                height:180,name:"雷",
            }
            var per6 = {
                weight:100,
            }
    

    继承函数的创建:

    // arguments类似数组,它的属性是当前函数所街搜到的所有参数
            function muli(){
                var child = {};
                for(var i = 0;i<arguments.length;i++) {
                    for(var j in arguments[i]){
                        child[j] = arguments[i][j];
                    }
                }
                return child;
            }
            // 注意:如果父对象中存在相同的属性,参数后面对象中的属性会覆盖前面对象中的属性
            var t = muli(per1,per3,per5,per6);
            console.log(t)//Object age: 20 height: 180 name: "雷" weight: 100 __proto__: Object
    

    这样新建的t对象就有其所有父级元素的属性了,集大成者

    不过要注意的是,如果父级元素中有相同的属性,谁在后面输出谁的属性,不过前面的属性值就被覆盖了,在当前函数下,不能找回前面的同名属性值,可以通过设置 uber 将所有父级对象属性保存下来,需要时再去获取。

    相关文章

      网友评论

          本文标题:继承 继承

          本文链接:https://www.haomeiwen.com/subject/wfdgpttx.html