资讯专栏INFORMATION COLUMN

js实现继承的方法中为何总是要修正constructor方法的指向呢?

fancyLuo / 1867人阅读

摘要:由于属性是可以变更的,所以未必真的指向对象的构造函数,只是一个提示。不过,从编程习惯上,我们应该尽量让对象的指向其构造函数,以维持这个惯例。

问题引入

最近看了许多关于js继承实现的相关文章,许多实现方式中都会存在这么一行代码:

A.prototype.constructor = A

于是感到好奇,这行代码的实际意义是什么?如果没有的话,还能达到继承的目的吗?

前置知识

为了熟悉javascript中与原型相关的几个基本概念,可以参看这篇文章JavaScript深入之从原型到原型链,作者写的十分简明易懂。

读了文章以后可以知道,在方法(构造函数)上存在一个叫做prototype的属性,这个属性是一个对象;方法结合new关键字可以生成实例,生成的每一份实例上都会有一个叫做__proto__的属性,这个属性也是指向生成该实例的方法上的prototype属性;原型对象(即prototype这个对象)上也存在一个特别的属性,即constructor,这个属性指向的方法本身。

回到问题本身

我们先来回答第二个问题:如果没有这行代码,还能到达继承的目的吗?
看一个常见的组合继承的实现方式,代码如下:

function Animal(name) {
    this.name = name || "";
    console.log("Animal called.");
}
Animal.prototype.showName = function() {
    console.log("Name is: ", this.name);
}
function Cat(name, age) {
    Animal.call(this, name);
    this.age = age || 1;
    console.log("Cat called.");
}
Cat.prototype = new Animal();
// Cat.prototype.constructor = Cat;    // 注释掉修正constructor方法的指向的这一行
Cat.prototype.showAge = function() {
    console.log("Age is: ", this.age);
}

var cat = new Cat("meow", 3);
console.log(cat.name);    // meow
cat.showName();          // Name is: meow
console.log(cat.age);    // 3
cat.showAge();           // Age is: 3

可以看到,继承的效果依然是达到了。所以,我觉得答案应该是能。

我们再来看第一个问题,注释掉的这行代码的意义是什么呢?为什么大部分的实现方式中都建议我们修正这个constructor的指向呢?
网上搜索后找到这篇文章: 为什么要做A.prototype.constructor=A这样的修正?, 并由此进一步的查看了Stack Overflow上的这篇问答: What it the significance of the Javascript constructor property?
所以,最重要的修正意义应该还是针对显示调用的时候。
接着刚刚的代码来看:

cat.__proto__.constructor  // 这个属性指向的应该是 Animal 构造函数,如果我们之前修正了constructor的指向的话,那么这里才会真的指向到 Cat 的构造函数

// 假设我们想要构造一个新的实例cat2,并且我们不知道对应的构造函数的名称是什么,不过好在我们刚刚已经有一个实例cat了(好吧,我知道这种假设比较2 -_-|||)
var cat2 = new cat.__proto__.constructor();  // Animal called (这里只有Animal的构造函数被调用了)
cat2.age;    // undefined  (因为在Animal构造函数中不存在age属性)

好吧,我承认这种场景比较少见。但是,万一有呢?所以我的建议是,我们应该保留这种修正constructor的写法。

后记

在知乎的一篇问答中看到一种说法

constructor其实没有什么用处,只是JavaScript语言设计的历史遗留物。由于constructor属性是可以变更的,所以未必真的指向对象的构造函数,只是一个提示。不过,从编程习惯上,我们应该尽量让对象的constructor指向其构造函数,以维持这个惯例。

作者:贺师俊
链接:https://www.zhihu.com/questio...
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考文章

JavaScript深入之从原型到原型链

为什么要做A.prototype.constructor=A这样的修正?

What it the significance of the Javascript constructor property?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97020.html

相关文章

  • js原型和继承

    摘要:举例说明组合继承组合继承利用原型链借用构造函数的模式解决了原型链继承和类式继承的问题。示例组合式继承是比较常用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。 对js原型和继承的理解一直处于不懂-懂-不懂-懂-不懂。。。的无限循环之中,本来打算只是简单总结下js继承方式,可看了些网上的资料后,发现又不懂继承了。。。这篇文章只...

    Hujiawei 评论0 收藏0
  • new 操作符到底做了什么?

    摘要:原文相信很多才接触前端的小伙伴甚至工作几年的前端小伙伴对这个操作符的了解还停留在一知半解的地步,比较模糊。 原文:http://blog.xieyangogo.cn/201... 相信很多才接触前端的小伙伴甚至工作几年的前端小伙伴对new这个操作符的了解还停留在一知半解的地步,比较模糊。就比如前不久接触到一个入职两年的前端小伙伴,他告诉我new是用来创建对象的,无可厚非,可能很多人都...

    _ivan 评论0 收藏0
  • ECMAScript 6入门类继承笔记

    类继承 看类继承前,先回顾构造函数怎么实现对象的继承的 function F() { this.a = 1; } function Son() { F.call(this); } function inherit(S, F) { S.protot...

    _DangJin 评论0 收藏0
  • JavaScript面向对象

    摘要:构造函数的两个特征函数内部使用了,指向所要生成的对象实例。将一个空对象的指向构造函数的属性,这个对象就是要返回的实例对象。用面向对象开发时,把要生成的实例对象的特有属性放到构造函数内,把共有的方法放到构造函数的里面。 JS中面向对象的概念 面向对象OOP是一种组织代码结构、实现功能过程的思维方式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的...

    Eirunye 评论0 收藏0
  • ES5/ES6 继承

    摘要:原型链构造函数原型实例的关系每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例有一个指向原型对象的指针构造函数原型对象构造函数构造函数操作符实例对象构造函数实例对象原型对象如果试 原型链 构造函数/原型/实例 的关系 每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例有一个指向原型对象的指针 构造函数 --(prototype)-->...

    libin19890520 评论0 收藏0

发表评论

0条评论

fancyLuo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<