这里讨论下对象的内部原型(__proto__)和构造器的原型(prototype)的关系。
一、所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function)

Number.__proto__ === Function.prototype // true 
Boolean.__proto__ === Function.prototype // true 
String.__proto__ === Function.prototype // true 
Object.__proto__ === Function.prototype // true 
Function.__proto__ === Function.prototype // true 
Array.__proto__ === Function.prototype // true 
RegExp.__proto__ === Function.prototype // true 
Error.__proto__ === Function.prototype // true 
Date.__proto__ === Function.prototype // true

JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的__proto__是Object.prototype。如下
Math.__proto__ === Object.prototype // true 
JSON.__proto__ === Object.prototype // true

上面说的“所有构造器/函数”当然包括自定义的。如下
// 函数声明 
function Person() {} 
// 函数表达式 
var Man = function() {} 
console.log(Person.__proto__ === Function.prototype) // true 
console.log(Man.__proto__ === Function.prototype) // true

这说明什么呢?
所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了Function.prototype的属性及方法。如length、call、apply、bind(ES5)。
Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象。如下
console.log(typeof Function.prototype) // function 
console.log(typeof Object.prototype) // object 
console.log(typeof Number.prototype) // object 
console.log(typeof Boolean.prototype) // object 
console.log(typeof String.prototype) // object 
console.log(typeof Array.prototype) // object 
console.log(typeof RegExp.prototype) // object 
console.log(typeof Error.prototype) // object 
console.log(typeof Date.prototype) // object 
console.log(typeof Object.prototype) // object

噢,上面还提到它是一个空的函数,alert(Function.prototype) 下看看。
知道了所有构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢?
相信都听说过JavaScript中函数也是一等公民,那从哪能体现呢?如下
console.log(Function.prototype.__proto__ === Object.prototype) // true

这说明所有的构造器也都是一个普通JS对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。
最后Object.prototype的__proto__是谁?
Object.prototype.__proto__ === null // true

已经到顶了,为null。
二、所有对象的__proto__都指向其构造器的prototype
上面测试了所有内置构造器及自定义构造器的__proto__,下面再看看所有这些构造器的实例对象的__proto__指向谁?
先看看JavaScript引擎内置构造器
var obj = {name: 'jack'} 
var arr = [1,2,3] 
var reg = /hello/g 
var date = new Date 
var err = new Error('exception') 
console.log(obj.__proto__ === Object.prototype) // true 
console.log(arr.__proto__ === Array.prototype) // true 
console.log(reg.__proto__ === RegExp.prototype) // true 
console.log(date.__proto__ === Date.prototype) // true 
console.log(err.__proto__ === Error.prototype) // true

再看看自定义的构造器,这里定义了一个Person
function Person(name) { 
this.name = name 
} 
var p = new Person('jack') 
console.log(p.__proto__ === Person.prototype) // true

p是Person的实例对象,p的内部原型总是指向其构造器Person的prototype。
每个对象都有一个constructor属性,可以获取它的构造器,因此以下打印结果也是恒等的
function Person(name) { 
this.name = name 
} 
var p = new Person('jack') 
console.log(p.__proto__ === p.constructor.prototype) // true

上面的Person没有给其原型添加属性或方法,这里给其原型添加一个getName方法
function Person(name) { 
this.name = name 
} 
// 修改原型 
Person.prototype.getName = function() {} 
var p = new Person('jack') 
console.log(p.__proto__ === Person.prototype) // true 
console.log(p.__proto__ === p.constructor.prototype) // true

可以看到p.__proto__与Person.prototype,p.constructor.prototype都是恒等的,即都指向同一个对象。
如果换一种方式设置原型,结果就有些不同了
function Person(name) { 
this.name = name 
} 
// 重写原型 
Person.prototype = { 
getName: function() {} 
} 
var p = new Person('jack') 
console.log(p.__proto__ === Person.prototype) // true 
console.log(p.__proto__ === p.constructor.prototype) // false

这里直接重写了Person.prototype(注意:上一个示例是修改原型)。输出结果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。
这也很好理解,给Person.prototype赋值的是一个对象直接量{getName: function(){}},使用对象直接量方式定义的对象其构造器(constructor)指向的是根构造器Object,Object.prototype是一个空对象{},{}自然与{getName: function(){}}不等。如下
var p = {} 
console.log(Object.prototype) // 为一个空的对象{} 
console.log(p.constructor === Object) // 对象直接量方式定义的对象其constructor为Object 
console.log(p.constructor.prototype === Object.prototype) // 为true,不解释

上面代码中用到的__proto__目前在IE6/7/8/9中都不支持。IE9中可以使用Object.getPrototypeOf(ES5)获取对象的内部原型。
var p = {} 
var __proto__ = Object.getPrototypeOf(p) 
console.log(__proto__ === Object.prototype) // true

JavaScript中__proto__与prototype的关系深入理解的更多相关文章

  1. prototype Element学习笔记(篇一)

    Element,哈哈哈。遇到正主了,到现在为止才遇到让我高兴的玩意。当初Ext.Element可是花三千余行代码专门来封装啊。我倒要看一看它的代码了。事实上prototype中我最想研究的只有两个内容:Element、Selector。这两个东西是精华。

  2. javascript prototype 原型链

    prototype源自法语,软件界的标准翻译为“原型”,代表事物的初始形态,也含有模型和样板的意义。

  3. prototype1.5 初体验第1/2页

    一直没有没有时间看prototype,现在好了,已经更新到了1.5pre1,呵呵,强大的功能不得不学习啊,这个是提升自己JS能力的又一个捷径.1.Prototype是什么?或许你还没有用过它,prototype.js是一个由SamStephenson写的JavaScript包。像所有在我之前的开发者一样,我只能一头扎进prototype.js的源代码中并且试验其中的每一个部分。从Prototype1.5.x版本开始,你可以更方便的如下面代码一样操作DOM对象了:这样的改变有什么益处呢?使用Try.thes

  4. Prototype源码浅析 String部分(一)之有关indexOf优化

    Prototype源码浅析 String部分(一)之有关indexOf优化介绍,需要的朋友可以参考下。

  5. Prototype Number对象 学习

    这个对象提供一些操作数值类型的工具函数

  6. 深入理解JS中的Function.prototype.bind()方法

    bind 是 ES5 中新增的一个方法,可以改变函数内部的this指向。这篇文章小编将带领大家深入理解Javascript中的Function.prototype.bind()方法。有需要的朋友们可以参考借鉴,下面来一起看看吧。

  7. Javascript学习笔记9 prototype封装继承

    在上文中,我利用prototype的原理做了一个封装的New,然后我就想到,我是否可以用prototype的原理进一步封装面向对象的一些基本特征呢?比如继承。

  8. Prototype Object对象 学习

    该不是一个概念。因为C#中的命名空间后面不会直接跟方法,肯定是接一个对象然后在调用方法,不过和C++中的命名空间倒是有些类似

  9. PHP设计模式(四)原型模式Prototype实例详解【创建型】

    这篇文章主要介绍了PHP设计模式:原型模式Prototype,结合实例形式详细分析了PHP原型模式Prototype的基本概念、功能、原理、实现方法与操作注意事项,需要的朋友可以参考下

  10. Prototype Selector对象学习

    这个对象在帮助文档上并没有,但是这个对象确是整个DOM操作的核心类,工具函数$$,其实就是调用这个类的方法

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部