作者:苏墨橘
来源:知乎
备注:本篇文章比较清楚的解释了__proto__属性、prototype、instanceof,秉持一贯风格,好文收藏,贴在这里供大家学习。

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

1.是什么

  • 显式原型 explicit prototype property:

每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。
Note:通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。(感谢

@陈禹鲁

同学的答案让我知道这一点)

NOTE Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties. ----- ECMAScript Language Specification

  • 隐式原型 implicit prototype link:

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

  • 二者的关系:

隐式原型指向创建这个对象的函数(constructor)的prototype

2. 作用是什么

  • 显式原型的作用:用来实现基于原型的继承与属性的共享。

ECMAScript does not use classes such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initialises all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.Objects are created by using constructors in new expressions; for example, new Date(2009,11) creates a new Date object. ----ECMAScript Language Specification

  • 隐式原型的作用:构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次查找。

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” ----ECMAScript Language Specification

3. __proto__的指向
__proto__的指向到底如何判断呢?根据ECMA定义 'to the value of its constructor’s "prototype" ' ----指向创建这个对象的函数的显式原型。所以关键的点在于找到创建这个对象的构造函数,接下来就来看一下JS中对象被创建的方式,一眼看过去似乎有三种方式:(1)对象字面量的方式 (2)new 的方式 (3)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() 创建出来的对象没有构造函数,看到这里你是不是要问,没有构造函数我怎么知道它的__proto__指向哪里呢,其实这里说它没有构造函数是指在 Object.create() 函数外部我们不能访问到它的构造函数,然而在函数内部实现中是有的,它短暂地存在了那么一会儿。假设我们现在就在函数内部,可以看到对象的构造函数是F, 现在

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

因此由Object.create(o)创建出来的对象它的隐式原型指向o。好了,对象的创建方式分析完了,现在你应该能够判断一个对象的__proto__指向谁了。

好吧,还是举一些一眼看过去比较疑惑的例子来巩固一下。

  • 构造函数的显示原型的隐式原型:
  1. 内建对象(built-in object):比如Array(),Array.prototype.__proto__指向什么?Array.prototype也是一个对象,对象就是由 Object() 这个构造函数创建的,因此Array.prototype.__proto__ === Object.prototype //true,或者也可以这么理解,所有的内建对象都是由Object()创建而来。
  • 自定义对象

1. 默认情况下:

function Foo(){}
var foo = new Foo()
Foo.prototype.__proto__ === Object.prototype //true 理由同上

2. 其他情况:
(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

4. instanceof
instanceof 操作符的内部实现机制和隐式原型、显式原型有直接的关系。instanceof的左值一般是一个对象,右值一般是一个构造函数,用来判断左值是否是右值的实例。它的内部实现原理是这样的:

//设 L instanceof R
//通过判断L.__proto__.__proto__ ..... === R.prototype ?
//最终返回true or false

也就是沿着L的__proto__一直寻找到原型链末端,直到等于R.prototype为止。知道了这个也就知道为什么以下这些奇怪的表达式为什么会得到相应的值了

 Function instanceof Object // true Object instanceof Function // true Function instanceof Function //true Object instanceof Object // true Number instanceof Number //false

文章参考:JavaScript instanceof 运算符深入剖析

转载于:https://www.cnblogs.com/xsfx/p/7152674.html

js中__proto__和prototype的区别和联系相关推荐

  1. JS中__proto__和prototype都是什么?原型链继承解读

    首先要知道,prototype是函数才有的属性,__proto__是每个对象都有的属性 随后,先谈一下 1.什么是prototype? prototype对象是JS实现面向对象的一个重要机制. 在很早 ...

  2. Js中的style,currentStyle,getComputedStyle()区别

    Js中的style,currentStyle,getComputedStyle()区别  样式表有三种方式: 1.内嵌样式(inline Style)-是写在Tag里面的,内嵌样式只对所有的Tag有效 ...

  3. JS中 let 和var的区别

    JS中let和var 的区别 简单介绍let var的常见变量提升 ES6可以用let定义块级作用域变量 let配合for循环的独特应用 let没有变量提升与暂时性死区 let变量不能重复声明 简单介 ...

  4. uniapp 获取到js文件var一个变量怎么获取到这个变量值_浅析Js中const,let,var的区别及作用域...

    理解:let变量的作用域只能在当前函数中 js中const,let,var的区别及作用域_lianzhang861的博客-CSDN博客​blog.csdn.net 全局作用域中,用 const 和 l ...

  5. js中的extend的用法及其JS中substring与substr的区别

    1.    JS中substring与substr的区别 之前在项目中用到substring方法,因为C#中也有字符串的截取方法Substring方法,当时也没有多想就误以为这两种方法的使用时一样的. ...

  6. js中几个对象的区别和用法

    js中几个对象的区别和用法 今天总结一下js中几个对象的区别和用法: 首先来说说 parent.window与top.window的用法 "window.location.href" ...

  7. js中DOM, DOCUMENT, BOM, WINDOW 区别

    全栈工程师开发手册 (作者:栾鹏) js系列教程6-BOM操作全解 js系列教程7-DOM操作全解 js中DOM, DOCUMENT, BOM, WINDOW 区别 DOM 全称是 Document ...

  8. js中click()与onclick()的区别

    由一个简单示例到 js中click()与onclick()的区别 之前朋友在学习js的时候遇到一个有意思的问题. 先贴一份代码说一下代码构成 这里是html结构 <ul><li> ...

  9. js中parentNode和parentElement的区别和用法

    了解本篇的基础必须知道什么是节点,关于html dom节点知识点和节点类型的知识,分别看<js节点都有哪些类型?怎么判断是哪种节点类型?>和<js属性节点获取和移除>,下面直接 ...

  10. js中 函数和方法的区别:转载于黑泽君

    js中 函数和方法的区别 在javascript中的解释为: 函数(function)是可以执行的javascript代码块,由javascript程序定义或javascript实现预定义.函数可以带 ...

最新文章

  1. RedHat 5.4 RHCE DHCP学习笔记
  2. ViewPager用法
  3. 2020-09-26
  4. c malloc 头文件_C/C++笔试题:主要考察C/C++语言基础概念算法及编程,附参考答案...
  5. 终端到服务器丢包,服务器丢包 ping的时候产生丢包的解决方法
  6. jodd忽略ssl证书_关于java访问https资源时,忽略证书信任问题
  7. oracle数据库导出和oracle导入数据的二种方法(oracle导入导出数据)
  8. php连接Access实例
  9. Atitit.angular.js 使用最佳实践 原理与常见问题解决与列表显示案例 attilax总结
  10. 正则表达式手机号(大陆,香港)
  11. 微信小程序码获取-从频繁失败到成功率100%
  12. [笔记] Codeforces#274 Riding in a Lift (479E) DP
  13. 微信网页授权并获取用户信息
  14. 2020考研上海交通大学823计算机通信网真题回忆
  15. ios上编译c语言,如何构建C编写的库并在iOS中使用
  16. 三参数坐标转换matlab,Coordinate-conversion
  17. 逻辑思维训练500题(带答案)前237题 文末附完整版PDF
  18. 2017大学计算机考试题,【2017年最新】新生福利:大学计算机基础入学考试题库...
  19. 2022-6月后两周前端实习面经base北京-已入职滴滴
  20. ROS笔记(33) 关节空间规划

热门文章

  1. 小程序 switch 自定义_微信小程序自定义组件问题一:获取组件DOM元素
  2. 第二天:继续完善路由层(router)及数据层(controller)
  3. js声明数组的四种方式
  4. layui 监听表单提交form.on(‘submit(sub)‘,function (){}) ajax请求失败问题
  5. Package ffnvcodec was not found in the pkg-config search path
  6. LINUX下载编译libc(glibc)
  7. LINUX虚拟机安装增强功能时报错:/sbin/mount.vboxsf: mounting failed with the error: No such device
  8. SHELL中获取函数返回值
  9. 大群就是公共场所,不要有事就在大群说
  10. 也谈谈古代一两银子相当于今天的价格