原理: 子类的原型对象 指向 父类的实例 , 当 子类实例 找不到属性和方法时,会沿着原型链往上找。
优点:简单,既是子类实例也是父类实例,父类新加原型方法或者属性,子类都能访问到
缺点:
通过使用call、apply方法可以在新创建的对象上执行构造函数,用父类的构造函数来增加子类的实例
原理: 子类的构造函数中执行父类的构造函数,并且改变子类的this绑定
优点:简单,直接父类的属性和方法
缺点:无法继承原型链上的属性方法
将父类原型对象直接赋值给子类的构造函数,再将空属性的构造函数实例赋值给子类原型对象
优点:完美实现继承,解决了组合式继承带两份属性的问题; new Child的时候不用 每次都 new Parent
缺点: 子类的prototype添加方法会影响 父类的prototype
将父类原型对象直接赋值给子类的构造函数,再将空属性的构造函数实例赋值给子类原型对象
优点:完美实现继承,解决了组合式继承带两份属性的问题; new Child的时候不用 每次都 new Parent
将等待继承的原型对象克隆,再赋值给继承的原型对象
优点:直接通过对象生成一个继承该对象的对象
缺点:不是类式继承,而是原型式基础,缺少了类的概念
参考: https://www.jb51.cc/note/413574.html
https://blog.csdn.net/qq_42926373/article/details/83149347
js继承有5种实现方式:1、继承第一种方式:对象冒充
function Parent(username){
this.username = username
this.hello = function(){
alert(this.username)
}
}
function Child(username,password){
//通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承
//第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,
//第二步:执行this.method方法,即执行Parent所指向的对象函数
//第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法
this.method = Parent
this.method(username)//最关键的一行
delete this.method
this.password = password
this.world = function(){
alert(this.password)
}
}
var parent = new Parent("zhangsan")
var child = new Child("lisi","123456")
parent.hello()
child.hello()
child.world()
2、继承第二种方式:call()方法方式
call方法是Function类中的方法
call方法的第一个参数的值赋值给类(即方法)中出现的this
call方法的第二个参数开始依次赋值给类(即方法)所接受的参数
function test(str){
alert(this.name + " " + str)
}
var object = new Object()
object.name = "zhangsan"
test.call(object,"langsin")//此时,第一个参数值object传递给了test类(即方法)中出现的this,而第二个参数"langsin"则赋值给了test类(即方法)的str
function Parent(username){
this.username = username
this.hello = function(){
alert(this.username)
}
}
function Child(username,password){
Parent.call(this,username)
this.password = password
this.world = function(){
alert(this.password)
}
}
var parent = new Parent("zhangsan")
var child = new Child("lisi","123456")
parent.hello()
child.hello()
child.world()
3、继承的第三种方式:apply()方法方式
apply方法接受2个参数,
A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this
B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数
function Parent(username){
this.username = username
this.hello = function(){
alert(this.username)
}
}
function Child(username,password){
Parent.apply(this,new Array(username))
this.password = password
this.world = function(){
alert(this.password)
}
}
var parent = new Parent("zhangsan")
var child = new Child("lisi","123456")
parent.hello()
child.hello()
child.world()
4、继承的第四种方式:原型链方式,即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承
function Person(){
}
Person.prototype.hello = "hello"
Person.prototype.sayHello = function(){
alert(this.hello)
}
function Child(){
}
Child.prototype = new Person()//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
Child.prototype.world = "world"
Child.prototype.sayWorld = function(){
alert(this.world)
}
var c = new Child()
c.sayHello()
c.sayWorld()
5、继承的第五种方式:混合方式
混合了call方式、原型链方式
function Parent(hello){
this.hello = hello
}
Parent.prototype.sayHello = function(){
alert(this.hello)
}
function Child(hello,world){
Parent.call(this,hello)//将父类的属性继承过来
this.world = world//新增一些属性
}
Child.prototype = new Parent()//将父类的方法继承过来
Child.prototype.sayWorld = function(){//新增一些方法
alert(this.world)
}
var c = new Child("zhangsan","lisi")
c.sayHello()
c.sayWorld()
继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的。
原型链
首先得要明白什么是原型链,昆明北大青鸟http://www.kmbdqn.cn/建议可以在一篇文章看懂proto和prototype的关系及区别中讲得非常详细
原型链继承基本思想就是让一个原型对象指向另一个类型的实例
添加方法
在给SubType原型添加方法的时候,如果,父类上也有同样的名字,SubType将会覆盖这个方法,达到重新的目的。但是这个方法依然存在于父类中。
记住不能以字面量的形式添加,因为,上面说过通过实例继承本质上就是重写,再使用字面量形式,又是一次重写了,但这次重写没有跟父类有任何关联,所以就会导致原型链截断。
问题
单纯的使用原型链继承,主要问题来自包含引用类型值的原型。
借用构造函数
此方法为了解决原型中包含引用类型值所带来的问题。
这种方法的思想就是在子类构造函数的内部调用父类构造函数,可以借助apply()和call()方法来改变对象的执行上下文
传递参数
借助构造函数还有一个优势就是可以传递参数