资讯专栏INFORMATION COLUMN

JS中的原型链和原型的认识

Juven / 993人阅读

摘要:在上面的各种原型的变换中,其实难点就在于构造函数也是对象原型对象等所有对象都由构造这四个点。

这篇文章主要是学习一下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实例的原型,如果不直观的话,下面直接看Array实例的原型

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


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


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

__proto__属性

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

person.__proto__ === Person.prototype 
true

__proto__是对象的属性,而且是浏览器强逼着ECMAScript加上的这个规范。

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

constructor

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

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

不过原型是无法指向实例的,只可以通过constructor属性指向 构造函数

Person === Person.prototype.constructor
true

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

由以上知识得出一个小公式
对象.__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为止

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/51716.html

相关文章

  • JS原型链和原型认识

    摘要:在上面的各种原型的变换中,其实难点就在于构造函数也是对象原型对象等所有对象都由构造这四个点。 这篇文章主要是学习一下JavaScript中的难点------原型和原型链 自定义一个对象 我们学习一门编程语言,必然要使用它完成一些特定的功能,而面向对象的语言因为符合人类的认知规律,在这方面做得很好,今天我以JS为例,探索一下JS不同于其他面向对象的语言的地方-------原型和原型链 首...

    Shimmer 评论0 收藏0
  • 我所认识JavaScript作用域链和原型

    摘要:为了防止之后自己又开始模糊,所以自己来总结一下中关于作用域链和原型链的知识,并将二者相比较看待进一步加深理解。因此我们发现当多个作用域相互嵌套的时候,就形成了作用域链。原型链原型说完了作用域链,我们来讲讲原型链。   毕业也整整一年了,看着很多学弟都毕业了,忽然心中颇有感慨,时间一去不复还呀。记得从去年这个时候接触到JavaScript,从一开始就很喜欢这门语言,当时迷迷糊糊看完了《J...

    Bmob 评论0 收藏0
  • 原型链、继承 和 instanceof

    摘要:原型链继承和参考理解的原型链和继承实现了什么操作的过程发生了什么原型链和属性原型链是什么上面的是什么就是原型链,原型链是内部,指向它父类的。通过这一句说明的原型链就是指向函数的属性。这可以为后面提到的继承做准备。 原型链、继承 和 instanceof 参考:MDN:instanceofMDN:Inheritance and the prototype chain理解JavaScrip...

    hqman 评论0 收藏0
  • 深入javascript——原型链和继承

    摘要:在使用原型链实现继承时有一些需要我们注意的地方注意继承后的变化。在了解原型链时,不要忽略掉在末端还有默认的对象,这也是我们能在所有对象中使用等对象内置方法的原因。 在上一篇post中,介绍了原型的概念,了解到在javascript中构造函数、原型对象、实例三个好基友之间的关系:每一个构造函数都有一个守护神——原型对象,原型对象心里面也存着一个构造函数的位置,两情相悦,而实例呢却又...

    UCloud 评论0 收藏0

发表评论

0条评论

Juven

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<