常见继承的几种方式
原型继承
CHILD.prototype = new PARENT();
CHILD.prototype.constructor = CHILD(保证原型重定向后的完整性)
特点:
子类重写父类上的方法会导致父类的其他实例也受到影响;
父类的私有或者公有的属性和方法最后都会变成子类公有的属性和方法
function A (x) {
this.x = x
}
A.prototype.getX = function () {
console.log(this.x)
}
function B (y) {
this.y = y
}
B.prototype = new A(200) // 核心代码
B.prototype.constructor = B // 保证原型重定向后的完整性
B.prototype.getY = function () {
console.log(this.y)
}
let b1 = new B(300)
寄生组合继承
CALL继承+类似于原型继承,父类私有和公有的分别是子类实例的私有和共有的属性和方法;
CALL继承实现子类继承了父类的私有的属性和方法,且为自己的私有属性和方法;在子类CHILD中把父类PARENT当成一个普通函数(这样和PARENT原型上的属性方法则没有关系,摆脱了对原型上方法属性的继承),通过PARENT.call(this)来实现
类似于原型继承实现子类继承了父类的公有的属性和方法,且为自己的公有属性和方法;通过PARENT.prototype = Object.create(CHILD.prototype); PARENT.prototype.constructor = PARENT
function A (x) {
this.x = x
}
A.prototype.getX = function () {
console.log(this.x)
}
function B (y) {
A.call(this, 200) // 把A当成普通函数,等价于b1.x = 200
this.y = y
}
// Object.create(OBJ); 创建一个空对象,让空对象__proto__指向第一个参数OBJ
B.prototype = Object.create(A.prototype)
B.prototype.constructor = B
B.prototype.getY = function () {
console.log(this.y)
}
let b1 = new B(300)
ES6继承
// ES6中class创造出来的类不能当做普通函数执行;不能A(),只能用new来执行;所以当然不能在B中通过A.call(this)来继承;
class A {
constructor (x) {
this.x = x
}
getX () {
console.log(this.x)
}
}
class B extends A {
// constructor可以不写,不写浏览器默认会创建:constructor (...args) {super(...args)}
// 但是constructor一旦写了,在constructor中的第一句话必须是 super();
constructor (y) {
super(100) // 相当于A.call(this)
this.y = y
}
getY () {
console.log(this.y)
}
}
Object.create()相关
Object.create(OBJ); 实现了创建一个空对象,让空对象__proto__指向第一个参数OBJ
Object.create在IE低版本上不支持,我们重写下Object.create()函数
Object.create = function (obj) {
let o1 = {}
o1.__proto__ = obj
return o1
}
__proto__在IE低版本上不支持,所以这种Object.create重写在IE低版本不生效,改良为下面的版本;
Object.create = function (obj) { // 用一个空函数来做周转,bind函数的底层实现也用到了这一点
function Fn () {}
Fn.prototype = obj
return new Fn();
}
参考文档:别再被JS继承问倒了