摘要:在上面的各种原型的变换中,其实难点就在于构造函数也是对象原型对象等所有对象都由构造这四个点。
这篇文章主要是学习一下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
完整的总结instanceof运算符的实质当你new一个构造函数的时候,创建一个函数实例,那么 『 函数实例.__proto__ === 该构造函数.prototype 』
所有的函数都是由Function构造出来的,那么 『被构造出来的其他函数.__proto__ === Function.prototype 』
所有的构造函数的原型对象都是由Object构造出来的,那么 『所有的构造函数.prototype.__proto__ === Object.prototype 』
首先这有几个题
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 Function ,Object.__proto__ === Function.prototype 为true,解决
对于Function instanceof Object , Function.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype为true,解决。
对于 Function instanceof Function ,Function.__proto__ === Function.prototype 为true,解决
对于Object instanceof Object , Object.__proto__.__proto__ === Function.prototype.__proto__ === Object.prototype 为true,解决
只要上面的推导,任一环节你写错或者压根写不出来(在今天之前我也是瞎搞,运气好了蒙对了),说明你就不是真懂原型链,面试问到稍微变形的题还是易错。
在上面的各种原型的变换中,其实难点就在于Function Object 构造函数也是对象 原型对象等所有对象都由Object构造
这四个点。
而且看待问题的角度不同,对事实的认知影响很大。比如 Object Function 你把它们看成构造函数或者对象,结果不同的。不同的场合,换不同的角度去认识它们,事物具有两面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲学原理吧。
各种原型的分析过程,让我回忆起了,被数学支配的恐惧。逻辑必须合理、一步是一步、抽丝剥茧看本质,大概是这么多年应试教育留在脑子里面的深深烙印吧。
JS越来越有意思了,感觉应该快入门了。
咦,在哪呢。
原型链就在上面啊。每个对象,沿着__prto__属性有一条链子,找呀找呀,一直找到Object.prototype为止
感谢冴羽大神和若愚大神的文章。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/51716.html
摘要:在上面的各种原型的变换中,其实难点就在于构造函数也是对象原型对象等所有对象都由构造这四个点。 这篇文章主要是学习一下JavaScript中的难点------原型和原型链 自定义一个对象 我们学习一门编程语言,必然要使用它完成一些特定的功能,而面向对象的语言因为符合人类的认知规律,在这方面做得很好,今天我以JS为例,探索一下JS不同于其他面向对象的语言的地方-------原型和原型链 首...
摘要:为了防止之后自己又开始模糊,所以自己来总结一下中关于作用域链和原型链的知识,并将二者相比较看待进一步加深理解。因此我们发现当多个作用域相互嵌套的时候,就形成了作用域链。原型链原型说完了作用域链,我们来讲讲原型链。 毕业也整整一年了,看着很多学弟都毕业了,忽然心中颇有感慨,时间一去不复还呀。记得从去年这个时候接触到JavaScript,从一开始就很喜欢这门语言,当时迷迷糊糊看完了《J...
摘要:原型链继承和参考理解的原型链和继承实现了什么操作的过程发生了什么原型链和属性原型链是什么上面的是什么就是原型链,原型链是内部,指向它父类的。通过这一句说明的原型链就是指向函数的属性。这可以为后面提到的继承做准备。 原型链、继承 和 instanceof 参考:MDN:instanceofMDN:Inheritance and the prototype chain理解JavaScrip...
摘要:在使用原型链实现继承时有一些需要我们注意的地方注意继承后的变化。在了解原型链时,不要忽略掉在末端还有默认的对象,这也是我们能在所有对象中使用等对象内置方法的原因。 在上一篇post中,介绍了原型的概念,了解到在javascript中构造函数、原型对象、实例三个好基友之间的关系:每一个构造函数都有一个守护神——原型对象,原型对象心里面也存着一个构造函数的位置,两情相悦,而实例呢却又...
阅读 2676·2021-10-11 10:57
阅读 2337·2021-08-27 16:20
阅读 1297·2019-08-30 13:03
阅读 1537·2019-08-30 12:50
阅读 3281·2019-08-29 14:16
阅读 1508·2019-08-29 11:12
阅读 1581·2019-08-28 17:53
阅读 2862·2019-08-27 10:58