原型继承
让子类的原型指向父类的一个实例
1、方式:B.prototype= new A();A的实例本身就具备了父类A的私有属性和公有方法,子类B的原型指向它,那么子类B的实例就可以找到这些属性和方法
2、和传统后台语言的继承不一样,子类继承父类并不是把父类的属性和方法克隆一份给子类,这样的处理子类和父类就没有关系了。JS中的原型继承是让子类和父类建立原型链的机制,子类的实例调取父类原型上的方法都是原型链的查找机制完成的
存在的问题 :子类可以重写父类原型上的方法,这就是所谓的“重写”,子类和父类还有关系的
B.prototype.proto.getX=null; 把父类A的原型上的getX重写为null,A的其他实例也会受到影响(IE下不让使用__proto__就是为了防止重写)
原型继承存在的问题
- 1、父类实例私有的属性已经共有的属性,都变为子类实例的公有属性
- 2、如果子类B的原型上有很多属性和方法,重新指向A的实例后,之前的方法都没有用了
function A(){
this.x=100;
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x)
}
}
function B(){
this.y=200;
}
// B的原型指向A的实例
B.prototype=new A();
// f为B的实例
let f = new B();
call继承
把父类A作为普通函数执行,让A中的this变为B的实例,相当于给B的实例增加一些属性和方法(弊端:把父类A当作普通函数执行,和父类原型没有关系了,仅仅把A中的私有属性变为子类B实例的私有属性,A原型上的公有属性和方法和B及它的实例咩有什么关系)。new A()把A作为类创建它的实例this:实例
function A(){
this.x=100;
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x)
}
}
function B(){
//call继承 把A执行,让A中的this变为f
A.call(this);
this.y=200
}
let f = new B();
寄生组合继承
A的私有变为B 的私有,A的公有变为B的公有(这个继承也是ES6 class extends 继承的原理)
function A(){
this.x=100
}
A.prototype={
constructor:A,
getX:function(){
console.log(this.x)
}
}
function B(){
//基于call继承把A的私有变为B的私有
A.call(this)
this.y=200
}
B.prototype=Object.create(A.prototype)
Object.create:内置Object类自带的方法
- 1、创建一个空对象
- 2、让给你新创建的空独行的__proto__指向第一个传递进来的对象(把obj作为新创建的空对象的原型)
let obj = {
name:'xiaoming'
}
console.log(Object.create(obj));
ES6中class类实现继承
ES6创建类是有自己标准语法的(这种语法创建出来的类只能new执行,不能当作普通函数执行)
class Fn { //Fn是类名,没有小括号
constructor(){
// 等价于传统ES5类的构造体
this.x=100;
this.y=200
}
// 给Fn的原型上设置方法(只能设置方法,不能设置属性)
getX(){
console.log(this.x)
}
//把Fn当作以恶搞普通对象设置私有方法(和实例没有关系,同样也只能设置方法不能设置属性)
static AA(){
}
}
// 只能通过这种方式设置原型属性
Fn.prototype.BB=100
//只能通过这种方式设置Fn的属性
Fn.BB=200
let f = new Fn(10,20)
ES6中的继承
class A {
constructor(){
this.x=100
}
getX(){
console.log(this.x)
}
}
class B extends A{
// extends 类似于实现了原型继承
constructor(){
supper();
//类似于call继承:在这里supper相当于把A的constructor执行,并且让方法中的this是B的实例,supper里传递实參都是在给A的constructor传递
this.y=200
}
}
let f = new B();