【问题标题】:How to answer "how is prototypical inheritance in Javascript different than classical inheritance" in an interview?如何在面试中回答“Javascript 中的原型继承与经典继承有何不同”?
【发布时间】:2019-09-14 00:13:10
【问题描述】:

所以...我已经编程了 40 年,从机器语言到 C++ 再到 Javascript/Typescript。过去 10 年大量使用 Javascript。

当被问及原型继承与经典继承时,我似乎迷惑了。我一直在阅读文章,我一直在尝试排练,但是……老实说,我觉得我理解了这些概念,但不知道如何给面试官他们想要的东西。

C++ 是我对经典继承的参考框架(以及我也编写过的 Java 和 C#)。这里的继承是静态的——你从一个类中创建一个对象,就是这样。

Javascript 当然是动态的。您创建一个对象,该对象有一个原型,该原型本身也有一个原型,并且这些原型具有可以在运行时扩展的方法和属性,并且可用于共享该原型链的所有对象。

好的,很酷。

我明白这一切。但我似乎无法给面试官他们想听的内容。老实说,我使用 classextends 以及 Typescript 接口,虽然我知道它在底层是不同的,但我体验到的唯一真正实际的区别是你可以在运行时修改原型,比如 polyfills(实现缺少的功能) .

所以...帮助。我觉得知识都在我的脑海里,但我不知道如何正确地传达它。

【问题讨论】:

标签: javascript inheritance


【解决方案1】:

免责声明:我仍然是一名经验非常有限的本科生。

我在实现有限域代数时意识到了这两者之间的区别。我们有:

class Field{
    int p;
    Field (int p){
        this->p = p;
    }
};
class FieldElement: public Field{
    int x; 
    FieldElement(int x, int p) : Field(p){
        this->x = x;
    }
};

现在,每个字段元素都有自己的字段并存储有关该字段的所有信息(恰好在这里只是一个整数p)。想象一下,如果Field 类非常重,那么我们有很多FieldElement 类型的对象。每个物体都会携带其庞大的磁场。相反,javascript类型原型链可以被认为只是携带一个指向元素所属的Field对象的指针。

希望我能满意地回答您的问题。

【讨论】:

  • 我认为您提出的问题是正确的,但是...“非常重”是什么意思?您可以向 Field 类添加很多方法。但是在 JS 或 C++ 中,这不会增加 Field 对象实例的大小(假设该方法已添加到 JS 原型中)。假设您向 Field 类添加了很多成员数据。现在在 JS 或 C++ 中,Field 类的实例同样庞大。
  • “现在在 JS 或 C++ 中,Field 类的实例同样庞大” - 是的,Field 的实例同样庞大。但是 FieldElement 的实例不会。 (同样,我没有太多经验,在 JS 中更是如此)。在 JS 中,如果我们有 var a = {};和 var b = {"name": "Scott"};如果我们执行 Object.setPrototypeOf(a, b),我们可以访问 a.name,它会返回 Scott。如果我们现在执行 b["name"] = "Orwell",a.name 也会返回 "Orwell"。这意味着除了对 b 的引用之外,a 不存储任何内容。因此,即使 b 有很多成员,a 的大小也会保持不变。
  • 当然,但是a.name 不是'a' 的属性,而是a 原型的属性。它基本上是一个类实例字段(又名静态成员数据)——任何使用此原型的对象都将具有相同的“名称”字段。没错,'name' 没有添加 'a' 对象,但这意味着使用相同原型的不同实例不能有不同的 'name' 值。 IMO,这种模棱两可是有些人讨厌 JS 的原因。 ;) 在 TypeScript 中,您可以简单地编写 class A { static name: string; } 并使其明确。无论如何,我觉得这更像是语法上的差异。
猜你喜欢
  • 2013-11-07
  • 2015-10-12
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
  • 1970-01-01
  • 2015-11-13
  • 2016-07-30
  • 2010-09-28
相关资源
最近更新 更多