garinghu/myblog

es5实现继承

Opened this issue · 0 comments

今天有个小伙伴接到了百度地图的电话面试,人家问了这个问题,我感觉这个问题我应该放在原型那章解释的,于是在这里补充一下

吐槽一下为啥百度地图没有搭理我,就因为我不咋会react?

本文参考了链接

这个问题其实是在变相考原型链

js的底层是没有类的概念的,有的只是通过函数来模仿类,我的原型链的文章在这里链接

所以继承也要通过原型链

//先来个父类,带些属性
function Super(){
    this.flag = true;
}
//为了提高复用性,方法绑定在父类原型属性上
Super.prototype.getFlag = function(){
    return this.flag;
}
//来个子类
function Sub(){
    this.subFlag = false;
}
//实现继承
Sub.prototype = new Super;
//给子类添加子类特有的方法,注意顺序要在继承之后
Sub.prototype.getSubFlag = function(){
    return this.subFlag;
}
//构造实例
var es5 = new Sub;

下面我画个图来理解一下
Alt text

比较有趣的是这种写法是把子类的原型和父类的实例等同起来,这样做的缺点是当父类的属性发生变化时,子类继承来的属性也会发生变化

function Super(){
    this.flag = true;
}
function Sub(){
   this.subFlag = false;
}
Sub.prototype = new Super;
var obj = new Sub();
obj.flag = false;  //修改之后,由于是原型上的属性,之后创建的所有实例都会受到影响
var obj2 = new Sub();
obj2.subFlag = true;
var obj_2 = new Sub();
console.log(obj.flag)  //false;
console.log(obj.subFlag) // false

其中obj是Sub的实例对象,而Sub中没有flag这个属性,所以只能在其原型中找,所以obj.flag修改的是原型上的属性,会影响Sub的所有实例,改动的方法就是让Sub中也有继承过来的flag属性,而不是去原型对象中找

function Super(){
    this.flag = true;
}
function Sub(){
    Super.call(this)  //如果父类可以需要接收参数,这里也可以直接传递
}
var obj = new Sub();
obj.flag = flase;
var obj_2 = new Sub();
console.log(obj.flag)  //依然是true,不会相互影响

用call来改变Super的指向,是一个不错的方法,但此方法只能拿到函数体内部的属性或方法,如果与原型链的方法结合一下就更完美了

function Super(){
    this.flag = true;
}
Super.prototype.getFlag = function(){
    return this.flag;     //继承方法
}
function Sub(){
    this.subFlag = flase
    Super.call(this)    //继承属性
}
Sub.prototype = new Super;
Sub.prototype.constructor = Sub;
var obj = new Sub();
Super.prototype.getSubFlag = function(){
    return this.flag;
}

为什么要让Sub的原型对象的构造器再指回Sub,是因为前一步把Super的实例赋值给了Sub的原型的对象 会导致Sub.prototype的constructor指向Super;然而constructor的定义是要指向原型属性对应的构造函数的所以还要指回来