深入JavaScript继承原理

javascript继承

ES6之前,JavaScript本质上不能算是一门面向对象的语言,因为它对于封装,继承,多态这些面向对象语言的特点并没有在语言层面上提供原生的支持。但是它引入了原型(prototype)的概念,可以让我们以另一种方式模仿类,并通过原型链的方式实现了父类子类共享属性的继承以及身份确认机制。其实面向对象概念本质上不是某种语言的特质,而是一种设计思想,如果你深韵面向对象的编程思想,即使用c这种面向过程的语言也能写出面向对象的代码(典型的代表就是windows NT内核实现),而JavaScript亦是如此,正式由于JavaScript本身对编程没有一个语言上的支持标准,所以才有了五花八门的“类继承”代码,所幸,es6增加了class,extends,static等关键字用以在语言层面上支持面向对象,但是还是有些保守,我们先列举出es6之前常见的几种继承方案。

ES6之前的继承

原型赋值继承

简而言之,就是直接将父类的一个实例赋值给子类的原型,如下实例:

如代码中1处所示,这种方式是直接new了一个父类的实例,然后赋值给子类的原型,这样也就相当于直接将父类的原型中的方法和属性以及挂在this上的各种方法属性全赋值给了子类的原型,简单粗暴,因为man本身没有getClassName方法,这种继承方式下,所有的子类实例会共享一个父类对象的实例,这种方案最大的问题就是子类无法通过父类创建私有属性。比如每一个Person都有一个名字,我们在初始化每一个Man的时候要指定一个不同的名字,然后子类将这个名字传递给父类,对于每隔man来说,保存在相应的person中的name应该是不同的,但是这种方式根本做不到。所以,这种继承方式,在实战中基本不用!

调用构造函数方式


这里在子类的构造函数里用子类实例的this去调用父类的构造函数,从而达到继承父类属性的效果,这样以来,每new一个子类实例,构造函数执行完后,都会有自己的一份资源(name),但是这种办法只能继承父类构造函数中声明的实例属性,并没有继承父类原型的属性和方法,所以就找不到getName方法,所以最后一行代码报错,为了同时继承父类原型,从而诞生了组合继承方式:

组合继承


这个例子很简单,这样不仅会继承构造函数中的属性,也会继承父类原型链中的属性,但是有个问题,Man.prototype = new Person();这句话执行后,Man的原型如下:


也就是说Man的原型中已经有了name属性,而之后创建man1时传给构造函数的name则是通过this重新定义了一个name属性,相当于只是覆盖掉了name原型中的属性(原型中的name依然还在),这样很不优雅。

分离组合继承

这是目前es5中主流的继承方式,也叫作寄生组合继承


这里用到了Object.create(obj)方法,该方法会对传入的obj对象进行浅拷贝,和上面组合继承的主要区别就是:将父类的原型复制给子类原型,这种做法很清晰:

    1.构造函数中继承父类属性/方法,并初始化父类。

    2.子类原型和父类原型建立联系。

还有一个问题就是constructor属性,我们来看一下:


contstructor是类的构造函数,我们发现Person和Man的实例的constructor都指向Person,当然,这并不会改变instanceof的结果,但是对于需要用到constructor的场景,就会有问题,所以一般会加上这么一句:


综合来看,es5下,这种方式就是首选,也是实际上最流行的。

此文至此,es5下的继承方式就讲完了。

ES6继承方法

ES6引入了class,extends,super,static(部分为ES2016标准)


ES6明确规定,class内部只有静态方法,没有静态属性,所以1处是有问题的,ES7有一个静态属性的提案,目前babel转码器支持,熟悉Java的可能对上面的代码感觉很亲切,几乎是自解释的。我们大概解释一下,按照代码中的标号对应:

    1.constructor为构造函数,一个类有一个,相当于es5中的构造函数标准化,负责一些初始化工作,如果没有定义,js vm会定义一个空的默认的构造函数。

    2.实例方法,ES6中可以不加“function”关键字,class内定义的所有函数都会置于该类的原型当中,所以class本身是一个语法糖。

    3.构造函数中通过super()调用父类构造函数,如果有super方法,super方法必须是构造函数中第一个执行的语句,this关键字在调用super后才可以使用。

    4.静态方法,在类定义的外部只能通过类名调用,内部可以通过this调用,并且静态函数是会被继承的,如示例中,sTest在Person中定义的静态方法可以通过Man.sTest()来调用。

es6和es5继承的区别

大多数浏览器的es5实现之中,每一个对象都有__proto__属性。指向对应的构造函数的prototype属性,Class作为构造函数的语法糖,同时有prototype和__proto__属性,因此同时存在两条继承链。

    1.子类的__proto__属性,表示构造函数的继承,总是指向父类。

    2.子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性

上面代码中,子类B的__proto__属性指向父类A,子类B的prototype属性指向父类A的prototype属性。这样的结果是因为,类的继承是按照下面模式实现的:

因此得到了上面的结果。


这两条继承链可以这样理解作为一个对象,子类(B)的原型(__proto__属性)是父类(A);作为一个构造函数,子类(B)的原型(prototype属性)是父类的实例。

es6继承的不足

    1.不支持静态属性,(除函数)。

    2.class中不能定义私有变量和函数。class中定义的所有函数都会被放到原型当中,都会被子类继承,而属性都会作为实例属性挂在this上,如果子类想定义一个私有的方法或定义一个private变量,便不能在class花括号中定义,这真的很不方便。

总结一下,和es5相比,es6在语言层面上提供了面向对象的部分支持,虽然大多数时候只是一个语法糖,但是用起来很方便,语义化更强,更直观,同时也给JavaScript继承提供了一个标准的方式。还有很重要的一点就是es6支持原生对象继承

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容