为什么特权方法和公共方法之间存在区别?怎么知道使用哪个?

时间:2015-10-06 19:25:35

标签: javascript ecmascript-5

  • 为什么特权方法和公共方法有区别?

  • 为什么我甚至不打扰公共方法,没有特权 方法更自然?他们觉得更直观,因为他们允许访问 私有方法和变量,如java。

  • 这个背后是否有一个特定的原因,或者这是一个错误 spec (在那里领先一点!)或者我错过了什么?

  • 在什么情况下你会使用公共方法而不是特权方法?

这是演示的代码:

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

7 个答案:

答案 0 :(得分:3)

它就像任何OOP语言一样(尽管没有可见性关键字),如果你需要在实例之外调用一个方法,public,else,private。

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

根据您的最新评论,有许多原因和场景,您必须公开对象功能才能被其他对象使用,例如

根据你在这个答案中的评论,让我们看看原型方法的一些优点。

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

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

答案 1 :(得分:2)

重要的是要注意,“特权”和“公共”方法之间的规范没有区别(实际上我认为规范根本不使用这些术语 - 道格拉斯·克罗克福德),它们受到确切的控制相同的规则,其中最基本的是功能范围

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

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

直接回答您的问题:

  

为什么特权方法和公共方法之间有区别?

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

  

为什么我甚至不愿意使用公共方法,特权方法不是更自然吗?

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

  

他们感觉更直观,因为他们允许访问私有方法和变量,如java。

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

  

这背后是否存在特定原因,或者这是规范中的错误还是我遗漏了什么?

(规范中的这样一个基本错误?!上帝没有。)我不确定你对“this”的意思,但可见性的差异由功能范围解释,见上文。

  

在什么情况下你会使用公共方法而不是特权方法?

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

答案 2 :(得分:1)

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

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

正如您所发现的,使用闭包来访问局部变量可以很好地模拟私有变量和公共方法的“感觉”。这是闭包的一个特性 - 您可以创建自己的OO系统而无需OO功能。

javascript中的OO系统被添加,因为OO是一个大问题。不可否认,如果Brendan Eich没有在javascript中添加OO,我们可以使用纯javascript从头开始进化(或几个)OO系统。实际上,在21世纪初,人们对javascript中的原型对象系统不满意,并开发了自己的OO系统来模仿他们习惯的东西。

在javascript中,OO系统没有私有方法或变量的概念。这是故意的。其他几种语言也有这样一种理念,即私人成员是一个“错误”。隐私是不良做法的想法源于多年使用库的经验,这些库创建了您需要访问私有的功能。对于鼓励开源或分发代码不太大的语言。您始终可以修改库代码以导出所需内容。但对于鼓励将库分发为已编译二进制文件的语言而言,这是一个很大的问题。在创建javascript时,大多数OO语言都具有允许您将库分发为已编译二进制文件的功能。因此,对隐私概念的反对很小。

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

答案 3 :(得分:0)

  

为什么特权方法和公共方法之间有区别?

我假设你读过Douglas Crockford网站(this page)。这是我从未被其他作者看到的区别。我没有做出这种区分,但我知道该函数可以访问构造函数闭包。

  

为什么我甚至不愿意使用公共方法,没有特权方法更自然?他们感觉更直观,因为他们允许访问私有方法和变量,如java。

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

A)它们由构造函数定义,因此,它们可以访问构造函数作用域。这是他们的特权。

B)它们的原型并没有共享。

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

B 意味着它们本质上是不同的功能。

obj1.privileged !== obj2.privileged
  

这背后是否存在特定原因,或者这是规范中的错误还是我遗漏了什么?

我看到的地方没有错误。它只是一种语言功能。

  

在什么情况下你会使用公共方法而不是特权方法?

如果您不需要访问构造函数中的任何闭包,并希望利用原型链。

答案 4 :(得分:0)

不确定语义和命名约定,但就模式而言,这是我在大多数情况下如何解决这个问题:

  1. privateFunc
    每当我想在功能中封装一些功能时(无论是多次重复使用此功能,还是仅仅因为它有合理的理由),我都会使用这种类型的功能,我 don& #39; t 希望作为API公开,通常是因为它作为API没有意义。
  2. publicFunc
    我想在公开API时使用这种类型的函数,并且实现并不需要任何"关闭" (如closure)变量。基本上任何使用该类型实例的状态但不需要其他资源的东西。也适用于"静态"直接从类型中使用的方法(例如,与Object.keys()相同),但这不会在原型上声明,而是直接在类型上声明。
  3. priviledgedFunc:
    publicFunc 相同的用例除了使用帮助器,"关闭"变量是必需的或大大简化了实现。这种技术的缺点在于这些方法是每个实例的属性,并且构造和分配会产生运行时惩罚。

答案 5 :(得分:0)

  

为什么特权方法和公共方法之间有区别?

这是语言设计的结果,而不是驱动因素。实际上你可以做得很好,而不必担心我认为这个术语的区别。

  

为什么我要打扰公共方法,没有特权   方法更自然?他们觉得更直观,因为他们允许访问   私有方法和变量,如java。

     

这背后是否存在具体原因,或者这是规范中的错误>或者我错过了什么?

     

在什么情况下你会使用公共方法而不是特权方法?

在某些情况下,您可能会想到自己想到的公共方法:

  • 每次创建对象时都会定义特权方法,而在解析时定义公共方法一次。因此,如果您正在编写创建存储桶负载的对象,例如粒子系统,你可能想使用公共方法。
  • 您可以使用公共方法是纯函数而无需实例化对象。

答案 6 :(得分:0)

你正在以错误的方式思考这个问题。您应该考虑范围而不是访问级别(公共/私有/受保护)Javascript不是传统的面向对象编程语言。

在您的示例中,“privateMethod”简单地限定为“Foo”函数,因此无法在函数外部访问。您的“privilegedFunction”附加到“this”,它在javascript中是“Foo”函数的上下文。您可以从示例中显示的Foo“实例”访问它,因为它具有作用域,并且与访问级别无关。