浅谈js继承的几种方法

先回顾一下上一讲的原型。

// 原型
function Person(name) {
    this.name = name;
}
Person.prototype.sayName = function() {
    alert(this.name)
}
var p1 = new Person('嘿嘿');
console.log(p1)

结果如下图:
1216658-20180711134921329-1420165854.jpg

每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型对象的内部指针(proto )。
构造函数Person中定义的属性(即实例属性)被挂在到实例p1上,原型方法被挂载到原型对象上。

原型链继承

思想:让原型对象等于另一个类型的实例。

function SuperType() {
    this.property = true;
} 

SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

SubType.prototype = new SuperType();  // 实现继承;也就是让SubType.prototype.constructor指向构造函数SuperType

console.log(SubType.prototype.constructor)

SubType.prototype.getSubValue = function() {
    return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());    // true

1216658-20180711134949470-120619799.jpg

默认的原型

所有函数的默认原型都是Object实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也是所有自定义类型都会继承toString()和valueOf()等默认方法的根本原因。

添加方法

给原型添加方法的代码一定要放在替换原型的语句之后。

function SuperType() {
    this.property = true;
} 

SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

SubType.prototype = new SuperType();  

// 添加新方法
SubType.prototype.getSubValue = function() {
    return this.subproperty;
}
// 覆盖SuperType中的方法
SubType.prototype.getSuperValue = function() {
    return false
}

var instance = new SubType();
alert(instance.getSuperValue());    // false

通过原型链实现继承的时候,不能使用对象字面量创建原型方法。

function SuperType() {
    this.property = true;
} 

SuperType.prototype.getSuperValue = function() {
    return this.property;
};

function SubType() {
    this.subproperty = false;
}

SubType.prototype = new SuperType();  

// 使用对象字面量添加新方法,会导致上一行代码无效
SubType.prototype = {
    getSubValue: function() {
        return this.subproperty;
    },
    someOtherMethod: function() {
        return false
    }
}

var instance = new SubType();
alert(instance.getSuperValue());    // error

使用字面量添加方法,使得现在的原型包含的是一个Object实例,而非SuperType实例。所以SubType和SuperType之间已经没有联系了。

原型链的问题

原先实例的属性变成了现在的原型属性。

function SuperType() {
    this.colors = ['red', 'blue', 'green'];
    // 相当于 this.colors = new Array('red', 'blue', 'green')
} 
function SubType() {}

SubType.prototype = new SuperType();

var instance1 = new SubType();
console.log(instance1.colors);  // ["red", "blue", "green"]
instance1.colors.push('yellow');
console.log(instance1.colors);  // ["red", "blue", "green", "yellow"]

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

引用类型的实例属性要被放在构造函数中,因为每个引用类型值在实例上会重新创建一遍,创建后的引用类型值的属性或方法是不一样的。这里,让SubType.prototype等于SuperType的实例,也就让SuperType中的实例方法变成了原型方法, 被挂在到SubType.prototype上

原型链实现继承还有一个问题:在创建子类型(SubType)的实例时,无法向超类型(SuperType)的构造函数中传递参数。

借用构造函数继承

在子类型构造函数中调用超类型构造函数。使用call或apply方法改变超类型构造函数this指向。

function SuperType(name) {
    this.colors = ['red', 'blue', 'green'];
    this.name = name;
} 
function SubType() {
    SuperType.call(this, '呵呵')
}
var instance1 = new SubType();
console.log(instance1.colors);  // ["red", "blue", "green"]
instance1.colors.push('yellow');
console.log(instance1.colors);  // ["red", "blue", "green", "yellow"]
console.log(instance1.name);    // 呵呵

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

借用构造函数的问题:在超类型原型中定义的方法,无法被子类型继承。

function A() {
    this.name = '嘿嘿'
}
A.prototype.sayName = function() {
    alert(this.name)
}
function B() {
    A.call(this)
}
var b = new B();
b.sayName();        //  error

组合继承(最常用方法,掌握这个就行了)

使用原型链实现对原型属性和方法的继承,使用构造函数实现对实例属性的继承。

function SuperType(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}
SuperType.prototype.sayName = function() {
    alert(this.name);
}
function SubType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();

SubType.prototype.constructor = SubType;    // 为了修复SubType.prototype的结构

SubType.prototype.sayAge = function(){
    alert(this.age);
}
var instance1 = new SubType('小红', 18);
instance1.colors.push('yellow');
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType('老红', 80);
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

原型式继承

原型式继承就是基于已有的对象创建新对象.

function object(o) {
    function F() {}
    F.prototype = o;    // 使一个类型的原型对象等于另一个对象
    return new F();
}
var person = {
    name: '小芳',
    friends: ['小明', '小华']
}
var anotherPerson = object(person);
anotherPerson.name = '老方';
anotherPerson.friends.push('老王');

var yetAnotherPerson = object(person);
yetAnotherPerson.name = '老明';
yetAnotherPerson.friends.push('二狗子');

console.log(person.friends)     // ["小明", "小华", "老王", "二狗子"]

ES5为了规范原型式继承,新增Object.create()方法。Object.create()可接收两个参数:第一个参数是超类型的对象,第二个参数可选,为新对象添加属性。

var person = {
    name: '小芳',
    friends: ['小明', '小华']
}
var anotherPerson = Object.create(person);
anotherPerson.name = '老方';
anotherPerson.friends.push('老王');

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = '老明';
yetAnotherPerson.friends.push('二狗子');

console.log(person.friends)     // ["小明", "小华", "老王", "二狗子"]
var person = {
    name: '小芳',
    friends: ['小明', '小华']
}
var anotherPerson = Object.create(person, {
    name: {
        value: '老方'
    }
})
console.log(anotherPerson.name)         // '老方'

寄生式继承

function CreateAnother(original) {
    var clone = Object(original);
    clone.sayHi = function() {
        alert('hi');
    }
    return clone
}
var person = {
    name: '小芳',
    friends: ['小明', '小华']
}
var anotherPerson = CreateAnother(person);
anotherPerson.sayHi();
anotherPerson.friends.push('老王');
console.log(person.friends)         //  ["小明", "小华", "老王"]

寄生组合式继承(最好的方法)

function inheritPrototype(subType, superType) {
    var prototype = Object(superType.prototype);
    prototype.constructor = subType;  //  修正subType.prototype的constructor
    subType.prototype = prototype;
}

function SuperType(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

SuperType.prototype.sayName = function() {
    alert(this.name)
}
function SubType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
    alert(this.age)
}

var p1 = new SubType()
console.log(p1.colors)      // ['red', 'blue', 'green']

注:以上内容总结自《javascript高级程序设计》

转载于:https://www.cnblogs.com/renzhiwei2017/p/8312845.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值