【JavaScript】难点1-继承

一、创建对象

1、工厂模式

用函数来封装以特定接口创建对象的细节

function createPerson (name,age,job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        alert(this.name);
    };
    return o;
}
var person = createPerson("vicky",20,"student");

缺点:没有解决对象识别的问题。

2、构造函数模式

function Person (name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name);
    };
}
var person = new Person("vicky",20,"student");

注:
        1、任何函数只要通过new操作符调用,就可以作为构造函数;
        2、问题:每个方法都要在实例上重复一遍。

3、原型模式

function Person(){}
Person.prototype.name = "vicky";
Person.prototype.age = 20;
Person.prototype.job = "student";
Person.prototype.sayName = function () {
    alert(this.name);
};
var person = new Person();

无论什么时候,只要创建了一个心函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象,原型对象都有要给constructor属性指向prototype属性所在的函数。
【JavaScript】难点1-继承_第1张图片
每当代码读取某个对象的某个属性时,都会执行一次搜索,搜索首先从对象实例本身开始,若找不到,则搜索指针指向的原型对象。
使用对象字面量来定义原型:

function Person () {}
Person.prototype = {
    constructor:Person,
    name:"vicky",
    age:20,
    job:"student",
    sayName:function () {
        alert(this.name);
    }
}

使用对象字面量,使得construtor不在指向Person构造函数,所以,在需要的时候可以以显示的设置constructor属性

问题:
        1、省略掉了为构造函数传递初始化参数,使得所有实例在默认情况下都取得相同的属性值;
        2、属性共享。

4、组合模式 (最常用*)

组合使用构造函数模式和原型模式,使用构造函数定义实例属性,用原型模式定义方法和共享属性。

function Person (name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype = {
    constructor:Person,
    sayName:function (){
        alert(this.name);
    }   
}

5、动态原型模式

把所有信息都封装在构造函数中,通过在构造函数中初始化原型。

function Person (name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
    if(typeof this.sayName!="function"){
        Person.prototype.sayName = function () { 
            alert(this.name);
        };
    }
}

6、寄生构造函数

创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象。

function Person (name,age,job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () { 
        alert(this.name);
    };
    return o;
}

构造函数返回的对象与在构造函数外部创建的对象没有什么不同,不推荐使用。

7、稳妥构造函数模式

稳妥对象:没有公共属性,且其方法也不引用this对象。
与寄生构造函数类似,不同之处:
1、新创建对象的实例方法不引用this;
2、不使用new调用构造函数

二、继承

依靠原型链实现继承

1、原型链

利用原型让一个引用类型继承另一个引用类型的属性和方法

        function SuperType () {
            this.value = "super";
        }
        SuperType.prototype.getSuperValue = function () {
            return this.value;
        };

        function SubType () {
            this.subValue = "sub";
        }
        SubType.prototype = new SuperType ();//继承父类
        SubType.prototype.getSubValue = function () {
            return this.subValue;
        }
        var instance = new SubType();
        console.log(instance.getSubValue());//sub
        console.log(instance.getSuperValue());//super

问题:
        1、包含引用类型的原型属性会被所有实例共享;
        2、创建子类型的实例时,不能向父类的构造函数中传递参数

2、借用构造函数

基本思想:在子类型构造函数的内部调用超类型的构造函数

//借用构造函数实现继承
        function Father () {
            this.array = [1,2,3];
        }
        function Son () {
            Father.call(this);
        }
        var instance = new Son();
        instance.array.push(5);
        var instance3 = new Son();
        console.log(instance.array);//[1,2,3,5]
        console.log(instance3.array);//[1,2,3]

通过使用call(),在新创建的子类实例的环境下调用了父类的构造函数

问题:方法都在构造函数中定义,因此函数无法复用。

3、组合继承

思路:使用原型链实现对原型共享属性和方法的继承,使用借用构造函数来实现对实例属性的继承

        function Super (name) {
            this.name = name;
            this.array = [1,2,3];
        }//父类
        Super.prototype.sayName = function () {
            console.log(this.name);
        };//父类原型的方法
        function Sub (name,age) {
            Super.call(this,name);//继承父类属性
            this.age = age;
        }//子类
        Sub.prototype = new Super();//继承父类方法
        Sub.prototype.constructor = Sub();
        Sub.prototype.sayAge = function () {
            console.log(this.age);
        };
        var a = new Sub("vicky",20);
        a.array.pop(1);
        a.sayName();//vicky
        a.sayAge();//20
        var b = new Sub("jay",37);
        console.log(b.array);//[1,2,3]
        console.log(a.array);//[1,2]

4、原型式继承

function object(o) {
    function F(){}
    F.prototype = o;
    return new F();
}
    var Chinese = {
    nation:'中国'
  };
    function object (o) {
        function F() {}
        F.prototype = o;
        return new F();
    }

    var Student = object(Chinese);
    Student.job = "xuesheng";
    alert(Student.nation);//“中国”

先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的新实例。

5、寄生式继承

创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象

function createAnother(original) {
    var clone = Object(original);
    clone.sayHi = function (){ 
        console.log("hi");
    };
    return clone;
}

6、寄生组合式继承

通过借用构造函数来继承属性,通过原型链来继承方法

function inheritPrototype (subType,superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

你可能感兴趣的:(JavaScript)