为什么 class 方法不能调用其他 class 方法或它们自己?

Why can't class methods call other class methods or themselves?

我很好奇为什么方法不能在javascript中调用其他方法或它们自己。例如,这会产生一个引用错误,指出 add is not defined.

class sum {
  add(x, amt) {
    if(amt == 0) return x
    return add(x+1, amt-1)
  }
}
summer = new sum()
console.log(summer.add(5,5))

您必须改用 this.add()。

现在我知道这些方法被转换为原型上的函数,但我不明白这如何解释我指出的这个限制?

这不是一个原因,当 add 被定义时,它可以引用自身或其他带有闭包捕获的方法。

为什么会这样?

@briosheje 发表评论时,我正在说明这个缺点:

function add() {
   console.log('called the wrong add!');
}

class sum {
  add(x, amt) {
    if(amt == 0) return x
    return add(x+1, amt-1)
  }
}
summer = new sum()
console.log(summer.add(5,5))

我会尝试使其"slightly"更理论化,而不会深入研究文档等。

您的问题的主要答案可以通过将您的代码转换为普通代码来找到 javascript。为此,您可以使用 babel online 或 typescript online playground。 无论哪种情况,转译后的代码都将如下所示:

"use strict";
var sum = /** @class */ (function () {
    function sum() {
    }
    sum.prototype.add = function (x, amt) {
        if (amt == 0)
            return x;
        return add(x + 1, amt - 1);
    };
    return sum;
}());
var summer = new sum();
console.log(summer.add(5, 5));

如你所见,add方法属于sum原型,是一个函数。因此,您可以猜测在 add 范围内访问 add 不能 隐式导致调用 sum.prototype.add 函数。

不同的是,如果您查看正确的代码:

class sum {
  add(x, amt) {
    if(amt == 0) return x
    return this.add(x+1, amt-1)
  }
}
var summer = new sum()
console.log(summer.add(5,5))

您将看到转译后的代码将调用 this 方法:

"use strict";
var sum = /** @class */ (function () {
    function sum() {
    }
    sum.prototype.add = function (x, amt) {
        if (amt == 0)
            return x;
        return this.add(x + 1, amt - 1);
    };
    return sum;
}());
var summer = new sum();
console.log(summer.add(5, 5));

这并不是模棱两可的问题,而是在javascript中允许这样的调用,因为add方法从全局范围隐式可用。能够访问函数作用域中的全局作用域(因为请记住,无论发生什么,javascript 中的 class 总是 转译为函数)允许继承函数的标准行为,即有权访问其父级、拥有自己的作用域并授予对全局作用域的访问权限。

一点好奇心:如果您实际上可以使用 add 访问 this.add,您将无法使用 undefined,因为它是一个 全局变量,因此您将无法访问和使用它,因为它隐式为 this.undefined.

所以,再一次,不是歧义,而是javascript函数如何工作。

从根本上讲,Javascript 中的 OOP 与 和其他语言非常不同。 "classes" 实际上并没有很强的概念。 classic OOP 概念,如 classes 和 Javascript 中的实例并不是真正来自 "classes",而是来自 属性 查找和 thisnew 关键字。其他一切都只是函数、对象和属性——其中一些是 "special",比如 prototype.

例如你可以 assemble 一个 "class" 这样的:

function Foo() {
    this.bar = 42;
}

function baz() {
    return this.bar;
}

Foo.prototype.baz = baz;

let foo = new Foo;
console.log(foo.baz());

这里没有真正的凝聚力,baz 本质上不属于任何 class,但 assembled 像这样他们表现得像一个。而 class 语法只是此机制的薄薄一层。因此,如果您在 函数 中编写 add,它会遵循变量范围规则并会在周围的某个范围内查找变量,它不会在原型上找到方法.