鄙人对constructor和prototype的总结
在学习js面向对象过程中,我们总是对constructor和prototype充满疑惑,这两个概念是相当重要的,深入理解这两个概念对理解js的一些核心概念非常的重要。因此,在这里记录下鄙人见解,希望可以给读者带来一些帮助.如若有错,请大佬们不吝指正,小弟十分感谢!
prototype
参考高程三:无论什么时候,只要创建一个函数,就会根据特定规则为该函数创建prototype属性,这个属性指向函数的原型对象.
换言之,我们自己定义的函数在这里我称之为自定义函数吧,每个自定义函数都有一个默认的prototype属性.然后这个属性指向函数的原型对象.那这个原型对象有什么特别呢?
如果这个自定义函数被用在创建自定义对象的场景中,我们称这个函数为构造函数。构造函数中原型对象中的属性和方法可以被使用该构造函数创建出来的实例对象使用.即以构造函数方式创建出来的所有实例对象,自动拥有和共享该构造函数的原型对象中的所有属性和方法.利用这点,我们看下面的代码:
//定义构造函数Animal function Animal(name) { this.name = name; } //设置构造函数Animal原型对象上的方法 Animal.prototype.shout =function (){ console.log('wow wow'); } //通过构造函数Animal创建实例对象a1,该过程称为实例化 var a1 = new Animal('小白'); a1.shout(); // 'wow wow'
那实例对象为什么可以继承创建该实例的构造函数的原型对象上的属性/方法呢?这里说的很绕口,我们再引入一个概念.
当用构造函数创建实例对象的时候,该实例的内部也将包含一个指针(内部属性),指向构造函数的原型对象.ECMA-262第5版中管这个指针叫[[Prototype]].我们把它称为对象的原型.
虽然在脚本中没有标准的方式访问它.但Firefox Safari Chrome在每个对象上都支持一个属性__proto__;后来ECMAScript 5 增加了一个新方法,叫Object.getPrototypeOf(),在所有支持的实现中,这个方法返回[[Prototype]]的值.其实__proto__和这个方法的作用是一样的(区别一个是部分浏览器厂商实现的非标准,一个是后来推出的标准),都是获取对象的原型.文章后面一律用这个__proto__来表示对象的原型.
一定要区分好原型和原型对象哦.虽然指向的是同一个对象za,但是访问的方法不一样,叫法不一样.鄙人总结了一下:
① 构造函数.prototype(访问构造函数的原型对象)
prototype属性:只有函数才有的,它跟原型链没有关系.它的作用是构造函数new对象时,告诉新创建对象的原型是谁.
② 实例对象.__proto__(访问实例对象的原型)
__proto__属性:是所有对象(包括函数)都有的,它才叫做对象的原型,原型链就是靠它形成的.(不是ECMA标准,仅供开发者调试使用,不要用于正式开发)
构造函数.prototype === 实例对象.__proto__
我们可以画一个图帮助理解
说回刚才的问题,为什么实例对象可以继承原型创建该实例的构造函数的原型对象上的属性/方法吧!
以上面的代码来说.构造函数new形式创建实例对象的过程实际上可以分为
1. var inobj = { } //创建一个内置对象
2. 如果Animal.prototype是Object类型,则将inobj.__proto__设置为Animal.prototype,否则inobj.__proto__将初始化值(即Object.prototype) //设置了新创建对象的__proto__
3. 把inobj赋值给this,Animal.call(inobj)
4. 如果[[Call]]的返回值是Object类型,则返回这个值,否则返回inobj
那么a1就接收了这个返回值,也就是刚刚创建的inobj对象.
那么继承又是怎么实现的?这就要讲到js原型链的搜索机制了.
当对象访问某属性或者调用某个方法时:
① 首先在实例对象中搜索该属性/方法
② 如果没有找到则搜索实例对象.__proto__上的属性/方法
③ 如此一层一层沿着原型链继续向上搜索
④ 直到查找到Object.prototype(原型链的顶端),如果有就直接使用,如果没有,返回undefined或者报错
正是因为有这样的搜索机制,inobj设置了__proto__之后,将会继承原型上的属性和方法,然后继承原型的原型上的属性和方法......
JS原型链的本质在于__proto__,也就是前文所说的[[Prototype]].
constructor
简单一点说,constructor始终指向创建当前实例对象的构造函数.
根据高程三的说法,无论什么时候,只要创建了一个新函数,就会根据特定规则为该函数创建一个prototype属性,这个属性指向函数的原型对象.在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性指向prototype属性所在的函数,也就是指向构造函数.我们通过实例对象.constructor方法访问的其实就是原型对象上的constructor属性
下面的代码为例,a1.constructor----a1有constructor属性吗?没有,然后通过原型链查找到---->a1.__proto__ , 也就是Animal.prototype上的constructor属性
//定义构造函数Animal function Animal(name) { this.name = name; } //设置构造函数Animal原型对象上的方法 Animal.prototype.shout =function (){ console.log('wow wow'); } //通过构造函数Animal创建实例对象a1,该过程称为实例化 var a1 = new Animal('小白'); console.log(a1.constructor); //打印的是创建a1的构造函数Animal // ƒ Animal(name) { this.name = name; }
但是当constructor遇到prototype时,有趣的事情就发生了。
我们知道每个函数都有一个默认的属性prototype,而这个prototype指向的原型对象上的constructor属性默认指向prototype属性所在的函数,也就是这个函数。如下例所示:
function Person(name) { this.name = name; }; Person.prototype.sayName = function () { console.log(this.name); }; var p = new Person("ZhangSan"); console.log(p.__proto__.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true console.log(p.constructor === Person); // true console.log(p.hasOwnProperty('constructor')); //false //检测实例上有constructor属性吗?答案是false console.log(p.__proto__.hasOwnProperty('constructor')); //true //在原型对象上检测到有constructor属性存在
因此结合代码输出结果,结合上面的图片就不难理解constructor属性从何而来,指向何处了吧!
结论:构造函数默认有prototype属性,指向原型对象,构造函数的原型对象(实例对象的原型)默认有constructor属性,指向构造函数.
不过,这个constructor 属性易变,不可信赖!
当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是覆盖),
constructor的行为就有点奇怪了,如下面例子:
function Person(name) { this.name = name; }; Person.prototype = { sayName: function() { console.log(this.name); } }; var p = new Person("ZhangSan"); console.log(p.__proto__.constructor === Person); // false console.log(Person.prototype.constructor === Person); // false console.log(p.constructor === Person); // false console.log(p.constructor === Object); // true console.log(p.__proto__.constructor === Object); // true console.log(Person.prototype.constructor === Object); // true
为什么呢?
原来是因为覆盖Person.prototype时,等价于进行如下代码操作:
Person.prototype = new Object({ sayName: function() { console.log(this.name); } });
而constructor始终指向创建自身的构造函数,所以此时Person.prototype.constructor === Object
怎么修正这种问题呢?方法也很简单,重新覆盖Person.prototype.constructor即可
function Person(name) { this.name = name; }; Person.prototype = { constructor : Person, sayName: function() { console.log(this.name); } }; var p = new Person("ZhangSan"); console.log(p.__proto__.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true console.log(p.constructor === Person); // true console.log(p.constructor === Object); // false console.log(p.__proto__.constructor === Object); // false console.log(Person.prototype.constructor === Object); // false
所以说constructor属性易变,如果是直接在原型上添加属性和方法倒是不会改变constructor,但是重写原型对象后若没有手动修正constructor属性,那么就不可靠了.
其实 constructor 的出现原本就是用来进行对象类型判断的,既然不可靠,那我们有一种更加安全可靠的判定方法:instanceof 操作符
即使上面没有修正constructor属性,下面的结果依然是true.
console.log(p instanceof Person); //true
由于时间的问题,就不继续写下去了.下面有一个示例,根据这个示例我还画了一个图,有兴趣的可以花点时间看看
//定义Animal构造函数 function Animal() { } //定义Dog构造函数 function Dog() { } var a1 = new Animal(); Dog.prototype = a1; Dog.prototype.constructor = Dog; //手动修正constructor var d1 = new Dog(); console.log(d1.constructor); //Dog构造函数 console.log(Dog.prototype.constructor); //Dog构造函数 console.log(d1 instanceof Dog); //true console.log(d1 instanceof Animal); //true
有个注意点就是Object.prototype是由Object构造函数实例化出来的,同时Object.prototype是Object构造函数的原型对象,那么Object.prototype的原型__proto__不就是它自己吗?这样就无限循环了,所以系统默认把它的原型__proto__设置为null,好有个终点嘛!然后还有一个注意点就是,由于创建对象的过程都是通过new创建一个inobj,因此在js中,万物皆对象,所有的内置或自定义对象都继承自Object对象,几乎所有的对象都可以使用Object.prototype上面的属性和方法.
画的也不是很完整,constructor没画上去,感觉那样线就太多太乱了.不过细心钻研一下还是能懂的,如若有错,请不吝指正哈!
鄙人对constructor和prototype的总结的更多相关文章
- 分析js中的constructor 和prototype
在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要. 我们在定义函数的时候,函数定义的时候函 ...
- JavaScript——this、constructor、prototype
this this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window: 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用. 我们还可以使用a ...
- 深入分析js中的constructor 和prototype
在javascript的使用过程中,constructor 和prototype这两个概念是相当重要的,深入的理解这两个概念对理解js的一些核心概念非常的重要. 我们在定义函数的时候,函数定义的时候函 ...
- JS中的constructor与prototype
http://www.cnblogs.com/qiantuwuliang/archive/2011/01/08/1930548.html 在学习JS的面向对象过程中,一直对constructor与pr ...
- 关于JS中的constructor与prototype
======================================================================== 在学习JS的面向对象过程中,一直对constructo ...
- 【JavaScript】关于JS中的constructor与prototype
最初对js中 object.constructor 的认识: 在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下 ...
- 面向对象的程序设计(二)理解各种方法和属性typeof、instanceof、constructor、prototype、__proto__、isPrototypeOf、hasOwnProperty
//理解各种方法和属性typeof.instanceof.constructor.prototype.__proto__.isPrototypeOf.hasOwnProperty. //1.typeo ...
- 【转】JavaScript中的constructor与prototype
最初对js中 object.constructor 的认识: 在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下 ...
- 四,前端---constructor与prototype
这里对于constructor 和 prototype做一个简单的介绍,旨在让大家有一个简单的了解与认识 1:定义与用法 prototype:属性使您有能力向对象添加属性和方法. constructo ...
随机推荐
- [leetcode-442-Find All Duplicates in an Array]
Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others ...
- 【LeetCode】2. Two Sum
题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...
- 【Android Developers Training】 59. 管理图片存储
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 54. 打印自定义文档
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- CUDA零内存拷贝 疑问考证
今天思考了一下CUDA零内存拷贝的问题,感觉在即将设计的程序中会派上用场,于是就查了一下相关信息. 以下是一些有帮助的链接: cuda中的零拷贝用法--针对二维指针 cuda中的零拷贝用法--针对一维 ...
- pouchdb-find( pouchdb查询扩展插件 ,便于查询)
pouchdb-find pouchdb-find 环境搭建 下载lib bower install pouchdb-find 引入js <script src="pouchdb.js ...
- Win10安裝weblogic12C
一.系统环境 Win10系统 Jdk1.8 64位 二.安装Weblogic 第一步:用系统管理员身份打开CMD命令提示符,用CMD方式进入"fmw_12.1.3.0.0_wls. ...
- localStorage与location的用法
1.localStorage 是h5提供的客户端存储数据的新方法: 之前,这些都是由 cookie 完成的.但是 cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 coo ...
- webpack热更新问题和antd design字体图标库扩展
标题也不知道怎么写好,真是尴尬.不过话说回来,距离上一次写文快两个月了,最近有点忙,一直在开发新项目, 今天刚刚闲下来,项目准备提测.借这个功夫写点东西,把新项目上学到的一些好的干活分享一下,以便之后 ...
- tcp入门(唐唐的故事)
1,互联网的实现,分成好几层.每一层都有自己的功能,就像建筑物一样,每一层都靠下一层支持.把互联网分成五层,容易让人理解. 2,对这五层的理解(唐唐讲故事): 实体层:目的就是把计算机连接起来,用电气 ...