为什么特权方法和 public 方法之间存在区别?如何知道使用哪个?

Why is there a distinction between privileged and public methods? How to know which to use?

这里是演示代码:

var Foo = function(){
    var privateVar = "i am private";
    function privateFunc(){
        console.log(privateVar);
    }

    this.privilegedFunc = function(){
        privateFunc(); // can access

    }
};

Foo.prototype.publicFunc = function(){
    privateFunc(); // cannot access
};

var foo = new Foo();

foo.privilegedFunc(); // prints "i am private"
foo.publicFunc(); // Uncaught ReferenceError: privateFunc is not defined

它就像任何 OOP 语言一样(虽然没有可见性关键字),如果您需要在实例外部调用一个方法,public,否则,私有。

未绑定到 this 的函数无法在范围外访问,因为它们是在构造函数的范围内定义和声明的。

并且根据您的最新评论,有很多原因和场景表明您必须公开一个对象函数才能被其他对象使用,例如

根据您在此回答中的评论,让我们看看原型方法的一些优点。

通过使用原型,您可以更改方法并且更改将反映到共享同一原型的所有实例,如果没有原型,每个实例将拥有给定方法的自己的版本,因此您将拥有一个一个改。

另一个优点是性能,functions/methods在原型中声明的只创建一次,而没有原型,每次使用new关键字从构造函数实例化时,所有函数必须在构造函数范围内创建。

Why is there a distinction between privileged and public methods?

我假设您阅读了 Douglas Crockford 网站 (this page)。我还没有真正看到其他作者使用过这种区别。我没有做出那种区分,但我知道该函数可以访问构造函数闭包。

Why should I even bother with public methods, aren't privileged methods more natural? They feel more intuitive as they allow access to private methods and variables like in java.

它们的含义与 public 方法不同。

A) 它们由构造函数定义,因此它们可以访问构造函数范围。那是他们的特权。

B) 其原型不共享它们。

A表示每次调用构造函数时都会实例化该函数。当您使用原型时,它只是链接。

B表示它们是本质不同的函数。

obj1.privileged !== obj2.privileged

Is there a specific reason behind this or was this an error in the spec or am I missing something?

从我看到的地方看没有错误。这只是一个语言功能。

In what situation would you use a public method over a privileged method?

当您不需要访问构造函数内的任何闭包并希望利用原型链时。

重要的是要注意 "privileged" 和 "public" 方法之间的规范没有区别(事实上我认为规范根本不使用这些术语 - Douglas Crockford 使用),它们受完全相同的规则约束,其中最基本的规则是 function scope

注意:我会在我的回答中遵循你的术语,但我实际上建议不要这样做:你会发现人们更经常调用你的特权方法public,以及您的 public 方法原型方法。

在您的示例中,this.privilegedFunc 可以访问私有变量 privateFunc,因为它们是在同一范围内定义的 - 即 Foo 构造函数的范围。 privilegedFunc 将能够使用它对 privateFunc 的引用,即使是从 "outside" 调用时,通过语言的所谓闭包机制。

直接回答您的问题:

Why is there a distinction between privileged and public methods?

没有根本的区别。您在不同的范围内定义了两个函数,因此,它们可以引用不同的变量。

Why should I even bother with public methods, aren't privileged methods more natural?

自然是一个很主观的词。但是,如果您不想直接公开字段,则需要使用特权函数从外部操作它们。

They feel more intuitive as they allow access to private methods and variables like in java.

这种直觉仅基于熟悉程度:)难怪当您尝试将 Javascript 用作 Java 时,在两种语言中工作不同的部分似乎最不直观。这并不意味着您应该尝试模仿您将在其中任何一个中使用的样式,一些解决方案更适合 Javascript,一些更适合 Java.

Is there a specific reason behind this or was this an error in the spec or am I missing something?

(规范中出现如此根本性错误?天哪。)我不确定你所说的 "this" 是什么意思,但可见性的差异由函数作用域解释,见上文。

In what situation would you use a public method over a privileged method?

例如,如果您不需要通过闭包公开私有字段。另一个值得注意的区别是原型上的函数将在实例之间共享(即实际上是同一个函数实例),而私有和特权方法对于实例来说是唯一的,这会对内存占用产生影响。

您所谓的 "privileged" 方法不是语言语法的一部分。相反,它是一种设计模式。这可能是因为 javascript 实现了闭​​包(即使在外部函数返回后函数也能访问外部函数的范围)。

有一种理论认为所有实现闭包(甚至只是 first-class 函数)的语言都可以实现对象系统。一些函数式语言在将 OO 添加到语言时采用了这种方法:OO 功能不是语言语法的一部分,而是一个您可以使用(甚至自己编写)的库。这方面的主要例子之一是 Lisp 中的 CLOS(Common Lisp 对象系统)。它是一个无需修改语言语法即可向语言添加 OO 功能的库。

如您所见,使用闭包访问局部变量足以模拟私有变量的 "feel" 和 public 方法。这是闭包的一个特性——您可以创建自己的 OO 系统而不需要 OO 特性。

添加javascript中的OO系统是因为当时OO很重要。诚然,如果 Brendan Eich 没有将 OO 添加到 javascript,我们本可以使用纯 javascript 从头开发一个(或多个)OO 系统。事实上,在 2000 年代初期,人们对 javascript 中的原型对象系统感到不舒服,并开发了自己的 OO 系统来模仿他们习惯的系统。

在javascript中,OO系统没有私有方法或变量的概念。这是故意的。其他几种语言也有这种理念,即私有成员是 "mistake"。隐私是不好的做法的想法源于多年使用图书馆的经验,这些图书馆使您需要访问私有功能。对于鼓励开源或分发代码的语言,这不是什么大问题。您可以随时修改库代码以导出您想要的内容。但对于鼓励将库作为已编译二进制文件分发的语言来说,这是一个大问题。在创建 javascript 时,大多数 OO 语言都具有允许您将库作为编译二进制文件分发的功能。所以对隐私的概念有一点反对。

所以..你什么时候会使用闭包来模拟私有变量?当你真的需要像私有变量这样的东西时使用它。

不确定语义和命名约定,但就模式而言,我将在大多数情况下将其分解:

  1. privateFunc:
    每当我想将某些功能封装在一个函数中时,我都会使用这种类型的函数(无论是多次重复使用这个函数,还是仅仅因为它有一个合乎逻辑的理由这样做)我 不想 想暴露为 API,通常是因为它作为 API.
  2. 没有意义
  3. publicFunc:
    每当我想公开 API 时,我都会使用这种类型的函数,并且实现不需要任何 "closed"(如 closure)变量。基本上任何使用类型实例状态但不需要其他资源的东西。同样适用于直接从类型使用的 "static" 方法(例如与 Object.keys() 相同),但这不会在原型上声明,而是直接在类型上声明。
  4. priviledgedFunc:
    publicFunc 相同的用例,除了使用 helper,"closed" 变量是必需的或大大简化了实现。这种技术有一个缺点,因为这些方法是每个实例的属性,并且会导致运行时构造和分配的惩罚。

Why is there a distinction between privileged and public methods?

这是语言设计的结果,而不是驱动因素。我认为您实际上会做得很好,而不必为这种术语区别而烦恼。

Why should I even bother with public methods, aren't privileged methods more natural? They feel more intuitive as they allow access to private methods and variables like in java.

Is there a specific reason behind this or was this an error in the spec > or am I missing something?

In what situation would you use a public method over a privileged method?

在某些情况下,您会想到使用 public 方法来打扰自己:

  • 特权方法在每次创建对象时定义,而 public 方法在解析时定义一次。因此,如果您正在编写创建大量对象的内容,例如粒子系统,您可能需要使用 public 方法。
  • 您可以使用 public 方法是纯函数,无需实例化对象。

你的想法是错误的。您应该在这里考虑范围而不是访问级别(public/private/protected)Javascript 不是传统的面向对象的编程语言。

在您的示例中,"privateMethod" 仅局限于 "Foo" 函数,因此无法在函数外部访问。您的 "privilegedFunction" 附加到 "this",后者在 javascript 中是 "Foo" 函数的上下文。由于范围界定,您可以从 Foo 的 "instance" 访问它,如您的示例所示,它与访问级别无关。