javascript - ECMAScript/JavaScript - 继承和新运算符

标签 javascript oop inheritance ecmascript-5

我目前正在学习 JavaScript/ECMAScript 编程,并且正在阅读“Professional JavaScript for Web Developers, 3rd Edition”一书。我很喜欢这本书,同时我在 Internet 上寻找描述同一主题的 Material 的支持。就像所有从一种语言出来学习另一种语言的 OO 程序员一样,我遇到了困难。我目前在第 6 章学习继承(PAG.201、202 - 如果有人有这本书,并且想看这部分),我很困惑,注意力不集中。

我很了解这个主题背后的机制......但我不明白为什么。例如,本书作者展示了以下案例(部分行略微调整了注释和分隔):

// SUPERTYPE
function SuperType()
{
    this.property = true;
}

SuperType.prototype.getSuperValue = function()
{
    return this.property;
};

// SUBTYPE
function SubType()
{
    this.subproperty = false;
}

SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function ()
{
    return this.subproperty;
};

// TEST
var instance = new SubType();
alert(instance.getSuperValue());    //true

据我了解,在 ECMAScript 中,类型的实例继承在其原型(prototype)上配置的属性和方法,并且通过原型(prototype)属性继承是可能的。因此,将一种类型的原型(prototype)更改为另一种类型将导致行为和属性被重用。

让我不知所措的是,将类型 A 的新实例分配为类型 B 的原型(prototype),据了解 B 可能有实例,A 也可能有实例(不是说这应该发生,但是允许发生)。

那是什么意思?好吧……想象一下,我有一个名为“Vehicle”的父类(super class)型和一个名为“Car”的子类型。如果我使用“Vehicle”的实例作为“Car”的父类(super class)型(毕竟,子类型不知道他的父类(super class)型,而只知道它的原型(prototype) - 正如书中的 PAG.185 所说),我正在创造一些完全抽象作为具体的东西。另外,我使用的可能只是抽象父类(super class)型(?)的许多可能实例之一,因为没有什么能阻止父类(super class)型将来在这种类型的代码中拥有更多自身实例,添加更多代码/方法/属性/ETC。

我真正的问题是……这就是它吗?亲切...开发人员应该担心关联正确的实例,而且只有其中一个?

另外,我对原型(prototype)链也有一些疑惑。例如,我知道当一个属性/方法被请求/使用时,首先在对象中寻找它,然后是它的原型(prototype)(如果没有找到)。这个故事中的上下文明显发生了什么?我的意思是,只在对象的原型(prototype)链中进行搜索而不运行任何上下文?我之前读到过,当使用一个变量时,它会在上下文堆栈中查找。 上下文栈和原型(prototype)链有什么关系?

我知道我问这个问题可能有点无聊/烦人,但是谁能用简单而详细的方式向我解释一下,好吗?

预先感谢您的耐心、时间和关注。

编辑

有些人真的不明白我在想什么,我很抱歉。以下是所有内容的摘要:

创建 A 的新实例,其中 A 是 B 的父类(super class)型,这是否允许且可能,即使 A 遵循某种抽象?如果允许这样做,其后果是什么?当实例使用某些东西(属性或方法)时,上下文堆栈在哪里?

总结更多:虽然我在问问题,但要意识到我在问继承的含义。就是这样……

最佳答案

JavaScript 有两个重要的概念,您似乎在此处触及,闭包/作用域原型(prototype)设计/继承。它们的工作方式与大多数其他现代语言不同,因此可能会给从更经典的语言过渡到 JavaScript 的人们造成困惑。

原型(prototype)

基本上 JavaScript 中的所有内容都是一个对象。在 JavaScript 中,对象 有一个叫做原型(prototype) 的东西,它是对可能具有继承属性的父 对象 的引用由后代对象原型(prototype)也可能是null ,它发生在原型(prototype)链的顶端。

原型(prototype)中通常的结构是让更具体的对象继承更抽象的对象,一直回到Object.prototype。或 null

当查找一个对象的属性时,您从该对象开始,如果它没有该属性,您就在原型(prototype)链中向上一级并再次查找。如果你到达 null那么就没有这个属性了。
这也意味着您可以通过在原型(prototype)链下游设置同名属性来隐藏继承的属性。

function Foo() {
}
Foo.prototype = {};
Foo.prototype.foobar = 'foo';

function Bar() {
    // if required
    // Foo.call(this);
}
Bar.prototype = Object.create(Foo.prototype); // inhert
Bar.prototype.foobar = 'bar';

var baz = new Bar();
baz.foobar; // "bar"
baz instanceof Bar; // true
baz instanceof Foo; // true

原型(prototype)可以是任何对象,因此使用另一个对象的实例来设置原型(prototype)链并没有什么违法的,但是如果您试图扩展或创建子类型,这通常被认为是不好的做法

关闭

这就是查找变量和标识符的方式。它与原型(prototype) 无关,完全取决于定义的地方。标识符“被困”在一个范围内,其他范围可以“关闭”它们。

JavaScript 中,作用域的主要提供者是函数

var a = 1;
function foo() {
    var b = 2;
    // foo can see `a` and `b` as well as `fizz`, `foo`, `bar` and `baz`
    function bar() {
        var c = 3;
        // bar can see `a`, `b` and `c` as well as `fizz`, `foo`, `bar` and `baz`
    }
    function baz() {
        var d = 4;
        // baz can see `a`, `b` and `d` as well as `fizz`, `foo`, `bar` and `baz`
    }
}
function fizz() {
    var e = 1;
    // fizz can see `a` and `e` as well as `fizz` and `foo`
}

但是,如果您要在 foo 上创建属性试图查找 bar ,你会得到一个ReferenceError(或undefined),同样如果你试图继承foo

foo.meth = function () {return bar;};
foo.meth(); // undefined

function Hello() {
    this.bar; // undefined
}
Hello.prototype = foo;
(new Hello()).bar; // undefined

访问bar的唯一途径是有foo为你做,例如通过 return bar;foo 的末尾

如果barfoo 返回,然后是变量 foo可以在 bar 中看到 “继续” .如果 bar 中没有 eval 风格的代码,智能垃圾收集器可能仍会清理无法访问的垃圾。 .

正如函数内的变量不会在多个调用之间共享一样,这些变量也不会在多个调用之间共享 foo调用,但是它们将在多个 bar 之间共享调用

function foo() {
    var a = 0,
        b = -1;
    function bar() {
        return ++a;
    }
    return bar; // pass `bar` out of `foo`
}
var fn1 = foo(), fn2 = foo();
// by this point, the `b` created by `foo()` may already be cleaned up
fn1(); // 1
fn1(); // 2
fn2(); // 1, it's a different `a` to the `a` in `fn1`
fn2(); // 2

关于javascript - ECMAScript/JavaScript - 继承和新运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29292471/

相关文章:

javascript - React + Flux - 如何避免全局变量

javascript - document.querySelectorAll 与 div.style 一起不起作用

c# - 我什么时候需要在 C# 中调用 base()?

c++ - 运算符 '...' 具有覆盖说明符但不覆盖基类成员

javascript - 按字母顺序对对象列表进行排序

flutter - 在 DART 中 - toList() 方法不会将 int 的 Iterable 转换为列表,但是当它应用于 print() 内部时,它可以正常工作。为什么?

javascript - 理解 JavaScript 中的原型(prototype)

c# - IoC、SRP 和组合——我是否创建了太多接口(interface)?

java - 如何在抽象父类(super class)中使用子类的方法

javascript - JSON.stringify 或如何将二进制数据序列化为 base64 编码的 JSON?