js继承

6种继承方式:

1.原型链继承
2.借用构造函数(经典继承)
3.组合继承
4.原型式继承
5.寄生式继承
6.寄生组合式继承

1.原型链:

缺点:所有实例会共享属性

     新实例无法向父类构造函数传参

        function FirstProto() {
            this.name = 'xiaoming';
            this.colors = ['red', 'yellow'];
        };

        function SecProto() {}
        SecProto.prototype = new FirstProto();
        var instance1 = new SecProto();
        instance1.colors.push('black');
        console.log(instance1.name, instance1.colors); //xiaoming ["red", "yellow", "black"]

        var instance2 = new SecProto();
        console.log(instance2.name, instance2.colors); //xiaoming ["red", "yellow", "black"]

2.借用构造函数     :各自继承,不会共享

function FirstProto(){
this.colors=['red','yellow'];
};
function SecProto(){
   FirstProto.call(this);
}
var instance1=new SecProto();
instance1.colors.push('black');
console.log(instance1.colors);//["red", "yellow", "black"]

var instance2=new SecProto();
console.log(instance2.colors);//["red", "yellow"]

还可以传递参数

function FirstProto(col){
this.colors=['red','yellow',col];
};
function SecProto(){
   FirstProto.call(this,'blue');
}
var instance1=new SecProto();
instance1.colors.push('black');
console.log(instance1.colors);// ["red", "yellow", "blue", "black"]

var instance2=new SecProto();
console.log(instance2.colors);// ["red", "yellow", "blue"]

存在的问题:方法都在构造函数中定义好了,不存在函数的复用

即:1.只是子类的实例,不是父类的实例
2.方法都在构造函数中定义,每次创建实例都会创建一遍方法

3.组合继承
思路是:使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。
function FirstProto(name){
    this.colors=['red','yellow'];
    this.name=name;
};
FirstProto.prototype.sayname=function(){
  console.log(this.name);
 }
function SecProto(name,age){
   //继承属性
   FirstProto.call(this,name);         //第二次调用父类
   this.age=age;
}
SecProto.prototype=new FirstProto();    //第一次调用父类 
SecProto.prototype.constructor=SecProto;
SecProto.prototype.sayage=function(){
  console.log(this.age);
 }
var instance1=new SecProto('Sun menghua',24);
instance1.colors.push('black');
instance1.sayname();//Sun menghua
instance1.sayage();//24
console.log(instance1.colors);//["red", "yellow", "black"]

var instance2=new SecProto('Qi Haiyang',25);
instance2.sayname();// Qi Haiyang
instance2.sayage();//25
console.log(instance2.colors);//["red", "yellow"]

 

优点:融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式
缺点:调用了两次父类构造函数
(组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部)

4.原型式继承

基于已有的对象创建新对象

①obj()浅复制

对象的属性会共享

function obj(o){
 function F(){}
 F.prototype=o;
 return new F();
}
var person={
name:"zhangsan",
age:18,
friends:['Lisi','wangwu','zhaoliu']
};
 var thePerson=obj(person);
thePerson. name='Sunmenghua';
thePerson.friends.push('liulaogen');
console.log(thePerson.name); //Sunmenghua
console.log(thePerson.friends);
//["Lisi", "wangwu", "zhaoliu", "liulaogen"]

 var theOtherPerson=obj(person);
theOtherPerson. name='Qi Haiyang';
theOtherPerson.friends.push('Da liu');
console.log(theOtherPerson.name);
//Qi Haiyang
console.log(theOtherPerson.friends);
// ["Lisi", "wangwu", "zhaoliu", "liulaogen", "Da liu"]

console.log(thePerson.name);
//Sunmenghua
console.log(thePerson.friends);
// ["Lisi", "wangwu", "zhaoliu", "liulaogen", "Da liu"]

console.log(person.name);
//zhangsan

缺点: 包含引用类型的属性值始终都会共享相应的值, 这点跟原型链继承一样

注意: 这里修改了thePerson.name的值,theOtherPerson.name的值并未改变,并不是因为thePerson和theOtherPerson有独立的name值,而是thePerson.name="Sunmenghua'是给thePerson添加了name值,并非修改了原型上的name值。

因为我们找对象上的属性时,总是先找实例上对象,没有找到的话再去原型对象上的属性。实例对象和原型对象上如果有同名属性,总是先取实例对象上的值
还可采用Object.create()方法,具体见https://i.cnblogs.com/posts/edit;postId=8880863

5.寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。
可以理解为在原型式继承的基础上新增一些函数或属性。

        function obj(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        function createPerson(orig) {
            var thePerson = obj(orig);
            thePerson.sayHi = function() {
                console.log('hi');
            };
            thePerson.sex = 'female';
            return thePerson;
        }

        var person = {
            name: "zhangsan",
            age: 18,
            friends: ['Lisi', 'wangwu', 'zhaoliu']
        };
        var newPerson = createPerson(person);
        newPerson.sayHi(); //hi
        console.log(newPerson.friends); //["Lisi", "wangwu", "zhaoliu"]
        console.log(newPerson.sex); //female

 

函数不能复用,降低效率,但新对象不仅具有person的属性和方法,还有自己的方法。

6.寄生组合式继承

        // 寄生组合式继承
        function Parent(name) {
            this.name = name;
            this.colors = ['blue', 'green'];
        }
        Parent.prototype.sayName = function() {
            console.log(this.name);
        }

        function Child(name, age) {
            Parent.call(this, name);
            this.age = age;
        }

        function CreateObj(o) {
            function F() {};
            F.prototype = o;
            return new F();
        }

        // Child.prototype = new Parent(); // 这里换成下面
        function prototype(child, parent) {
            var prototype = CreateObj(parent.prototype);
            prototype.constructor = child;
            child.prototype = prototype;
        }
        prototype(Child, Parent);

        var child1 = new Child('xiaopao', 18);
        child1.colors.push('red');
        console.log(child1);  //name: "xiaopao", colors: ["blue", "green", "red"], age: 18
        var child2 = new Child('xiao', 19); 
        console.log(child2); //name: "xiao", colors: ["blue", "green"], age: 19

只调用了一次Parent构造函数,并且因此在避免了Parent.prototype上面创建不必要的多余的属性。普遍认为寄生组合式继承是引用类型最理想的继承方式

 

posted @ 2018-04-19 12:15  sunmarvell  阅读(145)  评论(0编辑  收藏  举报