对象的继承:A对象通过继承B对象,就能直接拥有B对象的所有属性和方法。
方法一:原型链继承
子类型的原型为父类型的一个实例对象 。
function Person(name,age){
this.name = name,
this.age = age,
this.play = [1,2,3]
this.setName = function(){}
}
Person.prototype.setAge = function(){}
function Student(price){
this.price = price,
this.setScore = function(){}
}
Student.prototype = new Person()//子类型的原型为父类型的一个实例对象
var s1 = new Student(150000)
var s2 = new Student(140000)
console.log(s1,s2);
但这种方法的本质是通过将子类的原型指向了父类的实例,所以子类的实例就可以通过_proto_访问到Student.prototype 及Person的实例,就可以访问到父类的私有方法,然后再通过__proto__指向父类的prototype就可以获得到父类原型上的方法。
子类继承父类的属性和方法是将父类的私有属性和公有方法都作为自己的公有属性和方法。
注意:我们需要在子类中添加新的方法或者是重写父类的方法时候,切记一定要放到替换原型的语句之后
// Student.prototype.sayHello = function () { }//在这里写子类的原型方法和属性是无效的,
//因为会改变原型的指向,所以应该放到重新指定之后
Student.prototype = new Person()
Student.prototype.sayHello = function () { }
特点:
- 父类新增原型方法/原型属性,子类都能访问到
- 简单,易于实现
缺点:
- 无法实现多继承
- 来自原型对象的所有属性被所有实例共享
- 创建子类实例时,无法向父类构造函数传参
- 要想为子类新增属性和方法,必须要在
Student.prototype = new Person()
之后执行,不能放到构造器中
方法二:构造函数继承
在子类构造函数中通过call()调用父类构造函数
function Person(name,sge){
this.name = name,
this.age = age,
this.setName = function(){}
}
Person.prototype.setAge = function(){}
function Student(name,age,price){
Person.call(this,name,age)
//this.Person(name,age)
// this.name = name
// this.age = age
this.price = price
}
var s1= new Student('Tom',20,15000)
//只能继承父类的属性和方法,不能继承父类原型的属性和方法
特点:
- 解决了原型链继承中子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性和方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
方式三: 原型链+借用构造函数的组合继承
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过父类实例作为子类原型,实现函数复用。
function Person(name,age){
this.name = name,
this.age = age,
this.setAge = function(){}
}
Person.prototype.setAge = function(){
console.log("111");
}
function Student(name,age,price){
Person.call(this,name,age)
this.price = price
this.setScore = function(){}
}
Student.prototype = new Person()
Student.prototype.constructor = Student
Student.prototype.sayHello = function(){}
var s1 = new Student('Tom',20,15000)
var s2 = new Person('Jack',21,14000)
console.log(s1);
console.log(s1.constructor);
console.log(s2.constructor);
优点:
- 可以继承实例属性/方法,也可以继承原型属性/方法
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点:
- 调用了两次父类构造函数,生成了两份实例