JavaScript中属性和方法名称的下划线前缀


241

JavaScript中的下划线前缀仅是约定,例如Python私有类方法中的约定吗?

从2.7 Python文档中:

Python中不存在只能从对象内部访问的“私有”实例变量。但是,大多数Python代码遵循一个约定:以下划线开头的名称(例如_spam)应被视为API的非公开部分(无论是函数,方法还是数据成员) 。

这也适用于JavaScript吗?

以下面的JavaScript代码为例:

function AltTabPopup() {
    this._init();
}

AltTabPopup.prototype = {
    _init : function() {
        ...
    }
}

另外,使用带下划线的前缀变量。

    ...
    this._currentApp = 0;
    this._currentWindow = -1;
    this._thumbnailTimeoutId = 0;
    this._motionTimeoutId = 0;
    ...

只有约定?还是在下划线前缀后面?


我承认我的问题与这个问题非常相似,但是对于JavaScript中的下划线前缀的重要性,它并没有使人更聪明。


Answers:


33

欢迎来到2019!

似乎提出了扩展类语法以允许带#前缀的变量为私有的提议。Chrome 74 附带此支持。

_ 前缀变量名按照惯例被认为是私有的,但仍然是公共的。

尽管它与其他编程语言有很大不同,但该语法试图既简洁又直观。

为什么在所有Unicode代码点中选择标记#?

  • @是最初的最爱,但被装饰者采用。TC39考虑过更换装饰器和私人国家的信号灯,但是委员会决定推迟使用转译器用户的现有用法。
  • _会导致与现有JavaScript代码的兼容性问题,这很长时间以来一直允许_以标识符或(公共)属性名称开头。

该提案于2017年7月进入第三阶段。自那时以来,人们对各种替代方案进行了广泛的思考和冗长的讨论。最后,这种思考过程和社区的持续参与导致对该存储库中的提案重新达成共识。基于该共识,有关此提案的实施正在向前推进。

参见https://caniuse.com/#feat=mdn-javascript_classes_private_class_fields


257

那只是一个约定。Java语言对以下划线字符开头的标识符没有任何特殊含义。

这就是说,它是不支持语言相当有用的约定封装的开箱。尽管没有办法防止某人滥用您的类的实现,但至少它确实阐明了您的意图,并首先记录了此类错误行为。


4
对。即使该语言不“支持”它,这也是一个非常方便的约定。
JuhoVepsäläinen2010年

严重的概率。jsfiddle.net/VmFSR如您所见,只能通过在新值加上前缀的情况下访问创建值的名称,使用_我想知道正在发生的事情!为什么this.name不是呢?
穆罕默德·乌默

1
@Muhammad Umer,我不确定我是否理解您的评论。和console.log(someone._name = "Jean Dupont");一样好用console.log(someone.name);,并且它既分配和评估属性后面的带下划线前缀的成员。正如你所看到的,孤单是通过下划线:)没有保证的封装
弗雷德里克·哈米迪

3
默认情况下,Visual Studio会尝试帮助您尊重这一点。当使用“ this”变量时,javascript IntelliSense引擎会从对象内部向您显示“私有”属性。但是,当从外部调用时,它将隐藏所有强调的属性。
foxont​​herock

1
@Karuhanga他回答了这个早在2010年-当然事情已经10年改变
肯尼迈耶

99

JavaScript实际上确实通过一种将隐藏成员隐藏在闭包中的方法来支持封装(Crockford)。就是说,有时这很麻烦,下划线约定是一种非常好的约定,可用于某种私有的事情,但实际上您不需要隐藏。


19
投票赞成澄清如何实现关闭,而投票赞成说下划线是很好的惯例。所以我不会投票:)
Jason

3
将构件隐藏在封闭物中有时会阻碍可测试性。看看这篇文章:adequatelygood.com/2010/7/Writing-Testable-JavaScript
扎克Lysobey

4
@Jason-很好奇,为什么您认为下划线是不好的约定?
陶巴氏

5
@TamasPap-一些原因,但仅由我选择:1)强制将JS转换为其他语言风格的拐杖2)如果可访问,将使用它。下划线可能会使外部代码乱七八糟。3)使新的JS程序员感到困惑。
杰森

9
即使关闭了,在技术上仍然可以访问所谓的“私有”变量。_convention至少会让开发人员知道这样做的后果,后果自负(或类似的风险)。
sarink 2013年


10

“仅是约定?下划线前缀后面还有其他内容吗?”

除了隐私约定,我还想帮助人们意识到下划线前缀也用于依赖于独立参数的参数,特别是在URI锚定映射中。从属键始终指向地图。

示例(来自 https://github.com/mmikowski/urianchor):

$.uriAnchor.setAnchor({
  page   : 'profile',
  _page  : {
    uname   : 'wendy',
    online  : 'today'
  }
});

浏览器搜索字段上的URI锚更改为:

\#!page=profile:uname,wendy|online,today

这是用于基于哈希更改来驱动应用程序状态的约定。


8

import/export现在正在使用ES6。_如果我的大多数函数都已导出,我仍然倾向于为未导出的函数添加前缀。

如果仅导出一个类(例如在角度项目中),则完全不需要。

export class MyOpenClass{

    open(){
         doStuff()
         this._privateStuff()
         return close();
    }

    _privateStuff() { /* _ only as a convention */} 

}

function close(){ /*... this is really private... */ }

我认为导入/导出不以任何方式支持私有类方法。我的意思是,它确实支持类级别的类似功能,但是不提供隐藏所包含方法的功能。(即所有包含的方法总是公开的)
bvdb '18

您导出类,然后内部函数在函数外部调用。这些功能是私有的。
尼古拉斯·佐佐
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.