function A(name) {
this.name = name;
this.arr = [1];
this.say = function(){
console.log('hi')
}
}
注意:
每个实例对象(Object)都有一个私有属性(称之为__proto__)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto,层层向上知道一个对象的原型对象为null。根据定义,null没有原型,并作为这个原型链中的最后一个环节。
继承方法 | 继承核心代码 | 优点 | 缺点 |
---|---|---|---|
原型链继承 | child.prototype = new parent() | 父类方法可以复用 | 不可以传参, 实例的引用类型会被共享 |
构造函数继承 | 在子类child里执行parent.call(this} | 实例的引用类型不共享 ,可以传参 | 父类的方法不能复用,子类实例的方法每次都是被单独创建的 |
组合式继承 | child.prototype = new parent(); parent.call(this) | 父类的方法可以被复用;父类的引用属性不会被共享; 子类构建实例时可以向父类传递参数 | 调用两次父类的构造函数,第一次给子类的原型添加了父类的name, arr属性;第二次又给子类的构造函数添加了父类的name, arr属性,从而覆盖了子类原型中的同名参数 |
原型式继承 | 原型式继承的object方法本质上是对参数对象的一个浅复制 | 父类方法可以复用 | 子类的引用属性会被所有子类的实例共享;子类构建实例时不能向父类传参; |
寄生式继承 | 使用原型式继承获得一个目标对象的浅复制,然后增强这个浅复制的能力 | - | - |
寄生组合继承 | - | - | - |
es6 class extends | - | - | - |
function parent(){
this.name = 'mike';
}
parent.prototype.getName = function() {
console.log(this.name)
}
function child(){
}
child.prototype = new parent();
child.prototype.constructor = child;
var instanceChild = new child();
instanceChild.getName() ;// 'mike;
原型链继承缺点:
function parent() {
this.names = ['mike1', 'mike2'];
}
function child() {
}
child.prototype = new parent();
child.prototype.constructor = child;
var instanceChild = new child();
instanceChild.names.push = 'mike3';
console.log(instanceChild.names); // mike1, mike2, mike3
var instanceChild2 = new child();
instanceChild2.names.push = 'mike4';
console.log(instanceChild2.names); //mike1, mike2, mike3, mike4
function parent(name) {
this.names = name
}
function child(name) {
parent.call(this, name)
}
var instanceChild = new child('mike');
console.log(instanceChild.name); // mike
var instanceChild2 = new child('mike2');
console.log(instanceChild2.name); //mike2
优点:
function parent(name) {
this.names = name
this.body = ['head', 'foot']
}
function child(name, age) {
parent.call(this, name)
this.age = age
}
child.prototype = new parent()
child.prototype.constructor = child;
var instanceChild = new Child('mike', '8')
instanceChild.body.push('main')
console.log(instanceChild.name, instanceChild.age); // mike 8
console.log(instanceChild.body) // ['head', 'foot', 'main']
var instanceChild2 = new Child('mike2', '8')
instanceChild.body.push('main2')
console.log(instanceChild2.name, instanceChild.age); // mike2 8
console.log(instanceChild2.body) // ['head', 'foot', 'main2']
优点:
复制传入的对象到创建对象的原型上,从而实现继承
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
var person = {
name : 'mike'
body : ['head','foot']
}
var person1 = createObj(person)
var person2 = createObj(person)
console.log(person1) //mike
person1.body.push('main')
console.log(person2) //['head', 'foot', 'main']
缺点:
ECMAScript5通过新增Object.create()方法规范化了原型式继承。这个方法接受了两个参数:一个用作新对象原型的对象和(可选)的一个为新对象定义额外属性的对象。在传入一个参数的情况下,Object.create()与object()方法的行为相同
var person1 = createObje(person); => var person1 = Object.create(person)
可以使用Object.create来代替上述createObj的实现,原理基本上是一样的。寄生式继承其实就是createObj的内部某种形式来增强对象(这里的增强可以理解为添加对象的方法,最后返回增强之后的对象)
function createEnhanceObj(o) {
//代替原型式继承的createObj
var clone = Object.create(o) // 通过调用函数创建一个新对象
clone.getName = function () {//以某种方式来增强这个对象
console.log('hi')
}
return clone;
}
var person = {
name: 'mike',
body: ['head', 'foot']
}
var instancePerson = createEnhance(person)
instancePerson.getName(); // hi
缺点:
不需要为了子类的原型而多new了一次父类的构造函数,如Child.prototype = new Parent() 只需要复制父类原型的一个副本给子类原型即可
function inheritPrototype(Parent, Child){
Child.prototype = Object.create(Parent.prototype) //创建父类原型的浅复制
Child.prototype.constructor = Child; // 将子类的原型的构造函数替换
}
function Parent(name) {
this.name = name
}
Parent.prototype.getNmae = function () {
console.log(this.name)
}
function Child(color) {
Parent.call(this, 'arzh')
this.color = color
}
inheritPrototype(Parent, Child)
var arzhChild = new Child('red')
console.log(arzhChild.name) // 'arzh'
优点:
不必为了指定子类型的原型而调用父类型的构造函数
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
toString() {
return this.x + '' + this.y
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y) //调用父类的constructor(x, y)
this.color = color
}
toString() {
return this.color + ' ' + super.toString() // 调用父类的toString()
}
}
var colorPoint = new ColorPoint('1', '2', 'red')
console.log(colorPoint.toString()) // red 12
参考文章:
[1]《js继承、构造函数继承、原型链继承、组合继承、组合继承优化、寄生组合继承》
[2]《前端必知必会ES5、ES6的7种继承》
[3]《JavaScript高级编程》