js函数的对象的继承

1.原型链继承:将父亲的实例赋给子类的原型。

缺点:如果有一个子类实例改变所继承的内容,则当下一个子类实例继承是会是上一个子类改变之后的内容,而不是原有父亲的内容。

(解决:对象冒充继承方法)

function Father(name, age) {
            this.name = 'li';
            this.age = 3;
            this.arr = [1, 2, 3];
        }
        function Son(sex) {
            this.sex = sex;
        }
        Son.prototype = new Father; //将父类的实例赋值给子类的原型
        var son1 = new Son('男'); //new一个子类的实例son1
        var son2 = new Son('女'); //new一个子类的实例son2
        console.log(son1.arr); //打印son1继承的属性arr  [1, 2, 3]
        son1.arr.push(4); //通过son1改变arr的值 此时改变的是子类的原型链
        console.log(son2.arr); //再用son2打印arr值   [1, 2, 3, 4]

2.对象冒充继承: 通过call或其他方法改变父类中的this指向,让父类的this指向那子类,这样子类实例对象就可以使用父类中的属性和方法。

优点: 解决了原型链继承引用类型共用的问题 。

缺点:不能调用父类原型链中的方法函数。(解决:组合模式方法)

function Father(name, age) {
            this.name = 'li';
            this.age = 3;
            this.arr = [1, 2, 3];
            this.sayHi = function() {
                return 'Hi' + this.name;
            }
        }
        Father.prototype.showName = function() {
            return this.name;
        }

        function Son(sex) {
            Father.call(this); //通过call改变Father的this指向Son,这样就可以使Son中拥有Father的属性
            this.sex = sex;
        }
        var son1 = new Son('男');
        console.log(son1); //Son {nme: "li", age: 3, arr: Array(3), sex: "男", sayHi: ƒ}
        console.log(son1.name); //li
        console.log(son1.sayHi()); //可以调用父类本身具有的方法  Hili
        // console.log(son1.showName()); //报错 son1.showName is not a function
        //缺点:不能调用父类原型链中的方法函数

        //----------------------------------------------------------
        //解决了原型链中一个子类对象改变父类属性会影响其他子类的问题
        son1.arr.push(4);
        console.log(son1.arr); //[1, 2, 3, 4]
        var son2 = new Son();
        console.log(son2.arr); //[1, 2, 3]

3.组合继承:利用对象冒充继承父类本身的属性和方法,利用原型链继承父类原型上的方法

优点:解决了不能调用父类原型链中的方法函数;

缺点: 1.相同的属性,在原型链上出现了两次(读取没有问题,因为子实例上面的屏闭了 原型上面的属性)

2.父类的构造函数调用了两次

解决:寄生组合继承

function Father(name, age) {
            this.name = 'li';
            this.age = 3;
            this.arr = [1, 2, 3];
            this.sayHi = function() {
                return 'Hi' + this.name;
            }
        }
        Father.prototype.showName = function() {
            return this.name;
        }

        function Son(sex) {
            Father.call(this); //通过call改变Father的this指向Son,这样就可以使Son中拥有Father的属性 调用一次
            this.sex = sex;
        }
        Son.prototype = new Father(); //通过原型链继承父类原型中的方法 调用两次
        var son1 = new Son('男');
        console.log(son1); //Son {name: "li", age: 3, arr: Array(3), sex: "男", sayHi: ƒ}
        console.log(son1.showName()); //li
        console.log(son1.sayHi()); //Hili

可以看到age,arr,name,sayHi在原型链中出现了两次。

 

4.寄生组合继承:(完美)

function Father(name, age) {
            this.name = 'li';
            this.age = 3;
            this.arr = [1, 2, 3];
            this.sayHi = function() {
                return 'Hi' + this.name;
            }
        }
        Father.prototype.showName = function() {
                return this.name;
            }
            //  Son.prototype = new Father;//不能直接继承父类
            // 父的实例,不能直接赋给子的原型,利用一个中间函数中转一下
        function Son(sex) {
            Father.call(this); // 利用对象冒充继承继承属性Father的属性
            this.sex = sex;
        }

        // var F = function() {};
        // F.prototype = Father.prototype;
        // Son.prototype = new F();
        // Son.prototype.constructor = Son;
        inherits(Son, Father); // 调这个封装函数,相当于上面四句话
        // 子的原型上的方法,必须在调用inherits以后,再添加
        var son1 = new Son('男');
        console.log(son1.showName()); //li
        function inherits(Child, Parent) {
            var F = function() {};
            F.prototype = Parent.prototype;
            Child.prototype = new F();
            Child.prototype.constructor = Child;
        }
原文地址:https://www.cnblogs.com/ximenchuifa/p/13498139.html