js继承
- 原型链
- 构造函数
- 组合继承(原型链 + 构造函数)
- 原型式继承
- 寄生式继承
- 寄生组合继承
1.原型链继承
将父类的实例作为子类的原型
//父类
function School(name) {
//实例属性
this.name = name || "父类"
this.arr = [1]
}
//父类原型办法
School.prototype = {
constructor: School,
showName() {
console.log(this.name);
},
}
//子类
function Student(gender) {
this.gender = gender
}
Student.prototype = new School("子类")
Student.prototype.constructor = Student
//子类的实例
let std1 = new Student()
let std2 = new Student()
要害
Student.prototype = new School()
- 将父类的实例作为子类的原型
- new School()失去一个实例对象o,它的构造函数是School,o上没有constructor属性,但会继承School的prototype上的constructor
- 给o追加一个属性constructor指向Student
- 相当于通过o的继承实现的间接的继承,也就是原型链继承
长处
-
共享了父类原型上的办法
std1.showName() //子类 std1.showName === std2.showName //true
毛病
- 不能向父类传参 – 在实例化子类时想让std1带上name不能实现,只能手动追加
-
子类实例共享了父类构造函数的援用属性
std1.arr.push(2) console.log(std2.arr);//[1,2]
2.构造函数
将父类的构造函数在子类的构造函数中执行,扭转this指向
function School(name) {
this.name = name || "父类"
this.arr = [1]
this.showName = function () {
console.log(this.name);
}
}
function Student(name,gender) {
School.call(this,name)
this.gender = gender
}
let std1 = new Student("张三")
let std2 = new Student("李四")
要害
School.call(this,name)
- 将School中的this改为Student中的this,将name参数传入School返回
- 相当于拷贝了父类构造函数中的属性与办法
- 在实例化子类时都会这样拷贝一次
长处
- 能够向父类构造函数传参 – 通过call
-
不共享父类的援用属性
std1.arr.push(2) console.log(std2.arr);//[1]
毛病
-
办法不能复用
std1.showName === std2.showName //false
- 不能继承父类原型上的办法 – 只是对父类构造函数内属性与办法的拷贝
3.组合继承
联合原型链和构造函数
function School(name) {
this.name = name || "父类"
this.arr = [1]
}
School.prototype = {
constructor:School,
showName() {
console.log(this.name);
}
}
function Student(name, gender) {
School.call(this, name)
this.gender = gender
}
Student.prototype = new School()
Student.prototype.constructor = Student
let std1 = new Student("张三")
let std2 = new Student("李四")
- 蕴含了1和2的要害语句
长处
- 能够向父类传参数
- 共享复用父类原型上的办法
- 不共享父类构造函数上的援用属性
毛病
- 两个要害语句调用了两次父类构造函数,生成两个实例正本,影响性能
优化1
Student.prototype = new School()
替换为
Student.prototype = School.prototype
- 这种优化解决了两次调用,然而在批改constructor时,父类的也会扭转
优化2(完满
)
Student.prototype = new School()
替换为
Student.prototype = Object.create(School.prototype)
-
Object.create(proto),创立一个以proto为原型的对象,
未调用
父类构造函数并且失去一个能继承父类原型的对象
Student.prototype.__proto__ === School.prototype//true
- 批改子类的constructor不会影响到父类,相似与1中提到了o对象,对其追加constructor即可
let std1 = new Student("张三")
let sch1 = new School("理工")
std1.constructor === Student //true
sch1.constructor === School //true
4.原型式继承
2006年 Douglas Crockford介绍的一种不波及严格意义上构造函数的继承办法
不自定义类型也能够通过原型实现对象之间的信息共享
let School = {
name: "理工",
arr: [1],
showName() {
console.log(this.name);
}
}
function creat(o) {
function F() { }
F.prototype = o
return new F()
}
let sch1 = creat(School)
sch1.name = "工业"
sch1.showName() //工业
sch1.arr.push(2)
let sch2 = creat(School)
console.log(sch2.arr);//[1,2]
sch1.showName === sch2.showName //true
- 3中提到的Object.create()的原理和create函数一样
- 这种形式的优缺点与原型链继承形式相似
5.寄生式继承
let School = {
name: "理工",
arr: [1],
showName() {
console.log(this.name);
}
}
function create(o) {
function F() { }
F.prototype = o
return new F()
}
function enhance(obj) {
let clone = create(obj)
clone.showAge = function () {
console.log(this.age);
}
return clone
}
let sch1 = enhance(School)
let sch2 = enhance(School)
sch1.showName === sch2.showName;//true
sch1.showAge === sch2.showAge;//false
- 调用函数创建对象,再加强新对象,最初返回新对象
- 然而办法不能复用
6.寄生组合式继承
加强的形式与寄生式不同
function enhance(Student,School) {
let clone = create(School.prtotype)
clone.costructor = Student
Student.prototye = clone
}
- 其实这种形式就是3中的优化2,create就相当于Object.create()
ES6中class的继承形式在这里不再介绍,后续在介绍class时作为其中的一部分剖析
发表回复