一、prototype

在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。

function Person(age) {this.age = age
}
Person.prototype.name = 'kavin'
var person1 = new Person()
var person2 = new Person()
console.log(person1.name) //kavin
console.log(person2.name)  //kavin

Person.prototype可以找到Person的显示原型。上述例子中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型。

原型的概念:每一个javascript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。

让我们用一张图表示构造函数和实例原型之间的关系:

二、__proto__

这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的隐式原型。

对象的隐式原型会指向类的显式原型

function Person() {}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

而关系图:

三、constructor

每个原型都有一个constructor属性,指向该关联的构造函数。

function Person() {}
console.log(Person===Person.prototype.constructor)  //true

所以再更新下关系图:

function Person() {}var person = new Person();console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

补充说明:

function Person() {}
var person = new Person();
console.log(person.constructor === Person); // true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:

person.constructor === Person.prototype.constructor

四、实例与原型

当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

function Person() {}Person.prototype.name = 'Kevin';var person = new Person();person.name = 'Daisy';
console.log(person.name) // Daisydelete person.name;
console.log(person.name) // Kevin

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 Daisy。

但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 Kevin。

但是万一还没有找到呢?原型的原型又是什么呢?

五、原型的原型

在前面,我们已经讲了原型也是一个对象,既然是对象,我们就可以用最原始的方式创建它,那就是:

var obj = new Object();
obj.name = 'Kevin'
console.log(obj.name) // Kevin

其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 __proto__ 指向构造函数的 prototype ,所以我们再更新下关系图:

六、原型链

简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》

继上述五中所说,那 Object.prototype 的原型呢?

console.log(Object.prototype.__proto__ === null) // true

引用阮一峰老师的 《undefined与null的区别》 就是

null 表示“没有对象”,即该处不应该有值。

所以 Object.prototype.__proto__ 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。

所以查找属性的时候查到 Object.prototype 就可以停止查找了。

最后一张关系图也可以更新为:

图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。

七、instance of

instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。

使用 instanceof判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false

[] instanceof Array; // true

缺点: instanceof 只能用来判断对象类型,原始类型不可以。并且所有对象类型 instanceof Object 都是 true

优点:instanceof可以弥补Object.prototype.toString.call()不能判断自定义实例化对象的缺点。

所以可以用instanceof来区分Object和Array

[] instanceof Array   //true
{} instanceof Array   //false

也可以通过调用constructor来识别

{}.constructor    //返回object
[].constructor    //返回Array

通过Object.prototype.toString.call方法来识别

Object.prototype.toString.call([])   //["object Array"]
Object.prototype.toString.call({})   //["object Object"]

参考链接:

javascript——原型与原型链 - 雅昕 - 博客园

前端面试题1:Object.prototype.toString.call() 、instanceof 以及 Array.isArray()三种方法判别数组的优劣和区别_爱折腾的研究僧的博客-CSDN博客

【转载】js中区分object和array方法 - jaycethanks - 博客园

这个视频:快速掌握 JS 面试题之『原型和原型链』_哔哩哔哩_bilibili。讲的也很清楚

原型和原型链和instanceof相关推荐

  1. JS原型链与instanceof底层原理

    转载自  JS原型链与instanceof底层原理 一.问题: instanceof 可以判断一个引用是否属于某构造函数: 另外,还可以在继承关系中用来判断一个实例是否属于它的父类型. 老师说:ins ...

  2. javascript之原型与原型链

    前言   了解JavaScript的原型与原型链有助于我们更深层次的理解这门语言,看过很多相关的文章,写的都很好,下面是根据自己的理解,一步步揭开原型与原型链 正文 一.数据类型   在JavaScr ...

  3. JavaScript原型与原型链(总结篇)

    系列文章推荐 JavaScript原型与原型链(基础篇) JavaScript原型与原型链(进阶篇) JavaScript原型与原型链(总结篇) 1 构造函数和实例对象 构造函数的prototype属 ...

  4. java原型链_深入总结Javascript原型及原型链

    本篇文章给大家详细分析了javascript原型及原型链的相关知识点以及用法分享,具有一定的参考价值,对此有需要的朋友可以参考学习下.如有不足之处,欢迎批评指正. 我们创建的每个函数都有一个 prot ...

  5. (五)JS基础知识二(通过图理解原型和原型链)【三座大山之一,必考!!!】

    JS基础知识二(原型和原型链) 提问 class 继承 类型判断(instanceof) 原型 原型关系 基于原型的执行规则 原型链 说明 提问 如何准确判断一个变量是不是数组 class的原型本质 ...

  6. 的函数原型_JS基础函数、对象和原型、原型链的关系

    JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...

  7. 详解面向对象、构造函数、原型与原型链

    详解面向对象.构造函数.原型与原型链 为了帮助大家能够更加直观的学习和了解面向对象,我会用尽量简单易懂的描述来展示面向对象的相关知识.并且也准备了一些实用的例子帮助大家更加快速的掌握面向对象的真谛. ...

  8. 详解链表在前端的应用,顺便再弄懂原型和原型链!

    链表在前端中的应用 一.链表VS数组 二.JS中的链表 三.前端与链表:JS中的原型链 1.原型是什么? 2.原型链是什么? 3.原型链长啥样? (1)arr → Array.prototype → ...

  9. JS_13原型与原型链

    原型与原型链 原型 每一个函数都有一个属性:prototype,默认指向object空对象,就是原型对象,原型对象有一个constructor属性,指向函数对象 每一个实例化对象都有一个属性 prot ...

最新文章

  1. 为什么电脑磁盘从C盘开始,之前的A盘和B盘呢?
  2. MFC改变static text颜色
  3. Machine Learning On Spark——基础数据结构(一)
  4. 重建索引一般需要多久_游泳小白学游泳,一般需要多久才能学会?猜猜看
  5. Python正则表达式re模块
  6. UINavigationController 基本用法
  7. error 1044 (42000):access denied for user ''@'localhost' to database 'mysql'
  8. 【转】android gravity属性 和 weight属性
  9. 解决SVN安装语言包后无法选择中文的问题(亲测可行)
  10. 数学竞赛辅导陈启浩pdf_高中数学一题多解经典题型汇编(一)
  11. SMA :Structured Multimodal Attentions for TextVQA --- 论文阅读笔记
  12. Java实例项目之投票统计(可拓展衍生)
  13. Unity2D小游戏——类似QQ堂的小 demo(炸弹人)
  14. delphi 两行代码实现合并多张图片生成mp4视频
  15. Unity 3D游戏开发 - U3D入门 | 游戏场景基本操作
  16. guestbook.php注入,php防注入留言板(simple)
  17. 快速实现短信发送功能(SpringBoot)
  18. linux aarch64启动不了,引导AArch64 Linux
  19. [Aliyun] [FC] [CDN] 如何使用 refresh-cdn-cache 插件自动刷新 CDN 缓存
  20. 方正排版只支持rtf格式的文件在线打开的解决方案

热门文章

  1. 学习MyBatis3这一篇就够了
  2. BUUCTF-PWN刷题记录-17
  3. 华为张小军:期待区块链应用落地,加速推进区块链产业商用 | FBEC 2019
  4. Java中三种代理方式—— 静态代理与两种动态代理的实现机制
  5. 简易的记账软件设计与实现
  6. JS运动从入门到兴奋1
  7. MySQL UUID函数的详解
  8. Qt QTextStream
  9. 最小费用最大流 【模板】
  10. 风靡全球25年的重磅IP,新作沦为脚本乐园