1.原型链继承
特点:
1.子类型的原型是父类型的实例
2.可以继承构造函数和原型链上的属性和方法
缺点:
1.父类引用类型的属性会被所有实例共享;
2.在创建Child 的实例时, 不能向Parent传参
function Parent() {
this.name = "张三"
this.subject = {sex: "男", age: 40}
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child() {}
Child.prototype = new Parent()
var child = new Child()
var child2 = new Child()
var person = new Parent()
child.subject.sex = '女'
console.log(child.subject) // {sex: '女', age: 40}
console.log(child2.subject) // {sex: '女', age: 40}
child.name = 'wang'
console.log(child.name) // wang
console.log(child2.name) // 张三
child2.getName() // 张三
console.log(child instanceof Parent) // true
2.构造函数继承
缺点:
1.继承构造函数内部的属性和方法,不能继承原型链上的方法和属性;
2.属性和方法都在构造函数中定义,每次创建实例都会创建一遍属性和方法
3.只是子类的实例,不是父类的实例
优点:
1.child可以向parent传参;
2.引用类型的属性不会被所有实例共享
function Parent() {
this.firstName = "张"
this.lastName = "三"
this.getFirstName = function() {
console.log(this.firstName)
}
this.subject = {sex: '男', age: 10}
}
Parent.prototype.getName = function() {
console.log(this.firstName + this.lastName)
}
function Child() {
Parent.call(this)
this.lastName = "四"
this.id = "student"
}
var child1 = new Child()
var child2 = new Child()
child1.subject.sex = '女'
console.log(child1.firstName) // 张
console.log(child1.subject) // {sex: '女', age: 10}
console.log(child2.subject) // {sex: '男', age: 10}
child2.getFirstName() // 张
console.log(child instanceof Parent) // false
child1.getName() // Uncaught TypeError: child1.getName is not a function
// 因为没有继承父类的原型
3.组合继承
组合 原型链继承 和 借用构造函数继承
function Parent(name) {
this.name = name
this.subject = {sex: '男', age: 15}
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name) {
Parent.call(this, name)
}
Child.prototype = new Parent()
// 此时Child的构造函数会指向Parent
Child.prototype.constructor = Child
var child = new Child('xiaoxiao')
var child2 = new Child('linlin')
console.log(child.name) // xiaoxiao
child.subject.age = 18
console.log(child2.subject.age) // 15
child.getName() // xiaoxiao
4.原型式继承
特点:以一个对象为原型创建新的对象
缺点:
1.引用类型的属性会被所有实例共享;同原型链继承
function createObject(o) {
function F() {}
F.prototype = o
return new F()
}
var person = {
name: '王琳',
subject: {
sex: '女',
age: 18
}
}
var child = createObject(person)
var child2 = createObject(person)
console.log(child.name) // 王琳
console.log(child.subject) // {sex: '女', age: 18}
child.name = '张小花'
child.subject.age = 20
console.log(child.name) // 张小花
console.log(child2.name) // 王琳
console.log(child.subject) // {sex: '女', age: 20}
console.log(child2.subject) // {sex: '女', age: 20}
ES5通过Object.create()方法规范了原型式继承,可以接受两个参数,一个是用作新对象原型的对象和一个可选的为新对象定义额外属性的对像
var person = {
name: '王琳'
}
var child = Object.create(person, {sex: {value: 16}})
console.log(child) // {sex: 16, [[prototype]]: {name: '王琳'}}
var Base = function () {
this.a = 2
}
Base.prototype.a = 3;
var o1 = new Base();
var o2 = Object.create(Base);
console.log(o1.a) // 2
console.log(o2.a); // undefined
// 注意这里的o2只是继承了Base的prototype属性,a只是prototype的属性
// a并不在o2的原型链上,所以直接读o2.a读不到
5.寄生式继承
在原型式继承的基础上添加新的属性和方法来增强对象
function CreateObj(o){
var newob = Object.create(o)
newob.getName = function(){ // 增强对象
console.log(this.name);
}
return newob; // 指定对象
}
var ob = {name: 'xiaoxiao'}
var p1 = CreateObj(ob);
p1.getName(); // xiaoxiao
6.寄生式组合继承
使用寄生式继承来继承父类原型对象,使用组合继承来继承增强过的原型对象和实例属性
基本思路:不必为了指定子类型的原型而调用父类的构造函数,创建一个父类原型的副本
function Parent(name) {
this.name = name
}
Parent.prototype.getName = function () {
console.log(this.name)
}
function Child(name, job) {
Parent.call(this, name)
this.job = job
}
Child.prototype = CreateObj(Parent.prototype)
// Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
var sub = new Child('张三', 'student')
sub.getName()
ES6新增了一个方法,Object.setPrototypeOf,可以直接创建关联,而且不用手动添加constructor属性
Object.setPrototypeOf(SubType.prototype, SuperType.prototype)
console.log(SubType.prototype.constructor === SubType) // true