JavaScript难点之原型和原型链

这篇文章主要是学习一下JavaScript中的难点------原型和原型链

自定义一个对象

我们学习一门编程语言,必然要使用它完成一些特定的功能,而面向对象的语言因为符合人类的认知规律,在这方面做得很好,今天我以JS为例,探索一下JS不同于其他面向对象的语言的地方-------原型和原型链

  • 首先,假设你在做一个项目,要造一个新的对象,标准库里面没有。那你只能用构造函数去构造一个
function Person(){
  //构造函数
}

以上Person就是一个构造函数,可以用来生成小明 小红 等等人类的实例。

var person = new Person() //构造出一个对象
person.name = 'xiaoming'
console.log(person.name) // 'xiaoming'

那原型在哪呢,认识原型先认识一下prototype属性

prototype

先看一段代码

Person.prototype.name = 'god'
var person2 = new Person()
console.log(person2.name) //person2的名字是啥呢???

从上面三行代码,猜一猜person2的名字是啥,没错,就是god

person2没有自己规定名字,但是Person构造函数的prototype上绑定了name,所以由Person构造函数构造的实例对象都默认有一个god的名字。

  • 而且这个prototype属性只存在构造函数上,也就是说prototype是构造函数的属性!!!
  • 那这个prototype指向了哪里,那个地方就是--------调用构造函数而生成的对象实例的原型,存的是这个原型的地址。
构造函数和原型的关系

以上就是构造函数和原型之间的关系,构造函数内部的prototype属性指向了实例对象原型的地址。

  • 原型里面存的是所有实例化对象的共有属性,比如这个例子的name
Person实例原型的内容

上面红框是Person实例的原型,如果不直观的话,下面直接看Array实例的原型

Array实例的原型

红框的都是大家熟悉的数组的方法吧,他们都放在数组的共有属性里面。


上面的两幅原型图里面,我们竟然发现有共同点,都有一个熟悉 constructor 属性,待会研究一下这个属性。


现在,我们已经知道了构造函数和原型的关系了,那person person2这些实例对象和原型有啥关系呢

__proto__属性

每一个构造的实例对象,内部有一个__proto__属性,它指向了实例原型,存的是原型的地址。

person.__proto__ === Person.prototype 
true
  • __proto__是对象的属性,而且是浏览器强逼着ECMAScript加上的这个规范。
person

以上是构造函数、实例、实例原型之间的关系,不过方向是单向的,哪能不能让它循环起来呢,原型可不可以指向构造函数或者实例呢?

constructor

  • 还记得上面我们发现的那个 不同的原型 都有的一个共同的属性 constructor嘛

构造函数、实例、实例原型之间的关系的方向可以循环的关键就在这里了。我们一直叫构造函数,构造函数的,为什么这么叫呢,对,就是这个原型里面的constructor属性。

  • 不过原型是无法指向实例的,只可以通过constructor属性指向 构造函数
Person === Person.prototype.constructor
true
construcor属性

上面就是经典的铁三角了。

由以上知识得出一个小公式

对象.__proto__ === 构造函数.prototype

而Person这个构造函数也是对象,那么

Person.__proto__ === ???

上面的问号填啥呢,我们按公式填空,应该是构造函数.prototype,Person构造函数的构造函数是谁呢?没错,就是Function

Person.__proto__ === Function.prototype
true

在控制台验证确实如此。

所以有些以前的疑惑也解开了

Array.__proto__ === Function.prototype
true
String.__proto__ === Function.prototype
true
  • 那问题又来了,构造函数.prototype也是对象啊,它指向谁
  • 既然是对象,那么里面就有__proto__属性
Person.prototype.__proto__ === ???

问号填什么呢,原型是由谁构造的呢,我们想到了所有对象的根----------Object

原型的原型

在控制台验证如下

Person.prototype.__proto__ === Object.prototype
true
Array.prototype.__proto__ === Object.prototype
true
String.prototype.__proto__ === Object.prototype
true

既然引出了Object,我们来看一下所有对象的祖宗的原型吧

Object.prototype.__proto__ === null
true
原型的原型

特殊的Function

前面我们看到了Function构造方法构造除了所有的函数,包括普通的构造函数。

那么他自身也是一个函数,所以也是由Function构造函数构造的。所以由总结的公式可以知道

Function.__proto__ === Function.prototype

而且,下面这个很重要,易错

Function.prototype === Object.__proto__ //哈哈,这个老别扭了吧,还给你倒过来写,很容易错的

解释:Object也是构造函数啊,属于对象。Object构造函数也是由Function把它构造出来的,所以是结果是true

最终的关系图

完整的总结

  • 当你new一个构造函数的时候,创建一个函数实例,那么 『 函数实例.__proto__ === 该构造函数.prototype
  • 所有的函数都是由Function构造出来的,那么 『被构造出来的其他函数.__proto__ === Function.prototype
  • 所有的构造函数的原型对象都是由Object构造出来的,那么 『所有的构造函数.prototype.__proto__ === Object.prototype

instanceof运算符的实质

首先这有几个题

Object instanceof Function
Function instanceof Object
Function instanceof Function
Object instanceof Object
  • 能不假思索的说出来吗,大声告诉我,答案是什么。
  • 没错,全是true

虽然 instanceof运算符算是我们的老朋友了,不过背后是咋判断的呢

规范是这么写的

object instanceof constructor

参数

  • object

    要检测的对象.

  • constructor

    某个构造函数

    instanceof运算符用来检测 constructor.prototype是否存在于参数 object的原型链上

  • 对于 Object instanceof FunctionObject.__proto__ === Function.prototypetrue,解决
  • 对于Function instanceof ObjectFunction.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototypetrue,解决。
  • 对于 Function instanceof FunctionFunction.__proto__ === Function.prototypetrue,解决
  • 对于Object instanceof Object , Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototypetrue,解决

只要上面的推导,任一环节你写错或者压根写不出来(在今天之前我也是瞎搞,运气好了蒙对了),说明你就不是真懂原型链,面试问到稍微变形的题还是易错。


  • 在上面的各种原型的变换中,其实难点就在于Function Object 构造函数也是对象 原型对象等所有对象都由Object构造

这四个点。

  • 而且看待问题的角度不同,对事实的认知影响很大。比如 Object Function 你把它们看成构造函数或者对象,结果不同的。不同的场合,换不同的角度去认识它们,事物具有两面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲学原理吧。
  • 各种原型的分析过程,让我回忆起了,被数学支配的恐惧。逻辑必须合理、一步是一步、抽丝剥茧看本质,大概是这么多年应试教育留在脑子里面的深深烙印吧。
  • JS越来越有意思了,感觉应该快入门了。

原型链

  • 咦,在哪呢。
  • 原型链就在上面啊。每个对象,沿着__prto__属性有一条链子,找呀找呀,一直找到Object.prototype为止

感谢冴羽大神和若愚大神的文章

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

推荐阅读更多精彩内容