深入理解__proto__ 、constructor和prototype的关系

版权声明:本文为博主原创文章,未经博主允许不得转载。
- <!doctype html>
- <html>
- <head>
- <meta charset="utf-8">
- </head>
- <body>
- <script type="text/javascript">
- /**
- @authors Benjamin
- @date 2013-11-12 10:23:40
- 深入理解javascript 原型和原型链
- 最近不是很忙,空余时间整理最近几天看到的关于原型和原型链的文章,收获还是不小的。
- 今天十八届三中全会即将闭幕,期待新一届领导班子的改革方略,能够惠民吧
- 房价,户籍都是让80后很蛋疼的问题哈,当然,做为屌丝的我,肯定也是。
- 开篇先了解下两个很有用的属性:
- 一、__proto__属性:
- __proto__属性未来会成为ES6标准的一部分,目前,该属性在各个浏览器下的实现差别也许比较大.Firefox是最先实现的这个魔法属性(magic property)的浏览器,而且该属性在Firefox中的表现也最有望能成为标准.我们通常用的__proto__属性都是从Object.prototype上继承下来的,那到底__proto__与prototype什么关系呢?
- 1)所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function)
- 看看实例:
- */
- console.log(Number.__proto__ === Function.prototype) // true
- console.log(Boolean.__proto__ === Function.prototype) // true
- console.log(String.__proto__ === Function.prototype) // true
- console.log(Object.__proto__ === Function.prototype) // true
- console.log(Function.__proto__ === Function.prototype) // true
- console.log(Array.__proto__ === Function.prototype) // true
- console.log(RegExp.__proto__ === Function.prototype) // true
- console.log(Error.__proto__ === Function.prototype) // true
- console.log(Date.__proto__ === Function.prototype) // true
- /*
- JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的__proto__是Object.prototype。如下
- */
- console.log("对象测试...");
- console.log(Math.__proto__ === Object.prototype);//true
- console.log(JSON.__proto__ === Object.prototype);//true
- /**
- * 上面说的“所有构造器/函数”当然包括自定义的。看下面的例子:
- */
- var Employee = function (){
- };
- function Person(){
- }
- console.log("自定义函数测试...");
- console.log(Employee.__proto__ === Function.prototype);//true
- console.log(Person.__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("类型测试中...");
- 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
- /**
- * Function.prototype 是一个空函数,我们来测试下
- */
- console.log("空函数测试...");
- console.log(Function.prototype);//function(){}
- //用alert来看会更直接点
- //alert(Function.prototype);//function(){}
- /**
- * 下面我们来看看Function.prototype 的__proto__是谁呢?看下面的测试
- */
- console.log("Function.prototype的__proto__测试...");
- console.log(Function.prototype.__proto__ === Object.prototype);//true
- /**
- * 那Object.prototype的__proto__又是谁呢?看下面测试
- */
- console.log(Object.prototype.__proto__);//输出null
- /*
- 2)所有对象的__proto__都指向其构造器的prototype
- 来看看以下实例
- */
- console.log("对象的__proto__测试中...");
- //函数声明
- function Foo(){
- }
- var foo = new Foo();//对象实例化
- console.log(foo.__proto__ === Foo.prototype);//true
- //函数表达式
- var Foo = function (){}
- var foo = new Foo();//对象实例化
- console.log(foo.__proto__ === Foo.prototype);//true
- /**
- * 看完自定义函数,下面我们来看看javascript引擎内置构造器
- */
- var
- arr = ["aaa", "bbb"],
- reg = /^abc$/g,
- obj = {
- name: "张三",
- age: 20
- },
- date = new Date(),
- error = new Error("fdasfdasfd");
- console.log("内置构造器的对象测试...");
- console.log(arr.__proto__ === Array.prototype);//true
- console.log(obj.__proto__ === Object.prototype);//true
- console.log(reg.__proto__ === RegExp.prototype);//true
- console.log(date.__proto__ === Date.prototype);//true
- console.log(error.__proto__ === Error.prototype);//true
- /**
- * 二、constuctor属性
- * constructor属性始终指向创建当前对象的构造函数,看下面的实例
- */
- var
- arr = ["aaa", "bbb"],
- reg = /^abc$/g,
- obj = {
- name: "张三",
- age: 20
- },
- date = new Date(),
- error = new Error("fdasfdasfd");
- console.log("constructor指向测试...");
- console.log(arr.constructor === Array);//true
- console.log(obj.constructor === Object);//true
- console.log(reg.constructor === RegExp);//true
- console.log(date.constructor === Date);//true
- console.log(error.constructor === Error);//true
- /**
- * 我们都知道函数是对象,对象都有prototype属性,那么这个prototype的constructor属性指向谁呢?
- * 由以下实例得出结论,其constructor指也向其构造函数
- */
- console.log("prototype的constructor属性指向测试...");
- //函数声明
- function Foo(){
- }
- console.log(Foo.prototype.constructor === Foo);//true
- //函数表达式
- var Foo = function (){
- };
- console.log(Foo.prototype.constructor === Foo);
- /**
- * 那么一个函数的实例指向谁呢?
- */
- function Foo(){
- }
- var f1 = new Foo();
- console.log("测试constructor实例化指向...");
- console.log(f1.constructor === Foo);
- console.log(f1.constructor.prototype.constructor === Foo);
- /**
- * 到此我们来必须来总结下子了:
- * f1 = new Foo();
- * f1.__proto__ === Foo.prototype.__proto__ === Object.prototype
- * Foo.prototype.constructor === Foo
- * Foo.__proto__ === Function.prototype.__proto__ === Object.prototype
- * 这样看起来貌似还是比较乱,下面用一张图来总结以上问题,如下图:
- */
- /**
- * 开一个怪例子,当我们重定义prototype对象时,constructor的行为会有什么变化呢?
- */
- function Foo(name){
- this.name = name;
- }
- Foo.prototype = {
- getName :function (){
- return this.name;
- }
- };
- var f1 = new Foo();
- console.log("重定义prototype对象测试...");
- console.log(f1.constructor === Foo); //false
- console.log(Foo.prototype.constructor === Foo);//false
- console.log(f1.constructor === Object);//true
- console.log(Foo.prototype.constructor === Object);//true
- /**
- * 是什么原因导致的此问题呢?来分析哈子,其实定义Foo.prototype = {}
- * 其实等价于Foo.prototype = new Object({"getName":function(){return this.name;}})
- * 因此Foo.prototype.constuctor === Obeject 返回true
- * 那么怎么让前面的两个false 变为true,做如下操作:
- */
- Foo.prototype.constructor = Foo;
- var f1 = new Foo();
- console.log("重新指向测试...");
- console.log(f1.constructor === Foo); //true
- console.log(Foo.prototype.constructor === Foo);//true
- </script>
- </body>
- </html>
在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要。
我们在定义函数的时候,函数定义的时候函数本身就会默认有一个prototype的属性,而我们如果用new 运算符来生成一个对象的时候就没有prototype属性。我们来看一个例子,来说明这个

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
var obj = new a('test');
alert(typeof obj.prototype);//undefine
alert(typeof a.prototype);//object

从上面的例子可以看出函数的prototype 属性又指向了一个对象,这个对象就是prototype对象,请看下图

a.prototype 包含了2个属性,一个是constructor ,另外一个是__proto__
这个constructor 就是我们的构造函数a,这个也很容易理解。
那么__proto__ 是什么呢?
这个就涉及到了原型链的概念:
每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性 时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去。
请看mozzlia 对它对它的描述
When an object is created, its __proto__ property is set to constructing function's prototype property. For example var fred = new Employee(); will cause fred.__proto__ = Employee.prototype;.
This is used at runtime to look up properties which are not declared in the object directly. E.g. when fred.doSomething() is executed and fred does not contain adoSomething, fred.__proto__ is checked, which points to Employee.prototype, which contains a doSomething, i.e. fred.__proto__.doSomething() is invoked.
Note that __proto__ is a property of the instances, whereas prototype is a property of their constructor functions.
不管你信不信,我们来看图
在后面如果加上 alert(obj.__proto__ === a.prototype) //true
同理,在这里我们来分析出new 运算符做了那些事情
- var obj={}; 也就是说,初始化一个对象obj。
- obj.__proto__=a.prototype;
- a.call(obj);也就是说构造obj,也可以称之为初始化obj。
我们将这个例子改造一些,变得复杂一点。

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
a.prototype.test = function(){
alert(this.b);
}
var obj = function (){}
obj.prototype = new a('test');
obj.prototype.test1 =function(){
alert(22222);
}
var t = new obj('test');
t.test();//alert('test');

我们来分析下这个过程
由 var t = new obj('test'); 我们可以得到 t.__proto__ = obj.prototype,但是上面指定obj.prototype =new a('test'); 可以这样来看下
obj.prototype = p, p = new a('test'); p.__proto__ = a.prototype;
那么obj.prototype.__proto__ = a.prototype,由 t.__proto__ = obj.prototype 可以得出 t.__proto__.__proto__ = a.prototype,
所以对象t先去找本身是的prototype 是否有test函数,发现没有,结果再往上级找,即 t.__proto__ ,亦即obj.prototype 寻找test函数 ,但是obj.prototype 也没有这个函数,然后再往上找。即
t.__proto__.__proto__ 找,由于t.__proto__.__proto__ = a.prototype 在 a.prototype 中找到了这个方法,输出了alert('test')
从这里可以分析得出一个结论,js中原形链的本质在于 __proto__
再看看一个列子

function a(c){
this.b = c;
this.d =function(){
alert(this.b);
}
}
var obj = new a('test');
alert(obj.constructor);//function a(){}
alert(a.prototype.constructor);//function a(){}

根据上面讲到的__proto__ 我们来分析下,首先obj是没有constructor 这个属性的,但是 obj.__proto__ = a.prototype;就从
a.prototype中寻找,而 a.prototype.constructor 是就a,所有两者的结果是一一样的.
深入理解__proto__ 、constructor和prototype的关系的更多相关文章
- 彻底理解JavaScript中的prototype、__proto__
虽然在JavaScript里一切皆对象,但为了理解原型链系统,我们需要将JavaScript的对象分为对象和函数两大类.在此基础上,JavaScript的原型链逻辑遵从以下通用规则: 对象有__pro ...
- javascript 中isPrototypeOf 、hasOwnProperty、constructor、prototype等用法
hasOwnProperty:是用来判断一个对象是否有你给出名称的属性或对象,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员. isPrototypeOf是用来判断要检查 ...
- constructor、prototype、isPrototypeOf、instanceof、in 、hasOwnProperty
constructor.prototype.isPrototypeOf.instanceof.in .hasOwnProperty等等 constructor:对象构造器.存在于原型对象中?,相当于p ...
- 面向对象的程序设计(二)理解各种方法和属性typeof、instanceof、constructor、prototype、__proto__、isPrototypeOf、hasOwnProperty
//理解各种方法和属性typeof.instanceof.constructor.prototype.__proto__.isPrototypeOf.hasOwnProperty. //1.typeo ...
- js中__proto__和prototype constructor 的区别和关系
https://www.zhihu.com/question/34183746 javaScript原型.原型链的定义? prototype:每个函数都有一个prototype(显式原型),这个属性是 ...
- <JavaScript>constructor、prototype、__proto__和原型链
在看了网上很多相关的文章,很多都是懵逼看完,并不是说各位前辈们写得不好,而是说实在不容易在一两次阅读中理解透.我在阅读了一些文章后,自己整理总结和绘制了一些相关的图,个人认为会更容易接受和理解,所以分 ...
- JavaScript中__proto__与prototype的关系
一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...
- 深入理解原型链(Prototype chain) __proto__
原型链(Prototype chain) 原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain). A prot ...
- JavaScript中__proto__与prototype的关系(转)
一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) 1 2 3 4 5 6 7 8 9 Number.__proto__ ...
随机推荐
- python学习三十五天函数递归的用法
python函数递归就是自己调用自己,无限循环,但是python限制了调用的次数1000次,就会终止,递归用在栏目分类,采集程序比较多,下面简单说函数递归用法和实例 1,函数递归用法 def func ...
- 攻防世界--python-trade
测试文件:https://adworld.xctf.org.cn/media/task/attachments/69c8f29912ae4f679d92a6cd36c33196.pyc 这里需要用到一 ...
- 2. ZooKeeper基础
1. ZooKeeper的特性 ZooKeeper的特性主要从会话.数据节点,版本,Watcher,ACL权限控制,集群角色这些部分来了解,其中需要重点掌握的数据节点与Watcher 1.1 会话 客 ...
- 【学习总结】cpu缓存
参考链接: cpu缓存java性能问题初探 高速缓存 在内存与cpu寄存器之间,还有一块区域叫做cpu高速缓存,即我们常常说的cache. cache分为L1.L2.L3三级缓存,速度递减,离cpu越 ...
- 01.Linux-CentOS系统网卡名称变动问题
方法一root登陆系统1.删除原来的配置信息[root@localhost ~]# rm -f /etc/sysconfig/network-scripts/ifcfg-eth0[root@local ...
- Django——Ajax相关
Ajax简介 AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传输的数 ...
- Sass-减法
Sass 的减法运算和加法运算类似,我们通过一个简单的示例来做阐述: 同样的,运算时碰到不同类型的单位时,编译也会报错,如:
- hadoop集群常见问题解决
1:namenode启动 datanode未启动 解决: /hadoop/tmp/dfs/name/current VERSION 查看截取id 与 data/current VERSION集群ID ...
- web安全—tomcat禁用WebDAV或者禁止不需要的 HTTP 方法
现在主流的WEB服务器一般都支持WebDAV,使用WebDAV的方便性,呵呵,就不用多说了吧,用过VS.NET开发ASP.Net应用的朋友就应该 知道,新建/修改WEB项目,其实就是通过WebDAV+ ...
- JSOI2018冬令营游记&总结(迁移自洛谷博客)
游记 一开始在冬令营还没开始的时候,十分期待,殊不知每天都有一场浩劫在等着我. Day0 10:50出发,看见lbn同学发了一条说说,也随便发了一个. 然后在车上一直在睡觉,现在感觉挺后悔的,其实可以 ...