深入理解__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__ ...
随机推荐
- Pandas的高级操作
pandas数据处理 1. 删除重复元素 使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True keep参数: ...
- 进程池和multiprocess.Pool模块
一.为什么要有进程池 首先,创建进程需要消耗时间,销毁进程也需要时间.其次,即使开启了成千上万的进程,操作系统也不能让它们同时执行,这样反而会影响程序的效率.因此我们不能无限制的根据任务开启或者结束进 ...
- JVM(12)之 可视化分析工具
开发十年,就只剩下这套架构体系了! >>> 经过前几篇博文对堆内存以及垃圾收集机制的学习,相信小伙伴们已经建立了一套比较完整的理论体系!本篇博客就根据已有的理论知识,通过可视化工 ...
- spring(三):spring中BeanPostProcessor的使用
spring中实现BeanPostProcessor的后置处理器 ApplicationContextAwareProcessor 进入该实现类内部 可以看到:该类帮我们组建IOC容器,判断我们的be ...
- Spring Boot 2 Webflux的全局异常处理
https://www.jianshu.com/p/6f631f3e00b9 本文首先将会回顾Spring 5之前的SpringMVC异常处理机制,然后主要讲解Spring Boot 2 Webflu ...
- 【LeetCode】双指针 two_pointers(共47题)
[3]Longest Substring Without Repeating Characters [11]Container With Most Water [15]3Sum (2019年2月26日 ...
- ltp-ddt eth_iperf_tcp iperf dualtest遇到的问题
ltp-ddt eth_iperf_tcp server端:iperf -s -i 5 -w 1M client端将ddt的核心代码抠出来: iperf -c 1921.68.40.41 -m -M ...
- Go copy 的使用
copy 可以将后面的 第2个切片的元素赋值copy 到第一个切片中 package main; import "fmt" func test () { s1 := []int{1 ...
- 第01章 Spring概述
第01章 Spring概述 1.Spring概述 ①Spring是一个开源框架 ②Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能.同样的 ...
- java资料搜索网站
http://yun.java1234.com/ 盘多多 B站 一个集成了很多springboot功能的地址 https://gitbub.com/runzhenghengbin/SpringBoot ...