Префікс підкреслення для імен властивостей та методів у 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 був обраний sigil #?

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

Ця пропозиція досягла 3 етапу в липні 2017 року. З цього часу великі роздуми та тривалі дискусії щодо різних альтернатив. Врешті-решт, цей роздум та продовження залучення громад призвели до відновлення консенсусу щодо пропозиції у цьому сховищі. Виходячи з цього консенсусу, впровадження цієї пропозиції рухається вперед.

Дивіться https://caniuse.com/#feat=mdn-javascript_classes_private_class_fields


257

Це лише умовність. Мова Javascript не надає особливого значення ідентифікаторам, починаючи з символів підкреслення.

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


4
Так. Навіть якщо мова не "підтримує" це, це дійсно зручна умова.
— Juho Vepsäläinen

Серйозна проблема. jsfiddle.net/VmFSR Як ви бачите там, ім'я, створене значенням, доступне лише за допомогою префіксації нового значення, створеного, за допомогою якого _я б хотів знати, що відбувається !? чому це не this.nameзамість цього?
— Мухаммед Умер

1
@Muhammad Umer, я не впевнений, що я розумію твій коментар. console.log(someone._name = "Jean Dupont");працює також добре console.log(someone.name);, і він призначає і оцінює підкреслений член із властивістю. Як бачите , Theres не гарантується інкапсуляцією через підкреслення :)
— Frédéric Hamidi

3
За замовчуванням Visual Studio намагається допомогти вам це поважати. Двигун JavaScript IntelliSense показує вам "приватні" властивості зсередини об'єкта при використанні змінної "цей". Але, коли дзвонить ззовні, він приховує всі підкреслені атрибути.
— foxontherock

1
@Karuhanga він відповів на це ще в 2010 році - звичайно, все змінилося за 10 років
— Кенні Мейєр

99

JavaScript насправді підтримує інкапсуляцію за допомогою методу, який передбачає приховування членів у закриттях (Crockford). Однак, це іноді громіздко, і умовно-підкреслювальний конвент - це дуже хороша умова, яка використовується для речей, які є приватними, але які насправді не потрібно приховувати.


19
Вгору голосуйте за уточнення способів домогтися закриття, а голосування - за підкреслення - це хороша умова. Тому я не буду голосувати жодним чином :)
— Джейсон

3
Приховування членів у закриттях іноді може перешкоджати встановленню. Перевірте цю статтю: adequatelygood.com/2010/7/Writing-Testable-JavaScript
— Zach Lysobey

4
@Jason - Просто цікаво, чому ви вважаєте підкреслення поганою умовою?
— Тамас Пап

5
@TamasPap - Кілька причин, але тільки мій варіант: 1) Милиця змусити JS до стилю інших мов 2) Якщо вона доступна, вона буде використана. Підкреслення може засмічуватися і згортати зовнішній код. 3) Конфуз для нових програмістів JS.
— Джейсон

9
Навіть із закриттям, технічно все ж можливо отримати доступ до так званої "приватної" змінної. Конвенція, принаймні, дозволяє розробникам знати про це на свій страх і ризик (або щось подібне).
— Саринк

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.