Js原型链解读

前言

在JavaScript中没"子类”和“父类”的概念,进一步地也没有“类”和“实例”的的区分。它靠一种看上去十分古怪的”原型链“(prototype chain)模式来实现继承。学过JAVA等编程语言的人可能会认为这是对Java等语言的继承实现方式的一种拙劣并且失败的模仿,然而事实并非如此,原型链模式和我们常见的Class模式分别是两种编程范式prototype_base和class_base的实现,前者在动态语言中似乎十分常见,而后者主要在静态语言领域流行。下面是维基百科关于prototype_base模式的介绍:

Prototype-based programming is a style of object-oriented programming in which behaviour reuse (known as inheritance) is performed via a process of reusing existing objects via delegation that serve as prototypes. This model can also be known as prototypal, prototype-oriented, classless, or instance-based programming. Delegation is the language feature that supports prototype-based programming.
Prototype object oriented programming uses generalized objects, which can then be cloned and extended. Using fruit as an example, a "fruit" object would represent the properties and functionality of fruit in general. A "banana" object would be cloned from the "fruit" object, and would also be extended to include general properties specific to bananas. Each individual "banana" object would be cloned from the generic "banana" object. Compare to the class-based paradigm, where a "fruit" class (not object) would be extended by a "banana" class

维基原文

如何理解原型链

我们以一个名字叫Foo()的函数为例。我们定义:

function Foo(){


}

然后再var f1 = new Foo(),var f2 = new Foo(),这期间都有什么事情发生呢?我们通过一张图来看一下:

prototype.jpg

先介绍两个概念:_proto_prototype:

  • _proto_:引用《JavaScript权威指南》中的说明:

Every JavaScript object has a second JavaScript object (or null ,
but this is rare) associated with it. This second object is known as a prototype, and the first
object inherits properties from the prototype.
就是说就是每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。既然有这么一个原型对象,那么对象怎么和它对应的?如何描述这种对应关系?答案就是通过_proto_,对象__proto__属性的值就是它所对应的原型对象。

  • prototype: 与_proto_不同,prototype是函数才有的属性。当你创建函数时,JS会为这个函数自动添加prototype属性,值是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)。它的存在主要是为了存放共享的数据和实现继承。

  下面结合上面的图示来分析,我们可以看到function Foo()对应一个Foo.prototype的原型,那么function FooFoo.prototype之间的关系是什么尼?
  图里其实已经展示得很清楚了,functon Foo()Foo.prototype的构造函数,Foo.prototypefunction Foo()的原型实例。当我们使用new关键字创建var f1 = new Foo(),var f2 = new Foo()后,f1、f2中会有一个_proto_字段指向Foo.prototype,这种xxx._proto_._proto....的指向就代表了原型链的结构(应该是个森林)。同时每个函数function xxx()其实都是通过function Function()来创造的,所以function Foo()_proto_应该指向Function.prototype,并且function Function()自身的_proto_也指向Function.prototype
  事实上,所有function xxx()_proto_最终都会指向Function.prototype,而所有的xxx.prototype最后都会指向Object.prototype,最终指向null。关于function Object()这个函数其实有点像Java中的Object对象,所有原型都会继承自它的原型。这里有个有意思的问题,function Function()也是个函数,所以function Function()_proto_属性的值为Function.prototype,这也就意味着它自己创造了自己。这样的结果就是function Object()._proto_ = Function.prototype、而function Function()._proto._proto_ = Object.prototype,即Object instanceof Function == trueFunction instanceof Object == true翻译过来就是ObjectFunction的实例,FunctionObject的实例,这是一种类似先有鸡还是先有蛋的蜜汁尴尬局面。

总结:

  • 所有对象的_proto_字段都指向创建它的构造函数的原型, 最终都指向Object.prototype,类似xxx.prototype._proto_._proto_..._proto_ = Object.prototype = null就是原型链。
  • 所有函数都由function Function()创建,所以所有函数的(包括它本身)_proto_字段都会指向Function.prototype,最后才指向Object.prototype

使用原型链实现继承

定义父函数:

function Father() {
    this.age = "56"; }

Father.prototype.say = function () {
    alert("my age is "+this.age); 
} 

定义子函数:

function Son() {
    this.age = '26';
  this.play = "football"; }

Son.prototype.play = function () {
    alert("I like play "+this.play);
 }

实现继承后的原型链应该是:Son.prototype._proto_ = Father.prototype
实现方式:借用第三个函数过渡

function extends(Child,Father){
    var F = function(){};
    F.prototype = Father.prototype;
    //Child.prototype._proto_ = F.prototype = Father.prototype
    Child.prototype = new F();
    //原本Child.prototype.constructor = F,修改为Child
    Child.prototype.constructor = Child;
    
}

测试验证:Son的实例可以调用say()则说明继承成功。

    function Father() {
    this.age = "56"; }

    Father.prototype.say = function () {
    alert("my age is "+this.age); }

    function Son() {
    this.age = '26';
    this.play = "football"; }

    Son.prototype.play = function () {
    alert("I like play "+this.play); }

    function excents(Child,Father) {

    var F = function () {}
    F.prototype = Father.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;   }

    excents(Son,Father);  

    var son = new Son(); 
    son.say();

运行结果:


image

继承成功!

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

推荐阅读更多精彩内容