JavaScript原型基础
声明一个函数,函数会自动生成两个属性一个是constructor 属性指向构造函数,另一个是prototype属性指向原型对象。 实例化的对象是没有prototype属性的,会有有两个属性,一个是contructor 指向构造函数本身,另一个是__proto__属性指向构造器的prototype属性。
继续方式有几种
-
原型链继承 原型链继承的不足是:不能通过子类构造函数向父类构造器传递参数。
-
借用构造继承,这种方式解决了子类不能向父类构造器传递参数的局限,这种方式通过在子类中使用apply或者call改变父构造函数this来实现。
-
借用构造原型继承组合方式 缺点是调用了两次构造函数,实际上是在子类构造的时候调用了一次构造函数是在子类的原型上,在实例实话的时候借用的时候调用了一次。
3.1. 进入Child构造函数为属性赋值,分配内存空间,浪费内存;
3.2. 赋值导致导致效率下降,关键字new Child赋值无意义,出现代码冗余,赋值操作是通过子类构造函数的借用call来对父类构造函数进行赋值的
-
寄生组合继承实现, 寄生继承的组合实现方式,
原型链继承方式
缺点:
- 不能向父类构造函数传参
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
function Child (phone) {
this.phone = phone
}
Child.prototype = new Parent()
Child.constructor = Child
借用构造函数
优点
- 解决了可以向父类构造函数传参
缺点
- 调用了两次构造函数
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
function Child (name, age, sex, phone) {
Parent.call(this, name, age, sex, phone)
this.phone = phone
}
组合继承(借用构造与原型链方式)
优点
- 解决了原型链不能给父类传值的缺点
- 解决了子类不能调用父类方法原型上的方法
缺点
- 调用了两次构造函数,导致内存浪费,代码冗余
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
Parent.prototype.getname = function () {
return this.name;
}
function Child (ame, age, sex, phone) {
Parent.call(this,ame, age, sex, phone)
this.phone = phone
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
寄生组合方式
第一种方式:
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
Parent.prototype.getname = function () {
return this.name;
}
fucntion Middle () {
}
//这里把middle prototype 的原型对象指向了父类的原型对象空间,但是contructor 也发生了变化,变成了Parent
Middle.prototype = Parent.prototype
const middle = new Middle()
middle.prototype.constructor = Child
function Child (ame, age, sex, phone) {
this.phone = phone
}
Child.prototype = Parent.prototype
Child.prototype.constructor = Child
封装一下
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
Parent.prototype.getname = function () {
return this.name;
}
fucntion Middle () {
}
//这里把middle prototype 的原型对象指向了父类的原型对象空间,但是contructor 也发生了变化,变成了Parent
Middle.prototype = Parent.prototype
const middle = new Middle()
// 所以Child的原型对象指向middle的原型对象就是指向的Parent的原型对象了。此时Child.prototype.constructor === Parent, 所以要把当前对象的constructor 指向自己
Child.prototype = middle.prototype
指向构造函数本身,就是Child
function Child (ame, age, sex, phone) {
this.phone = phone
}
Child.prototype = Parent.prototype
Child.prototype.constructor = Child
//extends 方法的封装
function _extends(Sup, Sub) {
function Middle() {}
Middle.prototype = Sup.prototype
const middle = new Middle()
return middle
}
Child.prototype = _extends(Parent, Child);
Child.prototype.constructor = Child;
第三种方法
function Parent (name, age, sex){
this.name = name
this.age = age
this.sex = sex
}
Parent.prototype.getname = function () {
return this.name;
}
function _extends(Sup, Sub) {
const middle = Object.create(Sup.prototype)
Sub.prototype = middle
Sub.prototype.constructor = Sub
}
//这里是需要给父类传递参数的
function Child (name, age, sex, phone) {
Parent.call(this, name, age, sex)
this.phone = phone
}
_extends(Parent, Child)
let child = new Child('xb', 18, 'male', 13812345678)