学习JavaScript中的原型链式继承

最近在学习JavaScript的面向对象,被constructor,prototype和_proto_搞到头大,但还好,磕磕绊碰碰,终于了解了一点原型继承。接下来我们来看看这个原型继承是怎么回事

一、关于原型的几个概念

  1. prototype属性
  2. _proto_属性
  3. constructor属性

他们直观的关系是:

function/
    |——prototype/
              |—— constructor
              |—— __proto__
prototype属性

任何一个函数都存在着这样的一个prototype属性,这个属性是一个对象,称为原型对象。这个原型对象里有自函数一创建就生成的两个属性一个是constructor和 _proto_,除此之外我们可以给这个对象添加属性和方法,就像给一个普通对象动态添加属性和方法那样

example:
    //创建基类(或叫超类或叫父类)
    function Person(){};
    Person.prototype.name = 'kuohao';
    Person.prototype.age = 21;
    Person.prototype.method = function (){
        return this.name +':'+ this.age;
    }
    //给Person构造函数的原型对象添加一些属性和方法
    //(为什么说它是构造函数呢,因为需要用来构造对象,实际上跟普通函数一样)

现在原型对象就多了两个属性和一个方法

Person/
    |——prototype/
              |—— constructor
              |—— __proto__
              |——name:'kuhao'
              |——age:21
              |——method:function(){
                      return……
                      }

这个原型对象有啥用???
请看——

//实例化
var guy1 = new Person();
var guy2 = new Person();

console.log(guy1.name);    //'kuohao'
console.log(guy2.name);    //'kuohao'  

guy1.method()    //'kuohao':21
guy2.method()    //'kuohao':21

我们没有给他们定义属性和方法,他们继承了Person构造函数原型对象里面的属性和方法,注意我们也没给Person构造函数定义属性和方法噢

咋一看,跟构造函数和工厂模式差不多,他们都生成拥有相同属性和方法的对象。但是原型对象生成的对象有一个很重要的特点就是他们共用一个原型对象的属性和方法。

为什么这么说呢?
使用布尔运算来验证一下就知道了

guy1.method()===guy2.method;    //true

如果是构造函数生成的对象,他们的方法都不相等,原因就是构造函数生成的对象有不同的引用的地址,而构造函数的原型继承方法生成的对象指向了同一个引用地址,他们的对象都使用这个引用地址的属性和方法,所以他们的方法是相等的,对于生成的对象的new方法,在另外一篇文章会讲到。


_proto_属性

这是相当重要的一个属性,但是它不是标准属性,在标准中,它是不对外开放的,当时chrome和Firefox的私有属性中对外暴露了它,使得我们可以比较清楚了了解原型继承的过程。

__proto__

_proto_这个属性可以让我们访问创建当前对象的构造函数的prototype原型对象。那么当我们调用guy1.method()方法的时候,其实是这样的:

  1. 当js解析器解析guy1.method()的时候,先看看guy1对象实例里有没有method这个方法
    js解析器问:"喂,哥们,你的method方法呢?"
    guy1说:"这个方法是我老爸的,不在我这里"
    js解析器问:“怎么找到你老爸?”
    guy1指着_proto_说:“这里有道门,你进去就可以找到他了”

2.然后js解析器就又跑去找他老豆,找到他老豆后
问:“喂喂,你儿子叫我来找method方法,在哪?”
guy1的老豆Person就拿出一个箱子(prototype),说:“method方法就在里面,你拿去吧!”

如果Person父类还是没找到method方法的话,实际上它的prototype对象也有一个_proto_属性,可以访问guy1的爷爷类的prototype对象,找到method方法。

所以,这个查找是一环接一环的,就像递归一样。

![原型链,图片来自慕课网].PNG](http://upload-images.jianshu.io/upload_images/1577855-21c757167154f75a.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

constructor属性

constructor属性指向的是创建此对象的构造函数的引用,这个属性存在prototype原型对象中,构造函数的对象实例也可以通过constructor属性来访问构造它的那个函数。

构造与原型

这个属性对于原型继承的实现来说,不是很重要。

二、原型继承的实现

    //父类
    function Person(){};
    Person.prototype.method = function (){
        return 'hello';
    }

    //子类
    function Child(){};
    Child.prototype = Object.create(Person.prototype);
    Child.prototype.constructor = Child;
    Child.prototype.say = function (){
        return 'hello world';
    }
    
    var c1 = new Child();
    c1.method();    //'hello'
    c1.say();       //'hello world'
    //由此可见子类继承了父类的方法,也拥有自己的方法
Object.create()方法

Object.create()方法是ES5的一个用来创建一个指定原型和若干指定属性的对象的方法。
定义来自 Mozilla开发者文档

Child.prototype = Object.create(Person.prototye);

这句话的含义就是创建一个以Person原型对象为原型的空对象,赋值给Child的prototype原型对象.

Object.create(Person.prototye),相当与创建了这样一个对象:

{
    constructor
    //指向Person构造函数,这就是为什么上面要把这个属性指回Child的原因
    __proto__
    //指向Person.prototype,上面说到原型链继承正是通过这个属性层层查找实现的
}

将这个对象去覆盖Child子类的prototype,这就成功与Person父类搭上了关系再此之前,Person与Child没任何关系。


但是Object.create()这个方法是新方法,低级的浏览器,如IE9以下不支持,需要做一下兼容处理

examle:
    
        function createObejct(o){
            if(!Object.create){
                //新建一个构造函数,用来做临时对象
                function a(){};
                //把原型对象参数赋给这个空对象的原型对象
                a.prototype = o;
                return new a();
                //实例化一个出来一个原型对象指向原型对象参数的空对象,返回给上下文
            }else{
                return Object.create(o);
                //直接使用
            }
        }
Object.create的一些替代方法
  1. 直接将Person.prototype赋值给Child.prototype

Child.prototype = Person.prototype

这样Person和Child就共用一个原型对象,他们的属性和方法都是一样的,但是这个就有问题了,如果Child类想扩展自己的属性和方法,那么Person类也会受到影响。

这里要注意的是赋一个原型对象为Person.prototype的空对象(上面的方法)跟赋一个Person.prototype是不一样的。

前者Child.prototype指向空对象的引用再由空对象中的_proto_\指向Person.prototype,后者Child.prototype直接指向Person.prototype引用,后续的修改在都Person.prototype上,因为他们共用一个原型对象。

前者
后者

所以这个方法是非常不可取的,跟面向对象的多态特性相悖

2.new 一个Person的对象实例赋给Child的原型对象

Child.prototype = new Person()

这貌似是一个不错的方法,但是它也有弊端,就是事实上我们常常不会使用一个空的构造函数,来实例化对象,我们往往会将构造函数继承和原型继承结合在一起,所以我们的构造函数往往会有一些实例属性和实例方法,如果new Person()出来一个实例对象,对象里面还夹带着一些实例属性和方法,这看起来非常怪,虽然也是一个指向Person.prototype的对象。所以这种方法也不推荐使用,应该使用 Object.create() 较为妥当.

总结:

我个人觉得实现原型继承最重要就是两个属性的理解,prototype原型对象和_proto_这个接口的概念的理解,再结合原型链层层查找这种继承方式的直观感知,就能比较好地掌握原型式继承。我也是这两天才理解的原型链式继承,如果有所缪误,请批评指正!

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

推荐阅读更多精彩内容