__proto__(隐式原型)与prototype(显式原型)

1. 是什么?

  • 显式原型 explicit prototype property:

每一个函数在创建之后都会有一个prototype的属性,这个属性指向函数端的原型对象

ps: 通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。

  • 隐式原型 implicit prototype link:

JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个属性,但是大多数的浏览器都支持通过_proto_来访问。而到了ES5中有了对于这个内置属性标准的Get方法:Object.getPrototypeOf()。

ps: Object.prototype 这个对象是个例外,它的__proto__值为null

2. 作用是什么?

  • 显式原型的作用: 用来实现基于原型得继承与属性的共享。
  • 隐式原型的作用:构成原型链,同样用于实现基于原型的继承。当我们访问obj这个对象中的属性时,如果在obj中找不到,就沿着_proto_依次查找。

3. _proto_ 的指向

_proto_的指向根据ECNA定义'to the value of its constructor’s "prototype" ' ---指向创建这个对象的函数的显式原型。

所以关键点还是在于找到创建这个对象的构造函数,JS中对象创建的方式,一眼看过去似乎有三种方式:

  • 对象字面量的方式
  • new的方式
  • ES5中的Object.create()

但是我认为本质上只有一种方式,那就是通过new来创建。为什么呢,首先字面量的方式是一种为了让开发人员更方便创建对象的一个新增方法,本质就是: var o = new Object(); o.xx =xx; o.yy = yy;再来看Object.create(),这是ES5中新增的方法,在这之前这被称为原型式继承。

道格拉斯在2006年写了一篇文章,题为 Prototypal Inheritance In JavaScript。在这篇文章中,他介绍了一种实现继承的方法,这种方法并没有使用严格意义上的构造函数。他的想法是借助原型可以基于已有的对象创建新对象,同时还不比因此创建自定义类型,为了达到这个目的,他给出了如下函数:

function object(o){function F(){}F.prototype = o;return new F()
}

----- 《JavaScript高级程序设计》P169

所以从实现代码 return new F() 中我们可以看到,这依然是通过new来创建的。不同之处在于由 Object.create() 创建出来的对象没有构造函数,这个没有是说它在Object.creat()函数外部不能访问到它的构造函数,然而在函数内部实现中是有的,它短暂的存在了那么一会儿。假设我们就在函数内部,可以看到对象的构造函数是F,现在

//以下是用于验证的伪代码
var f = new F();
//于是有
f.__proto__ === F.prototype //true
//又因为
F.prototype === o;//true
//所以
f.__proto__ === o;

因此由Object.create(o)创建出来的对象它的隐式原型指向o。判断一个对象的__proto__指向谁就要看下面的了:

  • 构造函数的显示原型的隐式原型:

默认情况下:

function Foo(){var foo = new Foo()Foo.prototype._proto_ === Object.prototype // true
}

其他情况下:

(1)、

function Bar() {}
// 这时我们想让Foo继承Bar
Foo.prototype = new Bar()
Foo.prototype._proto_ === Bar.prototype // true

(2)、

//我们不想让Foo继承谁,但是我们要自己重新定义Foo.prototype
Foo.prototype = {a:10,b:-10
}
//这种方式就是用了对象字面量的方式来创建一个对象,根据前文所述
Foo.prototype.__proto__ === Object.prototype

: 以上两种情况都等于完全重写了Foo.prototype,所以Foo.prototype.constructor也跟着改变了,于是乎constructor这个属性和原来的构造函数Foo()也就切断了联系。

  • 构造函数的隐式原型

既然是构造函数,那么它就是Function()的实例,因此也就是指向Function.prototype,比如:Object._proto_ === function.prototype

身为初学者,就应该珍藏这张图:

首先,要明确几个点:

1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。

即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。

2.方法(Function)

方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

好啦,知道了这两个基本点,我们来看看上面这副图。

  • 构造函数Foo()

构造函数的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。

  • 原型对象Foo.prototype

Foo.prototype保存着实例共享的方法,有一个指针constructor指回构造函数。

  • 3.实例

f1和f2是Foo这个对象的两个实例,这两个对象也有属性__proto__,指向构造函数的原型对象,这样子就可以像上面1所说的访问原型对象的所有方法啦。

另外:

构造函数Foo()除了是方法,也是对象啊,它也有__proto__属性,指向谁呢?

指向它的构造函数的原型对象呗。函数的构造函数不就是Function嘛,因此这里的__proto__指向了Function.prototype。

其实除了Foo(),Function(), Object()也是一样的道理。

原型对象也是对象啊,它的__proto__属性,又指向谁呢?

同理,指向它的构造函数的原型对象呗。这里是Object.prototype.

最后,Object.prototype的__proto__属性指向null。

总结:

1.对象有属性__proto__,指向该对象的构造函数的原型对象。

2.方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象。

prototype 与 _proto_ 的区别相关推荐

  1. _proto_与prototype的关系及区别

    __proto__与prototype这两个原型属性大概在学习前端的过程中多多少少都接触过,但是不经常用基本就忘了,不过面试的时候经常会被问到,然后就一脸懵逼的蒙混过关,总觉得这样不太好,所以看了些文 ...

  2. prototype与_proto_

    1.prototype与_proto_ ①prototype:是函数才有的属性,这个属性是一个指针.当一个构造函数被创建时,该构造函数会自动生成一个prototype指针,该指针指向构造函数的原型.这 ...

  3. 一张图理解JS的原型(prototype、_proto_、constructor的三角关系)

    注意:前方高能预警,请认真仔细看完,阅读完后自己再次画下原型图,相信你一定会有更深刻的认识.(推荐炒鸡好用的画流程图的软件ProcessOn) 构造函数:function Foo ( ) { }; 实 ...

  4. prototype 和 proto 的区别

    学习Vue源码时看到一篇文章写得很好,记录一下 原文链接: 链接 本文主要讲三个 问题 prototype 和 proto function 和 object new 到底发生了什么 prototyp ...

  5. JavaScript call,apply和prototype的介绍,区别

    ----这三个概念会在实现js继承中使用到 1.call和apply call和apply的作用基本类似,都是去执行function并将这个function的context替换成第一个参数带入.两者的 ...

  6. __proto__ 和 prototype 到底有什么区别

    以前在日常工作中使用 JS 时只是粗浅的知道在原型链中会存在 __proto__ 和 prototype 这2个概念,但真正要回答这2个属性的具体作用以及之间的关系和差异时又总觉得不知道从哪里说起,今 ...

  7. 这些面试题你需要知道

    路口 (一) http状态码及含义 http请求头报文的结构 http和https的区别,https在哪一层加密 Js中的原型和原型链 Js中prototype和_proto_的区别 Js中函数调用的 ...

  8. Spring 循环引用 ——理解singleton与prototype初始化的区别

    所谓的循环引用,就是A依赖B,B又依赖A,A与B两个对象相互持有.像下面这种情况: class A {B b;public A(B b) {this.b=b;} }class B {A a;publi ...

  9. JavaScript_proto_和prototype到底是什么玩意

    JavaScript_proto_和prototype到底是什么玩意 今天去逛了贴吧,发现有人在问instanceof 的类型比较,所以比较贴心的去解释了一下,instanceof是比较左侧的_pro ...

最新文章

  1. 深入理解JDK动态代理
  2. 使用yum安装gitlab
  3. Spring Security 实战干货:实现自定义退出登录
  4. 算法题:找出一个数组中相加值最大的连续序列元素
  5. 着迷英语900句小结
  6. 权值线段树小结(hdu多校,普通平衡树,郁闷的出纳员)
  7. c 语言多参数函数,C/C++实现多参数函数编程
  8. 一款社区论坛小程序源码(修复登录图片发布上传问题)
  9. 深入解析:Row Movement 的原理和性能影响与关联
  10. then 微信小程序_微信小程序和es6 promise的关系
  11. 【台大李宏毅机器学习】机器学习基本概念
  12. 2014.12 总结
  13. 西游记笔记与想法(2)
  14. 使用Unity3D编写ARPG游戏——角色属性的定义与实现(一)
  15. Stratified Transformer复现和调试记录,ubuntu20复现S3DIS数据集(点云语义分割)
  16. 进程冲突造成的深信服ssl ***客户端登录异常问题
  17. 小程序wx.downloadFile下载pdf并保存
  18. Python字符串底层原理
  19. 车羊问题c语言编程,再谈“羊车门”问题
  20. 模仿百度“您要找的是不是:”提示功能

热门文章

  1. 简要分析竞技场3V3职业搭配及用途
  2. 4273. 【NOIP2015模拟10.28B组】圣章-精灵使的魔法语
  3. 深度学习——线性代数
  4. 使用Segment Anything(SAM)模型进行自动标注
  5. 路由信号能不能穿墙,要看这两个东西
  6. 关于如何插入网线(网线没网)的同时连接wifi上网
  7. Windows vbs脚本获取系统信息
  8. Linux内核与根文件系统的关系详解
  9. php 嵌套 mysql_php – 在MySQL中实现SQL INTERSECT时嵌套过高
  10. 16万装饰复古家 独享130平欧式生活