Подчеркнуть префикс для имен свойств и методов в 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.


Ответы:


33

Добро пожаловать в 2019!

Похоже, было предложено расширить синтаксис класса, чтобы #префиксная переменная была закрытой. Chrome 74 поставляется с этой поддержкой.

_ Имена префиксных переменных считаются закрытыми по соглашению, но по-прежнему общедоступны.

Этот синтаксис пытается быть кратким и интуитивно понятным, хотя он довольно отличается от других языков программирования.

Почему был выбран символ # среди всех кодовых точек Unicode?

  • @ был первым фаворитом, но его взяли декораторы. TC39 рассматривал возможность обмена декораторами и частными государственными символами, но комитет решил отложить существующее использование пользователей транспорта.
  • _ может вызвать проблемы совместимости с существующим кодом JavaScript, что позволяет _ в начале идентификатора или (открытого) имени свойства в течение длительного времени.

Это предложение достигло стадии 3 в июле 2017 года. С тех пор было много размышлений и продолжительных дискуссий о различных альтернативах. В конце концов, этот мыслительный процесс и продолжающаяся вовлеченность сообщества привели к обновленному консенсусу по предложению в этом хранилище. Исходя из этого консенсуса, реализации этого предложения продвигаются вперед.

Смотрите https://caniuse.com/#feat=mdn-javascript_classes_private_class_fields


257

Это всего лишь соглашение. Язык Javascript не придает особого значения идентификаторам, начинающимся с символов подчеркивания.

Тем не менее, это довольно полезное соглашение для языка, который не поддерживает инкапсуляцию из коробки. Хотя нет никакого способа предотвратить злоупотребление реализациями ваших классов, по крайней мере, это проясняет ваши намерения и в первую очередь документирует такое поведение как неправильное .


4
Ага. Даже если язык не «поддерживает» его, это действительно удобное соглашение.
Юхо Вепсяляйнен

Серьезный проб. jsfiddle.net/VmFSR Как вы можете видеть, имя созданного значения доступно только с помощью префикса нового созданного значения, с помощью которого _я хотел бы знать, что происходит !? почему это не this.nameвместо этого?
Мухаммед Умер

1
@ Мухаммед Умер, я не уверен, что понимаю ваш комментарий. console.log(someone._name = "Jean Dupont");работает так же, как console.log(someone.name);и он, и назначает и оценивает элемент с префиксом подчеркивания за свойством. Как видите , theres нет гарантированной инкапсуляции через подчеркивание :)
Frédéric Hamidi

3
По умолчанию Visual Studio пытается помочь вам уважать это. Движок IntelliSense javascript показывает вам «приватные» свойства изнутри объекта при использовании переменной «this». Но при вызове извне он скрывает все подчеркнутые атрибуты.
foxontherock

1
@Karuhanga он ответил на это еще в 2010 году - конечно, все изменилось за 10 лет
Кенни Мейер

99

JavaScript на самом деле поддерживает инкапсуляцию с помощью метода, который включает в себя сокрытие членов в замыканиях (Крокфорд). Тем не менее, это иногда громоздко, и соглашение о подчеркивании является довольно хорошим соглашением для вещей, которые являются частными, но которые вам на самом деле не нужно скрывать.


19
Голосование за разъяснение того, как добиться закрытия, голосование за подчеркивание - хорошая договоренность. Так что я не буду голосовать в любом случае :)
Джейсон

3
Сокрытие членов в замыканиях может иногда препятствовать проверке. Проверьте эту статью: адекватно
good.com/2010/7/Writing-Testable-JavaScript

4
@ Джейсон - Просто любопытно, почему ты считаешь это плохим условием?
Тамас Пап

5
@TamasPap - несколько причин, но только мой выбор: 1) костыль, чтобы заставить JS перейти в стиль других языков 2) если он доступен, он будет использоваться. Подчеркивание может засорять и извилистый внешний код. 3) Путать с новыми программистами JS.
Джейсон

9
Даже с закрытием технически возможно получить доступ к так называемой «закрытой» переменной. _Convention по крайней мере позволяет разработчикам делать это на свой страх и риск (или что-то в этом роде).
Саринк

14

JSDoc 3 позволяет вам аннотировать ваши функции с помощью @access private(ранее @privateтега), который также полезен для передачи ваших намерений другим разработчикам - http://usejsdoc.org/tags-access.html


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

Вы экспортируете класс и вызываете внутреннюю функцию за пределами функции. Эти функции являются частными.
Николас Зозол
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.