继承 继承

2016-12-01  本文已影响0人  nwzk41

属性拷贝

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

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

函数代码在此:

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 将所有父级对象属性保存下来,需要时再去获取。

上一篇 下一篇

猜你喜欢

热点阅读