美文网首页
JS如何实现继承(未完成 谨慎参考)

JS如何实现继承(未完成 谨慎参考)

作者: moyahuang | 来源:发表于2019-11-14 21:44 被阅读0次

    《JS语言精粹》刷到继承部分,有点刷不动了。决定跟这一部分死磕到底。希望完成后也可以帮到其他初学的旁友们。

    继承可以帮我们实现1. 代码重用 2. 以及进行规约

    JS的对象采用原型继承(prototype-based inheritance)机制。当属性和方法添加到对象的原型上时,该对象及其后代便都会具备这些属性和方法。

    在其他诸如C语言等程序语言中,通常都有一个函数叫做构造函数(constructor)。构造函数就是为对象实例赋初值的。JS中没有类(ES6以前),普通函数(function)即可以用作构造函数,不过为了跟普通函数进行区分,一般会把用作构造函数的普通函数名首字母大写。

    当定义了这样一个函数(类)时

    function Crane(a, b){}
    

    JS会为Crane.prototype增加一个属性constructor,其值指向刚才定义的方法(对象)或构造函数(以下统称为构造函数)本身,并且该构造函数还包括下面几个属性

    Crane.prototype={constructor: this}
    

    用一张图可以表示为

    constructor.png

    同时,构造函数本身也有constructor属性,这个属性指向Function构造函数

    function_constructor.png

    注:ES6引入了关键词class,JS也可以像其他语言一样在class内部作用域定义构造函数。

    构造函数模式如何继承

    使用Parent.call

    上面提到的构造函数使用关键词new即可创建对象,这种模式怎样实现继承呢?我们看到下面的例子

    function Bird(type, color){
        this.type=type;
        this.color=color;
        this.fly=function(){
            console.log(this.color+' '+this.type+" is flying!");
        }
    }
    //Parrot也是鸟 它有所有Bird拥有的属性
    function Parrot(type, color){
        Bird.call(this, type, color); //继承鸟的所有属性和方法
        this.talk=function(){
            console.log(this.color+' '+this.type+" is talking!")
        }
    }
    
    var prr=new Parrot("鹦鹉", "彩色de");
    prr.talk();
    prr.fly();
    

    使用ES6的类关键词

    ES6引入了类机制,使用关键词extends即可实现继承。上面的代码可以改成这样

    class Bird{
        constructor(type, color){
            this.type=type;
            this.color=color;
        }
        fly(){
            console.log(this.color+' '+this.type+" is flying!");
        }
    }
    
    class Parrot extends Bird{
        constructor(type, color){
            super(type, color);
        }
        talk(){ ... }
    }
    

    伪类模式(不推荐)

    我认为伪类模式与上面的继承方法的不同点在于,子类的构造函数会包含所有的属性,而无法不会进行属性的传递。因其关键点在于将子类的原型设置为父类对象。下面看一个例子

    var Mammal=function(name){
        this.name=name;
    }
    //注意这里要采用加强prototype的方式添加方法
    Mammal.prototype.get_name=function(){
        return this.name;
    }
    Mammal.prototype.says=function(){
        return this.saying||'';
    }
    var Cat=function(name){
        this.name=name;
        this.saying='meow';
    }
    Cat.prototype=new Mammal();
    Cat.prototype.get_name=function(){
        return this.says()+' '+this.name;//调用父类的方法
    }
    var myCat=new Cat("Katy");
    console.log(myCat.get_name()); // "meow Katy"
    

    当然,《JS语法精粹》里对上述的一些步骤进行了方法的封装,使程序表达性更高,隐藏了重复写prototype的一些"ugliness"。

    var Cat=function(name){
        this.name=name;
        this.saying="meow";
    }.inherits(Mammal)
    .method("get_name",function(){...});
    

    其中inherits是这么定义的

    Function.method("inherits",function(Parent){
        this.prototype=new Parent();
        return this;
    })
    

    Function.method也是《JS语法精粹》定义的一个方法,常常用到,这里我写一遍算是复习了

    Function.prototype.method=function(name, func){
        if(this.prototype[name]!=="function"){
            this.prototype[name]=func;
            return this;
        }
    }
    

    参考资料

    1. https://www.freecodecamp.org/news/a-guide-to-prototype-based-class-inheritance-in-javascript-84953db26df0/

    2. 《JS语法精粹》

    相关文章

      网友评论

          本文标题:JS如何实现继承(未完成 谨慎参考)

          本文链接:https://www.haomeiwen.com/subject/rzudictx.html