关于prototype和constructor的思考

栏目: JavaScript · 发布时间: 5年前

内容简介:文章目录今天在看题主对这几个输出的结果比较疑惑,我也来分析一下这几个结果,看看自己对原型这部分知识掌握得如何。
  • Home
  • Programming >Front end >Javascript
  • 关于prototype和constructor的思考

文章目录

前言

今天在看 getset 语法的时候在知乎上看到一个提问,具体内容看下面的代码

function Dog(){
     this.tail = true;
        }
Dog.prototype.say = function(){return "Woof";}
var dog = new Dog();
dog.say(); // "Woof"
dog.constructor // Dog()
Dog.prototype = {
      paws:4
};
var newDog = new Dog();

newDog.constructor // ƒ Object() { [native code] }
typeof newDog.constructor.prototype.paws // "undefined"
typeof dog.constructor.prototype.paws // "number"

题主对这几个输出的结果比较疑惑,我也来分析一下这几个结果,看看自己对原型这部分知识掌握得如何。

分析图

要搞清楚这些对象之间的关系,我们来画一画这些对象的关系图

关于prototype和constructor的思考

图中不同类型的连线我已经用不同颜色标注出来,还是可以清楚的看出我们的各个对象之间的关系的。对象被我分成了三行,下面的分析中有时我会用第几行来说名对象的位置。

细节

问题 1

第一个问题 newDog.constructor ,我们先来看看 new 做了几件事

  1. 创建一个新的空对象
  2. 把新对象的 __proto__ 链接到构造函数的 prototype 对象(每一个函数都有一个 prototype 属性指向一个对象,该对象有一个 constructor 属性指向该函数)
  3. 将第一步创建的新的对象作为 this 的上下文
  4. 执行构造函数,如果构造函数没有返回值或者返回值不是一个对象,则返回 this

通过上面的步骤我们可以知道我们的 newDog 对象有一个 __proto__ 属性指向代码中的 {paws: 4} 这个对象,因为在代码中我们人为地将构造函数的 prototype 引用改变了,它现在指向了一个我们自定义的对象。需要注意的是,我们上面的步骤中说函数的 prototype 指向的对象有一个 constructor 属性指向函数,这种情况只限于引擎自动生成的 prototype 对象,对于我们自己创建的对象是没有该属性的。

可能有些同学有个疑问就是通过构造函数实例化的对象(比如代码中的 dognewDog )是否有 constructor 属性呢?答案是没有,虽然我们经常看到有这样的用法,但是其实访问的是原型链上的某个 prototype 对象中的 constructor 属性。那么我们代码中的 newDog.constructor 是哪一个呢?

从图中我们可以看出 newDog 对象的 __proto__ 指向了自定义的 prototype 对象(第二行第三个),我们的 newDog 和这个自定义的对象中都没有 constructor 的属性,那么引擎自然会沿着原型链继续寻找。自定义对象的构造函数是 Object 对象(也就是 ƒ Object() { [native code] } ,这是引擎底层函数,用 C++ 编写),是函数自然就有 prototype 属性,这个属性指向的对象也是 newDog 原型链上的一个对象,并且它有 constructor 属性,指向 Object 对象,结果出来了, newDog.constructor 就是 ƒ Object() { [native code] }

实例化对象中没有 constructor 属性很好验证,用 hasOwnProperty 方法即可。另外提一点就是引擎沿着原型链搜索属性, Object.prototype 是最后一环,这里就是原型链的终点, Object.prototype.__proto__ === null

问题 2

其实解决了问题 1 ,问题 2 也就迎刃而解了, typeof newDog.constructor.prototype.paws 等价于 Object.prototype.paws ,显然这个属性是不存在的。

问题 3

问题 3 的核心是当我们手动改变了构造函数的 prototype 指向,之前实例化的对象的 __proto__ 指向会改变吗?从图中的对象关系和代码运行结果我们可以得出否定的结论。 dog.__proto__ 此时依然指向 prototype 改变之前由引擎自动生成的对象,该对象中的 constructor 属性指向 Dog 构造函数, dog.constructor.prototype.paws 此时等价与 Dog.prototype.pawsDog.prototype 此时指向 {paws: 4} ,自然能够获取该属性。

总结

我们在构造函数原型上添加方法的时候尽量使用 Obj.prototype.xxx 的方式,而不要覆盖原型对象,这样会导致很多问题。即使在需要覆盖的时候,也要给新对象加上 constructor 属性。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web2.0策略指南

Web2.0策略指南

艾米 / 2009-3 / 39.00元

《Web2.0策略指南》是有关战略的。书中的示例关注的是Web 2.0的效率,而不是聚焦于技术。你将了解到这样一个事实:创建Web 210业务或将Web 2.0战略整合到现在业务中,意味着创建一个吸引人们前来访问的在线站点,让人们愿意到这里来共享他们的思想、见闻和行动。当人们通过Web走到一起时,结果可能远远大于各部分的和。随着传统的“口碑传诵”助推站点高速成长,客户本身就能够帮助建立站点。 ......一起来看看 《Web2.0策略指南》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具