由于 es 函数没有签名, 在函数中无法实现OO语言的接口继承,只支持实现继承。
原型链继承
原型链继承,就是把一个函数的原型等于另一个函数的实例。
原型链继承的缺点:
- 在通过原型来实现继承时,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了。
- 创建子类型的实例时,不能向父类型的构造函数中传递参数。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| function LookingForAWife() { function Girl() { this.name = 'Arutoria'; this.age = 20; this.job = '护士'; this.dating = false; }
function GirlFriend() { this.belong = 'haise'; }
function Wife() { this.husband = 'haise'; }
Girl.prototype.getGirlInfo = function () { return { name: this.name, age: this.age, job: this.job, dating: this.dating }; }
var girl = new Girl();
if (!girl.dating) { GirlFriend.prototype = girl; } else { console.log('没戏'); return girl = null; }
var girlFriend = new GirlFriend(); girlFriend.__proto__.dating = true
if (girlFriend.belong === 'haise') { Wife.prototype = girlFriend; } else { console.log('结婚没戏'); return girlFriend = null; }
var wife = new Wife();
console.log(wife.name); console.log(wife.age); console.log(wife.job); console.log('爱我?', wife.dating); console.log('属于', wife.belong); console.log('丈夫', wife.husband); console.log(wife.getGirlInfo()); }
LookingForAWife();
|
借用构造函数
在子类型构造函数的内部调用父类型构造函数。
问题:
- 方法都在构造函数中定义,因此函数复用就无从谈起了
- 在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Girl(name) { this.name = name; }
function GirlFriend() { Girl.call(this, "Arutoria"); this.age = 20; } var instance = new GirlFriend(); console.log(instance.name); console.log(instance.age);
|
组合继承
组合继承是将原型链和借用构造函数组合在一起,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
这种继承方式比较常用,原因是结合了原型链继承和借用构造函数继承,各自的优点。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function Girl(name) { this.name = name; this.job = ["护士", "空姐", "教师"]; }
Girl.prototype.sayName = function () { console.log(this.name); };
function GirlFriend(name, age) { Girl.call(this, name); this.age = age; }
GirlFriend.prototype = new Girl(); GirlFriend.prototype.constructor = GirlFriend;
GirlFriend.prototype.sayAge = function () { console.log(this.age); };
var girl1 = new GirlFriend("Arutoria", 20); console.log('Arutoria的职业是:' + girl1.job); girl1.sayName(); girl1.sayAge();
|
原型式继承
原型式在es5被规范化, 使用Object.create()
方法,方法接收两个参数:一 个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| var Girl = { name: 'Arutoria', job: ["护士", "空姐", "教师"], }
var girlFriend = Object.create(Girl, { name: { value: "Amia" } });
console.log(girlFriend.name); console.log(girlFriend.job)
|
寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function createGirlFriend(original) { var clone = new Object(original); clone.sayHi = function () { console.log("hi"); }; return clone; }
var Girl = { name: 'Arutoria', job: ["护士", "空姐", "教师"], }
var girl = createGirlFriend(Girl); girl.sayHi(); console.log(girl.name); console.log(girl.job);
|
寄生组合式继承
组合继承是js最常用的继承模式,组合继承最大的问题就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型时,另一次是在子类型构造函数内部。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function object(o) { function F() {} F.prototype = o; return new F(); }
function inheritPrototype(subType, suberType) { var prototype = object(suberType.prototype); prototype.constructor = subType; subType.prototype = prototype; }
function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } SuperType.prototype.sayName = function () { console.log(this.name); }
function SubType(name, age) { SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function () { console.log(this.age); }
var girl1 = new SubType("Arutoria", 20); girl1.sayName(); girl1.sayAge();
|