1

类有三部分

  1. 构造函数内的,供实例化对象复制用的
  2. 构造函数外的,直接通过点语法添加的,供类使用,实例化对象访问不到
  3. 类的原型中的,实例化对象可以通过其原型链间接地访问到,也是供所有实例化对象所共用的。

类式继承

类的原型对象的作用就是为类的原型添加共有方法,但类不能访问这些属性和方法,只有通过原型prototype来访问。

//类式继承
//声明父类
function SuperClass() {
    this.superValue = true;
}
//为父类添加共有方法
SuperClass.prototype.getSuperValue = function () {
    return this.superValue;
};
//声明子类
function SubClass() {
    this.subValue = false;
}
//继承父类
SubClass.prototype = new SuperClass();
//为子类添加共有方法
SubClass.prototype.getSubValue = function () {
    return this.subValue;
};
var instance = new SubClass();
console.log(instance.getSuperValue());//true可以这样使用子类
console.log(instance.getSubValue());//false
console.log(instance instanceof SuperClass);//true
console.log(instance instanceof SubClass);//true
console.log(SubClass instanceof SuperClass);//false

类式继承的两个缺点:
一、子类通过其原型prototype对父类实例化,继承了父类。父类的共有属性要是引用类型,就会在子类中被所有实例共用,一个子类的实例更改子类原型从父类构造函数中继承的共有属性就会直接影响其他子类。
二、由于子类实现的继承是靠其原型prototype对父类的实例化实现的,因此在创建父类的时候,无法向父类传递参数,在实例化父类的时候也无法对父类构造函数内的属性进行初始化。

构造函数继承

//构造函数式继承
//声明父类
function SuperClass(id) {
    //引用类型共有属性
    this.books = ['javascript','html','css'];
    //值类型共有属性
    this.id = id;
}
//父类声明原型方法
SuperClass.prototype.showBooks = function () {
    console.log(this.books);
}
//声明子类
function SubClass(id) {
    //继承父类
    SuperClass.call(this,id);//将子类的变量在父类中执行一遍
}
//创建第一个子类实例
var instance1 = new SubClass(10);
var instance2 = new SubClass(11);
instance1.books.push('设计模式');
console.log(instance1.books);//[ 'javascript', 'html', 'css', '设计模式' ]
console.log(instance1.id);//10
console.log(instance2.books);//[ 'javascript', 'html', 'css' ]
console.log(instance2.id);//11
instance1.showBooks();//[ 'javascript', 'html', 'css', '设计模式' ]

由于这种类型的继承没有涉及原型prototype,所有父类的原型方法自然不会被子类继承,而如果想要被子类继承就必须放在构造函数中,这样创建的每个实例都会单独拥有一份而不能共用,违背了代码复用原则。

组合继承

前面两种模式的特点:类式继承通过子类的原型prototype对父类实例化实现的,构造函数式继承是通过在子类的构造函数作用环境中执行一次父类的构造函数来实现的。组合继承同时做到了这两点。

//组合式继承
//声明父类
function SuperClass(name) {
    //值类型共有属性
    this.name = name;
    //引用类型共有属性
    this.books = ['html','css','javaScript'];
}
//父类原型共有方法
SuperClass.prototype.getName = function () {
    console.log(this.name);
}
//声明子类
function SubClass(name,time) {
    //构造函数式继承父类name属性
    SuperClass.call(this,name);
    //子类中新增共有属性
    this.time = time;
}
//类式继承 子类原型继承父类
SubClass.prototype = new SuperClass();
//子类原型方法
SubClass.prototype.getTime =function () {
    console.log(this.time);
}
var instance1 = new SubClass('js',2018);
instance1.books.push('设计模式');
console.log(instance1.books);//[ 'html', 'css', 'javaScript', '设计模式' ]
instance1.getName();//js
instance1.getTime();//2018
var instance2 = new SubClass('css',2018);
console.log(instance2.books);//[ 'html', 'css', 'javaScript' ]
instance2.getName();//css
instance2.getTime();//2018

缺点:在使用构造函数继承时执行了一遍父类的构造函数,而在实现子类原型的类式继承时又调用一遍父类构造器,因此父类构造器调用了两遍。


蓝胖子tracer
7 声望1 粉丝

人生没有白走的路,每一步都算数!