图解prototype、proto和constructor的三角关系


Posted in Javascript onJuly 31, 2016

javascript里的关系又多又乱。作用域链是一种单向的链式关系,还算简单清晰;this机制的调用关系,稍微有些复杂;而关于原型,则是prototype、proto和constructor的三角关系。本文先用一张图开宗明义,然后详细解释原型的三角关系

图示图解prototype、proto和constructor的三角关系

概念

上图中的复杂关系,实际上来源就两行代码

function Foo(){};var f1 = new Foo;

【构造函数】

用来初始化新创建的对象的函数是构造函数。在例子中,Foo()函数是构造函数

【实例对象】

通过构造函数的new操作创建的对象是实例对象。可以用一个构造函数,构造多个实例对象

function Foo(){};
var f1 = new Foo;
var f2 = new Foo;
console.log(f1 === f2);//false

【原型对象及prototype】

构造函数有一个prototype属性,指向实例对象的原型对象。通过同一个构造函数实例化的多个对象具有相同的原型对象。经常使用原型对象来实现继承

function Foo(){};
Foo.prototype.a = 1;
var f1 = new Foo;
var f2 = new Foo;console.log(Foo.prototype.a);
//1
console.log(f1.a);//1
console.log(f2.a);//1

【constructor】

原型对象有一个constructor属性,指向该原型对象对应的构造函数

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

由于实例对象可以继承原型对象的属性,所以实例对象也拥有constructor属性,同样指向原型对象对应的构造函数

function Foo(){};
var f1 = new Foo;
console.log(f1.constructor === Foo);//true

【proto】

实例对象有一个proto属性,指向该实例对象对应的原型对象

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

说明

概念介绍完了,现在对图示的关系进行详细说明

function Foo(){};
var f1 = new Foo;

【第一部分: Foo】

图解prototype、proto和constructor的三角关系

实例对象f1是通过构造函数Foo()的new操作创建的。构造函数Foo()的原型对象是Foo.prototype;实例对象f1通过__proto__属性也指向原型对象Foo.prototype

function Foo(){};
var f1 = new Foo;
console.log(f1.__proto === Foo.prototype);//true

实例对象f1本身并没有constructor属性,但它可以继承原型对象Foo.prototype的constructor属性

function Foo(){};
var f1 = new Foo;console.log(Foo.prototype.constructor === Foo);//true
console.log(f1.constructor === Foo);//true
console.log(f1.hasOwnProperty('constructor'));//false

下图是实例对象f1的控制台效果

图解prototype、proto和constructor的三角关系

【第二部分: Object】

图解prototype、proto和constructor的三角关系

Foo.prototype是f1的原型对象,同时它也是实例对象。实际上,任何对象都可以看做是通过Object()构造函数的new操作实例化的对象

所以,Foo.prototype作为实例对象,它的构造函数是Object(),原型对象是Object.prototype。相应地,构造函数Object()的prototype属性指向原型对象Object;实例对象Foo.prototype的proto属性同样指向原型对象Object

function Foo(){};
var f1 = new Foo;
console.log(Foo.prototype.__proto__ === Object.prototype);//true

实例对象Foo.prototype本身具有constructor属性,所以它会覆盖继承自原型对象Object.prototype的constructor属性

function Foo(){};
var f1 = new Foo;
console.log(Foo.prototype.constructor === Foo);//true
console.log(Object.prototype.constructor === Object);//true
console.log(Foo.prototype.hasOwnProperty('constructor'));//true

下图是实例对象Foo.prototype的控制台效果

图解prototype、proto和constructor的三角关系

如果Object.prototype作为实例对象的话,其原型对象是什么,结果是null。私以为,这可能也是typeof null的结果是'object'的原因之一吧

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

【第三部分: Function】

图解prototype、proto和constructor的三角关系

前面已经介绍过,函数也是对象,只不过是具有特殊功能的对象而已。任何函数都可以看做是通过Function()构造函数的new操作实例化的结果

如果把函数Foo当成实例对象的话,其构造函数是Function(),其原型对象是Function.prototype;类似地,函数Object的构造函数也是Function(),其原型对象是Function.prototype

function Foo(){};
var f1 = new Foo;console.log(Foo.__proto__ === Function.prototype);//true
console.log(Object.__proto__ === Function.prototype);//true

原型对象Function.prototype的constructor属性指向构造函数Function();实例对象Object和Foo本身没有constructor属性,需要继承原型对象Function.prototype的constructor属性

function Foo(){};
var f1 = new Foo;
console.log(Function.prototype.constructor === Function);//true
console.log(Foo.constructor === Function);//true
console.log(Foo.hasOwnProperty('constructor'));//false
console.log(Object.constructor === Function);//true
console.log(Object.hasOwnProperty('constructor'));//false

所有的函数都可以看成是构造函数Function()的new操作的实例化对象。那么,Function可以看成是调用其自身的new操作的实例化的结果

所以,如果Function作为实例对象,其构造函数是Function,其原型对象是Function.prototype

console.log(Function.__proto__ === Function.prototype);//true
console.log(Function.prototype.constructor === Function);//true
console.log(Function.prototype === Function);//true

如果Function.prototype作为实例对象的话,其原型对象是什么呢?和前面一样,所有的对象都可以看成是Object()构造函数的new操作的实例化结果。所以,Function.prototype的原型对象是Object.prototype,其原型函数是Object()

console.log(Function.prototype.__proto__ === Object.prototype);//true

第二部分介绍过,Object.prototype的原型对象是null

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

总结

【1】函数(Function也是函数)是new Function的结果,所以函数可以作为实例对象,其构造函数是Function(),原型对象是Function.prototype

【2】对象(函数也是对象)是new Object的结果,所以对象可以作为实例对象,其构造函数是Object(),原型对象是Object.prototype

【3】Object.prototype的原型对象是null

Javascript 相关文章推荐
innerText和innerHTML 一些问题分析
May 18 Javascript
开发 Internet Explorer 右键功能表(ContextMenu)
Jul 03 Javascript
js中document.write使用过程中的一点疑问解答
Mar 20 Javascript
新入门node.js必须要知道的概念(必看篇)
Aug 10 Javascript
jQuery如何解决IE输入框不能输入的问题
Oct 08 Javascript
纯JS实现表单验证实例
Dec 24 Javascript
ES6 如何改变JS内置行为的代理与反射
Feb 11 Javascript
详解element-ui中form验证杂记
Mar 04 Javascript
优雅的使用javascript递归画一棵结构树示例代码
Sep 22 Javascript
微信小程序自定义tabbar custom-tab-bar 6s出不来解决方案(cover-view不兼容)
Nov 01 Javascript
Vue中添加滚动事件设置的方法详解
Sep 14 Javascript
vue 组件基础知识总结
Jan 26 Vue.js
JavaScript数据类型转换的注意事项
Jul 31 #Javascript
关于JavaScript 原型链的一点个人理解
Jul 31 #Javascript
jquery实现界面无刷新加载登陆注册
Jul 30 #Javascript
AngularJS ng-change 指令的详解及简单实例
Jul 30 #Javascript
Javascript中级语法快速入手
Jul 30 #Javascript
AngularJS ng-blur 指令详解及简单实例
Jul 30 #Javascript
AngularJS ng-bind-template 指令详解
Jul 30 #Javascript
You might like
Zend Framework教程之Zend_Config_Xml用法分析
2016/03/23 PHP
[原创]网络复制内容时常用的正则+editplus
2006/11/30 Javascript
JavaScript constructor和instanceof,JSOO中的一对欢喜冤家
2009/05/25 Javascript
Javascript 函数中的参数使用分析
2010/03/27 Javascript
新发现一个骗链接的方法(js读取cookies)
2012/01/11 Javascript
js模仿html5 placeholder适应于不支持的浏览器
2013/01/13 Javascript
jquery动态加载js/css文件方法(自写小函数)
2014/10/11 Javascript
使用jQuery实现返回顶部
2015/01/26 Javascript
jQuery实现自动滚动到页面顶端的方法
2015/05/22 Javascript
js闭包引起的事件注册问题介绍
2016/03/29 Javascript
js 求时间差的实现代码
2016/04/26 Javascript
js和C# 时间日期格式转换的简单实例
2016/05/28 Javascript
原生js开发的日历插件
2017/02/04 Javascript
JavaScript关联数组用法分析【概念、定义、遍历】
2017/03/15 Javascript
Vue中计算属性computed的示例解读
2017/07/26 Javascript
node.js实现http服务器与浏览器之间的内容缓存操作示例
2020/02/11 Javascript
python实现代理服务功能实例
2013/11/15 Python
详解Python中的__new__()方法的使用
2015/04/09 Python
python机器学习库xgboost的使用
2020/01/20 Python
python中读入二维csv格式的表格方法详解(以元组/列表形式表示)
2020/04/24 Python
Django bulk_create()、update()与数据库事务的效率对比分析
2020/05/15 Python
Python简单实现词云图代码及步骤解析
2020/06/04 Python
如何创建一个Flask项目并进行简单配置
2020/11/18 Python
CSS3的RGBA中关于整数和百分比值的转换
2015/08/04 HTML / CSS
Stella McCartney官网:成衣、包袋、香水、内衣、童装及Adidas系列
2018/12/20 全球购物
预备党员党校学习自我评价分享
2013/11/12 职场文书
硕士生找工作求职信
2014/07/05 职场文书
最新离婚协议书范本
2014/08/19 职场文书
2014年团员学习十八大思想汇报
2014/09/13 职场文书
幼师小班个人总结
2015/02/12 职场文书
食品仓管员岗位职责
2015/04/01 职场文书
2015年行政管理人员工作总结
2015/10/15 职场文书
《坐井观天》教学反思
2016/02/18 职场文书
2016年度农村党员干部主题教育活动总结
2016/04/06 职场文书
nginx刷新页面出现404解决方案(亲测有效)
2022/03/18 Servers
springboot集成redis存对象乱码的问题及解决
2022/06/16 Java/Android