function Person (name,age,language){
this.name = name;
this.age = age;
this.language = language;
this.sleep = function (){
console.log('im '+this.name+' im sleeping')
}
}
Person.prototype.speak = function(){
console.log('im '+this.name+' im speak '+this.language)
}
Person.prototype.eyes = 4
原型链继承
原理
将父类的实例作为子类的原型
子类.prototype = new 父类()
function Chinese(province){
this.province = province
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
Chinese.prototype = new Person()
Chinese.prototype.constructor = Chinese //修复constructor的指向
//如果有 prototype 上的方法和属性,要放在这里之后
Chinese.prototype.language = 'chinese'
let gromy = new Chinese('吉林')
看下gromy都有什么?
gromy.speak()
VM5382:2 im undefined im speak chinese
gromy.sleep()
VM5278:6 im undefined im sleeping
gromy.eat()
VM6138:4 im chinese,im eating
所以子类的实例可以使用父类的方法,但是由于无法向父类传参数,所以 没有name
优点
- 实现简单
-
缺点
不能向父类的构造函数传参
-
使用
构造函数继承
原理
在子类构造函数中通过 call 将父类的构造器中的内容合并
function Chinese(name,age,language,province){
this.province = province
Person.call(this,name,age,language)
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
Chinese.prototype.language = 'chinese'
let gromy = new Chinese('gromy',18,'english')
属性,方法都合并过来了gromy.sleep()
VM5659:6 im gromy im sleeping
gromy.speak()
VM5935:1 Uncaught TypeError: gromy.speak is not a function
at <anonymous>:1:7
gromy.eat()
VM6178:5 im english,im eating
优点
可以实现多继承(使用多个call)
- 可向父类传参(实际是把属性在构造器中合并过来了)
缺点
- 因为是合并过来的,所以每个子类的实例都是副本,影响性能
-
使用
原型+构造器组合
function Chinese(name,age,language,province){
this.province = province
Person.call(this,name,age,language)
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
Chinese.prototype = new Person()
Chinese.prototype.constructor = Chinese //修复constructor的指向
//如果有 prototype 上的方法和属性,要放在这里之后
Chinese.prototype.language = 'chinese'
let gromy = new Chinese('gromy',18,'chinese','吉林')
gromy.sleep()
VM6305:6 im gromy im sleeping
gromy.speak()
VM6305:10 im gromy im speak chinese
gromy.eat()
VM6307:5 im chinese,im eating
gromy.eyes
4
优点
可以继承所有父类的属性和方法
- 可传参数
缺点
- 部分可实现多继承(call的部分)
-
原型+构造器优化
组合的最大弊端是调用了两次父类的构造器,两次实例化
function Chinese(name,age,language,province){
this.province = province
Person.call(this,name,age,language)
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
Chinese.prototype = Person.prototype
//Chinese.prototype.constructor = Chinese
Chinese.prototype.language = 'chinese'
let gromy = new Chinese('gromy',18,'chinese','吉林')
gromy.sleep()
VM6422:6 im gromy im sleeping
gromy.speak()
VM6422:10 im gromy im speak chinese
gromy.eat()
VM6424:5 im chinese,im eating
gromy.eyes
4
优点
继承了所有父类的属性和方法
-
缺点
由于子类直接被赋值了父类的prototype,所以子类的实例的 proto 指向了父类
原型+构造器优化(使用Object.assign())
Object.assign() 是使用现有的对象来提供新创建的对象的 会将原型作用在实例的 proto 上
function Chinese(name,age,language,province){
this.province = province
Person.call(this,name,age,language)
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
Chinese.prototype = Object.assign(Person.prototype) //核心
Chinese.prototype.constructor = Chinese //核心
Chinese.prototype.language = 'chinese'
gromy.__proto__
gromy.proto === Chinese.prototype
优点
-
缺点
-
es6的class
class Person {
constructor(name,age,language){
this.name = name;
this.age = age;
this.language = language;
this.sleep = function(){
console.log('im '+this.name+' im sleeping')
}
}
speak(){
console.log('im '+this.name+' im speak '+this.language)
}
}
class Chinese extends Person{
constructor(name,age,language,province){
super(name,age,language)
this.province = province
this.eat = function(){
console.log('im '+this.language+',im eating')
}
}
}
let gromy = new Chinese('gromy',18,'chinese','吉林')
gromy.sleep()
VM6422:6 im gromy im sleeping
gromy.speak()
VM6422:10 im gromy im speak chinese
gromy.eat()
VM6424:5 im chinese,im eating
gromy.eyes
4
优点
-
缺点
浏览器对支持es6有限制