做过前端的都知道,两个必会的知识就是原型和原型链,如果有人问你,原型是什么?你是不是回答对象中都有一个默认的属性叫prototype,指向的就是原型。如果再追问你,那原型链是什么呢?你是不是回答如果在当前对象中找不到某个属性,就会去父对象的原型中去查找,这样一层一层的向上查找,一直到顶层null,这样形成的一条链就叫原型链。

那到底什么是原型与原型链呢,先不说上面的回答对不对,这样的答案肯定是小伙伴们听别人说的之后,似懂非懂的记在了心里,并没有去验证,只是在工作中觉得确实好像是这么回事。

下面我们来一起看一下,相信看完之后你能对它们有更深的了解。

prototype

所有的js对象都会继承原型对象上面的属性和方法。其中原型对象就是prototype所指向的那个对象。我们一般叫它原型属性。

而原型属性,是只有函数才有的,或者说是只有typeof为function的对象才有的(箭头函数除外),在js里面,函数可以作为构造函数使用,可以生成自己对应的实例化对象,而它所生成的这些实例,就会共享这个函数的原型对象里面的属性和方法,也就是我们所说的继承。

从下面的例子我们来看一下:

我们可以看到,不同的函数都拥有自己的原型属性,而非函数不具有prototype属性,因此返回undefined,其中Symbol不是构造函数,但是本身具有原型属性,箭头函数也不是构造函数,但其本身并无原型属性。

对于字符串、数值、布尔类型与其对应的构造函数也是一样的:

上面的输出是否有跟你想的不一样的呢?

我们通过一个简单的例子来理解一下原型对象:

function PaperNovel(author, title, date, pages, content) {this.author = authorthis.title = titlethis.date = datethis.pages = pagesthis.content = content
}
PaperNovel.prototype.medium = "纸质"
PaperNovel.prototype.category = "小说"
PaperNovel.prototype.wordsNum = function () {return this.content.length
}
let 三国演义 = new PaperNovel("罗贯中", "三国演义", "2022-07-31", "327", "东汉末年,皇帝昏聩,宦官专权,民不聊生。爆发了大型农民起义——黄巾起义。乱世之中,一代英雄人物竞相涌现。")
let 西游记 = new PaperNovel("吴承恩", "西游记", "2022-07-30", "465", "东胜神州傲来国海边有一花果山,山顶一石,受日月精华,产下一个石猴。石猴在花果山做了众猴之王,为求长生,出海求仙,在西牛贺州拜菩提祖师为师。")
console.log(三国演义.author)//罗贯中
console.log(三国演义.medium)//纸质
console.log(西游记.author)//吴承恩
console.log(西游记.medium)//纸质
console.log(西游记.wordsNum())//69

我们定义了函数PaperNovel,当它被当做构造函数来调用的时候,实例化了两个对象:三国演义和西游记。其中author属于实例属性,不同的实例拥有各自对应的值,medium属于原型属性,各个实例之间共用这个值。

用图形来表述上面的关系的话,大概长成这样:

构造函数与实例

其中的author、title、date、pages、content属于实例属性,每个实例对象都会有自己的实例属性值,存储在当前的实例对象中。medium、category、wordsNum属于原型属性,每个实例对象都共有这些原型属性,存储在构造函数的原型中,实例对象只保存一个对它们的引用。

因此原型中的属性改变的时候,所有的实例对象都会受到影响,请看如下结果:

console.log(三国演义.category)//小说
console.log(西游记.category)//小说
PaperNovel.prototype.category = "散文"
console.log(三国演义.category)//散文
console.log(西游记.category)//散文
三国演义.__proto__.category = "科普"
console.log(西游记.category)//科普

在实例对象访问一个值的时候,会先在实例属性中查找,如果没有找到,那么将会去它对应的构造函数的原型中去查找,还是以上面的代码为例,我们来看一下效果:

console.log(三国演义.category)//小说
三国演义.category = "散文"
console.log(三国演义.category)//散文
console.log(三国演义.__proto__.category)//小说
console.log(西游记.category)//小说

至此我们知道了,prototype是函数的原型对象,当函数被当做构造函数调用的时候,区别于实例属性,原型属性会被所有实例所共用,实现的方式就是所有实例对象保存一个指向该原型对象的指针。

原型属性大概先介绍这些。

proto

我们上文中说到,实例对象没有prototype属性,只有构造函数才有,实例对象会有一个指针来指向构造函数的原型对象,而这个指针就是用__proto__来存储和表示的。

也就是说实例对象的__proto__指向它的构造函数的原型。

知道了这一点,我们很容易得出:

到这就为止了吗?,我们还可以深挖一下,其实看到这里,有眼尖的小伙伴可能会问:PaperNovel.prototype也是一个对象,那它有没有__proto__属性,有的话指向哪里呢?

很好,提出这个问题说明你的求知欲很强,我们对待技术就是要充满好奇心。给你鼓掌[手动鼓掌]。

我们先来简单思考一下,PaperNovel.prototype是一个对象,它应该也是被实例化出来的,那么它应该有__proto__属性,并且指向它的构造函数的原型。

好了,对象的构造函数是什么呢?没错!就是Object,已经很清晰了,我们来下是否像你想的样子:

这个时候小伙伴们又会问了:Object.prototype也是一个对象,它有__proto__属性吗?有的话指向哪里呢?

我们直接来看:

呀!我们发现虽然有这个属性,但是它为null了,其实这也就是我们平常所说的,循着原型链查找,一直查找到null为止,那么那个null是什么它又在哪呢?就是这个,已经到达了原型链顶端,发现是null,就不会再继续往上查找了。

至此我们知道了,对象的__proto__属性指向它的构造函数的原型,通过它可以把一系列的原型连接起来,我们在访问一个对象的属性的时候,如果当前对象不存在这个实例属性,那么它就会去从它的__proto__指向的对象中去查找,层层往上,一直到null。

我们可以通过一个示例来感受一下它的魔力:

__proto__先大概介绍这些。

原型与原型链扩展

相信看到这里,大家已经知道了什么是原型以及原型的存在形式,也知道了__proto__是做什么用的,它是如何把各个原型对象连接起来的,也能明白了对象属性访问时对于原型链的查找机制。

下面我们来扩展一些内容,理解既有一些构造函数他们之间的关系。

如下示例:

① 数组的__proto__指向构造函数Array的原型

② 函数的原型对象的__proto__指向构造函数Object的原型

③ 函数的__proto__指向构造函数Function的原型

④ Function的__proto__指向构造函数Function(也就是它自己)的原型

⑤ Object的__proto__指向Function的原型

⑥ Function的原型的__proto__指向Object的原型

我们一切操作基本都离不开上面的这些关联关系,只要了解prototype和__proto__,相信你会很快明白上面的这些行为。

主要总结为两点:

  1. prototype为函数特有属性,只有函数才具有原型属性,以供继承,对象也能继承主要是通过__proto__的连接
  2. __proto__表示一个对象指向它的构造函数的原型的指针,也就是说一个对象的__proto__指向它的构造函数的原型

好好理解一下上面的这两点内容,结合之前的例子,基本就对原型与原型链有了深刻的认识,相信你也能很好的回答了文章开始的问题。

常用方法解析

① Object.prototype.toString.call

相信你看到这种形式的写法不会感到陌生,这是调用Object原型上面的toString方法,通过call指定了它的执行作用域,也就是改变了this的指向。

通过上面的学习我们知道Object的原型,其实就是它的实例化对象的__proto__,因此我们换一种方式书写也是可以的:

//注意,下面的结果是false
//因此这两个方法转化的字符串规则是不一样的
//我们在例子中使用的是Object.prototype.toString
Object.prototype.toString === Object.toString
//通过上面的讲解,我们知道下面的结果是true
//因此这两种写法是等价的
Object.prototype.toString === ({}).__proto__.toString

Array.prototype.slice.call

//下面的结果为true
//因此这两种写法是等价的
Array.prototype.slice === [].__proto__.slice

总结

理解原型与原型链,对我们书写代码、构造高级函数、理解深层次的执行机制等,都是非常有帮助的,利用这些属性和它们的特点能创造出很多优雅的代码。

现在是不是对于原型和原型链有了更好的理解了呢?对于面试官给出的问题也能不慌不忙的解释清楚了呢?

希望本文对你有所帮助,不胜欣慰。

prototype是原型对象,那__proto__又是什么呢,总不能是别名吧?相关推荐

  1. 【JavaScript高级教程】JavaScript prototype(原型对象)

    所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法. function Person(first, last, age, eyecolor) {this.fi ...

  2. 关于JavaScript的Prototype及原型对象的理解

    学习JavaScript时,就一定会涉及到两个概念–prototype,原型对象.自己在做项目时可能无意中使用到,但是却没有真正去了解这个东西,在学会使用的基础上,进一步去理解它会帮助自己吸收到更多不 ...

  3. JS中函数的prototype属性和对象的__proto__属性

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  4. 彻底理解js中的原型对象和prototype属性

    prototype(函数的原型属性) prototype 是一个指向该实例所使用的原型对象的[指针] prototype 是几乎所有的函数(除了某些内建函数)的属性 prototype 不是一个实例的 ...

  5. javascript面向对象系列第一篇——构造函数和原型对象

    前面的话 一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如何用构造函数和原型对象来创建对象 构造函数 构造函数是 ...

  6. Js 原型对象与原型链(转)

    原文出处 原创作者: abruzzi 原文图文并茂,很好的说明了原型链的原理,在这里感谢原文作者把文章写的那么通俗易懂. 原型对象 每个javascript对象都有一个原型对象,这个对象在不同的解释器 ...

  7. 原型、原型对象、构造函数、原型链理解

    1. 基本概念: "原型属性"也可以叫做"原型"(prototype):所有函数都有prototype,我觉得可以理解为python中的类属性,不需要通过实例, ...

  8. JavaScript——面向对象之继承(原型对象)与多态(重载、重写)

    继承与多态 引入问题 一.继承 1. 步骤 (1) 找到所有子对象共同的父对象 (2) 将所有子对象公共的方法定义添加到共同的父对象中 (3) 所有子对象因继承关系而直接使用父对象中公共的方法 2. ...

  9. 【javascript】对原型对象、原型链的理解

    原型对象,原型链这些知识属于基础类知识.但是平时开发过程中也很少用到. 看网上的意思,原型链用于es5开发场景下的继承.es6有了类语法糖之后,就自带继承了. 通过理解,个人画了一张原型链解构的关系图 ...

最新文章

  1. react 从使用 看定义
  2. bzoj 1691: [Usaco2007 Dec]挑剔的美食家
  3. hdu3313 最大流找关键点,或者最短路找关键点.
  4. undefined reference to `_imp___Py_NoneStruct'
  5. 怎么卸载旧版本java_卸载旧的java-jdk安装新版本jdk
  6. 【Python】数据科学家提高效率的 40 个 Python 技巧
  7. 雷达多普勒频率计算公式_手持式雷达流速仪的监测应用方案
  8. Java代码优化方案 J2ME内存优化
  9. 丁香医生APP被App Store拒绝更新:违反苹果内购系统规定
  10. 集合及其常见操作,创建,增加,删除,查找
  11. 银行招聘考试面试心得
  12. .net中Task.WaitAll和WaitAny同步的等待Task完成
  13. 如何在centos7上安装源码包
  14. 华鑫证券王习平:让投资变成一件容易事、有趣事
  15. 知道创宇荣获“年度公益贡献安全企业”及“中国网安产业100强”
  16. Ubuntu系统实现简单c语言编程
  17. 关于王小云破解MD5
  18. 白话大数据--Hash分片
  19. ubuntu shuru zhic
  20. 垃圾工作还不如伺候一个渣男!!!

热门文章

  1. JavaScript特效源码(8、其他特效)
  2. python中cat,stac,transpose,permute,squeeze区别用法
  3. QuickBooks 2018 For Dummies 免积分下载
  4. 学linux作用,linux有必要学吗?学linux有什么作用,学linux能干什么
  5. motoxt 1085 android8,Moto(Moto)X XT1085/全网通手机系统介绍评测-ZOL中关村在线
  6. Directx11 Effects
  7. 【有图有真相】北京地区午饭线下活动——香山行圆满结束
  8. 华为oj初级 学英语
  9. 超神学院之天河战役计算机,《超神学院之雄兵连 第1季 天河战役篇》
  10. 他们十年发生的那些事,你好奇不?