JS中的原型链和原型的认识
这篇文章主要是学习一下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 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,解决
只要上面的推导,任一环节你写错或者压根写不出来(在今天之前我也是瞎搞,运气好了蒙对了),说明你就不是真懂原型链,面试问到稍微变形的题还是易错。
- 在上面的各种原型的变换中,其实难点就在于
FunctionObject构造函数也是对象原型对象等所有对象都由Object构造
这四个点。
- 而且看待问题的角度不同,对事实的认知影响很大。比如
ObjectFunction你把它们看成构造函数或者对象,结果不同的。不同的场合,换不同的角度去认识它们,事物具有两面性。大概就是背了多年的同一性,巴拉巴拉一堆的哲学原理吧。 - 各种原型的分析过程,让我回忆起了,被数学支配的恐惧。逻辑必须合理、一步是一步、抽丝剥茧看本质,大概是这么多年应试教育留在脑子里面的深深烙印吧。
- JS越来越有意思了,感觉应该快入门了。
原型链
- 咦,在哪呢。
- 原型链就在上面啊。每个对象,沿着
__prto__属性有一条链子,找呀找呀,一直找到Object.prototype为止
JS中的原型链和原型的认识的更多相关文章
- 谈JS中的作用域链与原型链(1)
学习前端也有一段时间了,觉得自己可以与大家分享一些我当初遇到疑惑的东西,希望能给对此问题有疑惑的朋友带来一点帮助. 先来普及一下JS的概念(不要嫌我啰嗦,可能一些朋友开始学习JS是跟着视频和写好的代码 ...
- jacascript中的原型链以原型
今地铁上看慕课网js课程,又学习到关于原型的一些知识,记录如下.如有偏差欢迎指正: 三张图要连起来看哦~ 图解: 1.创建一个函数foo. 2.运用函数的prototype属性(这个属性就是实例对象的 ...
- js 原型,原型链,原型链继承浅析
对于网上的关于原型,原型链和原型链继承的晦涩语言说明就不累赘了,复制粘贴过来再解释一遍怕自己也整蒙了,本人最怕空气突然安静,四目对视,大眼对小眼,一脸懵逼. 我们先看下面
- Javascript原型链和原型继承
哇好久都没有写随笔啦,整个人都慵懒啦. 为了不让大家忘记我,把以前写过的一些慢慢发出来. 在JS 中, 有两条链子,作用域链 和 原型链. 作用域链相对容易理解,两点 - 函数限定变量作用域,就是说, ...
- 面试题常考&必考之--js中的难点!!!原型链,原型(__proto__),原型对象(prototype)结合例子更易懂
1>首先,我们先将函数对象认识清楚: 补充snow的另一种写法: var snow =function(){}; 2>其次:就是原型对象 每当我们定义一个函数对象的时候,这个对象中就会包含 ...
- js 中对象--对象结构(原型链基础解析)
对于本篇对于如何自定义对象.和对象相关的属性操作不了解的话,可以查我对这两篇博客.了解这两篇可以更容易理解本篇文章 用构造函数创建了一个对象 obj对象的本身创建了两个属性 x=1 ,y=2 ...
- Js中找任意对象的原型方法及改造原型
Java中有运行时类型识别,js可以很方便的模仿这个特性,因为所有js对象都有一个属性constructor(构造器),表示这个对象的构造方法,原型与构造方法同名,所以可以通过这儿知道任意对象的原型名 ...
- 对js中闭包,作用域,原型的理解
前几天,和朋友聊天,聊到一些js的基础的时候,有一种‘好像知道,好像又不不知道怎么讲的感觉’...于是捡起书,自己理一理,欢迎拍砖. 闭包 理解闭包首先要理解,js垃圾回收机制,也就是当一个函数被执行 ...
- js通过沿着作用域链还是原型链查找变量
这是一道非常典型的JS闭包问题,结果和具体的解析请看这里. 对于其中的`函数作用域链的问题`博主似乎没有解释清楚,有一些疑问:js中的变量到底是沿着作用域链还是原型链查找呢? 首先,要分清作用域链与原 ...
随机推荐
- O048、掌握 cinder-scheduler 调度逻辑
参考https://www.cnblogs.com/CloudMan6/p/5589707.html 上一节我们详细讨论了cinder-api 和 cinder-volume ,今天讨论另一个重要 ...
- O028、nova-compute 部署 instance 详解
参考https://www.cnblogs.com/CloudMan6/p/5451276.html 本节讨论 nova-compute ,并详细分析 instance 部署的全过程. nov ...
- vue 编译警告 Compiled with 4 warnings
问题原因: windows下盘符的大小写导致的. 我在cmd里运行的时候,是切换到小写,改成大写的E盘符就没问题了
- QQ大盗 - 巧用clientkey
场景: 1.将程序发给好友,好友打开 qq昵称就会被秒改为”账号已被盗“. 2.将程序运行在自己的电脑,让那些随意借用电脑看片聊天的室友产生一个觉悟:乱使用别人电脑很可能会泄露隐私. 思路: 通过数据 ...
- centos6.4升级openssh7.4p1
Centos6.4版本yum升级openssh版本最高到5.3,想要升级到更高的版本需要重新编译 一.查看当前openssh版本: [root@localhost ~]# ssh -VOpenSSH_ ...
- 02-【servlet】
1.什么是Servlet Servlet是JavaWeb的三大组件之一[Servlet,Filter,Listener],它属于动态资源.Servlet的作用是处理请求,服务器会把接收到的请求交给Se ...
- BLE 5协议栈-逻辑链路控制与适配协议层(L2CAP)
文章转载自:http://www.sunyouqun.com/2017/04/page/2/ 逻辑链路控制与适配协议通常简称为L2CAP(Logical Link Control and Adapta ...
- 解决remix在线编译器连接本地私有链环境不成功的问题
一.部署合约到私有链环境 选择"environment"里的"Web3 Provider" 弹出RPC连接地址输入框 输入我们Geth客户端安装服务器的IP:9 ...
- Hive权限管理(十)
Hive权限管理 1.hive授权模型介绍 (1)Storage Based Authorization in the Metastore Server 基于存储的授权 - 可以对Metastore中 ...
- PAT1005 继续(3n+1)猜想
卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数.例如对 n=3 进行验证的时 ...