Prefiks podkreślenia dla nazw właściwości i metod w JavaScript

241

Czy prefiks podkreślenia w JavaScript jest tylko konwencją, jak na przykład w metodach klasy prywatnej Python?

Z dokumentacji języka Python 2.7:

„Prywatne” zmienne instancji, do których dostęp jest możliwy tylko z wnętrza obiektu, nie istnieją w Pythonie. Istnieje jednak konwencja, po której następuje większość kodu w języku Python: nazwa poprzedzona znakiem podkreślenia (np. _Spam) powinna być traktowana jako niepubliczna część interfejsu API (niezależnie od tego, czy jest to funkcja, metoda czy element danych) .

Czy dotyczy to również JavaScript?

Weźmy na przykład ten kod JavaScript:

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

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

Wykorzystywane są również zmienne z prefiksem podkreślenia.

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

Tylko konwencje? A może kryje się za tym prefiks?


Przyznaję, że moje pytanie jest dość podobne do tego pytania , ale nie uczyniło to mądrzejszego o znaczeniu prefiksu podkreślenia w JavaScript.

Kenny Meyer
źródło
Zobacz także stackoverflow.com/questions/17359885/…
Jon Onstott

Odpowiedzi:

33

Witamy w 2019 roku!

Wydaje się, że zaakceptowano propozycję rozszerzenia składni klasy, aby pozwolić, aby #zmienna z prefiksem była prywatna. Chrome 74 jest dostarczany z tym wsparciem.

_ Prefiksowane nazwy zmiennych są z reguły uważane za prywatne, ale nadal są publiczne.

Ta składnia stara się być zwięzła i intuicyjna, chociaż różni się raczej od innych języków programowania.

Dlaczego sigil # został wybrany spośród wszystkich punktów kodu Unicode?

  • @ był początkowym ulubieńcem, ale został wzięty przez dekoratorów. TC39 zastanawiał się nad wymianą dekoratorów i pieczęci państwowych, ale komitet postanowił odroczyć się do obecnego wykorzystania użytkowników transpilerów.
  • _ spowodowałoby problemy z kompatybilnością z istniejącym kodem JavaScript, co pozwoliło _ na początku identyfikatora lub (publicznej) nazwy właściwości przez długi czas.

Ta propozycja osiągnęła etap 3 w lipcu 2017 r. Od tego czasu trwa wiele przemyśleń i długa dyskusja na temat różnych alternatyw. Ostatecznie ten proces myślowy i ciągłe zaangażowanie społeczności doprowadziły do ​​odnowienia konsensusu w sprawie wniosku w tym repozytorium. W oparciu o ten konsensus wdrażanie tego wniosku jest kontynuowane.

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

Karuhanga
źródło
257

To tylko konwencja. Język JavaScript nie nadaje żadnego specjalnego znaczenia identyfikatorom rozpoczynającym się od znaków podkreślenia.

To powiedziawszy, jest to dość przydatna konwencja dla języka, który nie obsługuje enkapsulacji po wyjęciu z pudełka. Chociaż nie ma sposobu, aby zapobiec nadużywaniu implementacji twoich klas, przynajmniej wyjaśnia twoje zamiary i przede wszystkim dokumentuje takie zachowanie jako niewłaściwe .

Frédéric Hamidi
źródło
4
Tak. Nawet jeśli język go nie „obsługuje”, jest to naprawdę przydatna konwencja.
Juho Vepsäläinen,
Poważny problem. jsfiddle.net/VmFSR Jak widać, nazwa utworzona wartość jest dostępna tylko poprzez prefiks nowej wartości utworzonej, używając _Chciałbym wiedzieć, co się dzieje !? dlaczego nie jest this.namezamiast tego?
Muhammad Umer
1
@Muhammad Umer, nie jestem pewien, czy rozumiem twój komentarz. console.log(someone._name = "Jean Dupont");działa równie dobrze, jak console.log(someone.name);i przypisuje i ocenia element z prefiksem podkreślenia znajdujący się za właściwością. Jak widać , nie ma gwarantowanej enkapsulacji poprzez podkreślenia :)
Frédéric Hamidi
3
Domyślnie Visual Studio stara się pomóc ci to uszanować. Silnik javascript IntelliSense pokazuje „prywatne” właściwości z wnętrza obiektu, gdy używana jest zmienna „this”. Ale po wywołaniu z zewnątrz ukrywa wszystkie podkreślone atrybuty.
foxontherock,
1
@Karuhanga odpowiedział na to w 2010 roku - oczywiście, że zmieniło się to za 10 lat
Kenny Meyer
99

JavaScript faktycznie obsługuje enkapsulację, za pomocą metody polegającej na ukrywaniu członków w zamknięciach (Crockford). To powiedziawszy, czasami jest kłopotliwe, a konwencja podkreślenia jest całkiem dobrą konwencją do użytku w przypadku rzeczy, które są w pewnym sensie prywatne, ale których tak naprawdę nie trzeba ukrywać.

Zach
źródło
19
Głosowanie za wyjaśnieniem, jak osiągnąć zamknięcie, głosowanie za mówieniem podkreślenia to dobra konwencja. Więc nie będę głosować w żaden sposób :)
Jason
3
Ukrywanie elementów w zamknięciach może czasami utrudniać testowanie. Sprawdź ten artykuł: odpowiednio odpowiedniogood.com/2010/7/Writing-Testable-JavaScript
Zach Lysobey
4
@Jason - Ciekawe, dlaczego uważasz podkreślanie za złą konwencję?
Tamás Pap
5
@TamasPap - Kilka powodów, ale tylko moja opcja: 1) Kula, aby zmusić JS do stylu innych języków 2) Jeśli jest dostępny, zostanie użyty. Znak podkreślenia może zaśmiecać i skręcać kod zewnętrzny. 3) Mylące dla nowych programistów JS.
Jason
9
Nawet po zamknięciu technicznie możliwe jest uzyskanie dostępu do tak zwanej zmiennej „prywatnej”. Konwencja _ przynajmniej informuje deweloperów, że robią to na własne ryzyko (lub coś w tym rodzaju).
sarink
14

JSDoc 3 umożliwia dodawanie adnotacji do funkcji za pomocą @access private(poprzednio @privatetagu), co jest również przydatne do rozpowszechniania swoich zamiarów wśród innych programistów - http://usejsdoc.org/tags-access.html

philrabin
źródło
10

„Tylko konwencje? A może kryje się za tym prefiks?”

Oprócz konwencji dotyczących prywatności chciałem również pomóc uświadomić, że przedrostek podkreślenia jest również używany w przypadku argumentów zależnych od niezależnych argumentów, szczególnie w mapach kotwiczenia URI. Klucze zależne zawsze wskazują mapę.

Przykład (z https://github.com/mmikowski/urianchor ):

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

Kotwica URI w polu wyszukiwania przeglądarki jest zmieniana na:

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

Jest to konwencja używana do sterowania stanem aplikacji na podstawie zmian skrótu.

Sam Araiza
źródło
8

import/exportwykonuje teraz pracę z ES6. Nadal mam tendencję do prefiksu funkcji nieeksportowanych_ jeśli większość moich funkcji jest eksportowana.

Jeśli eksportujesz tylko klasę (jak w projektach kątowych), nie jest ona wcale potrzebna.

export class MyOpenClass{

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

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

}

function close(){ /*... this is really private... */ }
Nicolas Zozol
źródło
Nie sądzę, aby import / eksport w jakikolwiek sposób wspierał metody klas prywatnych. Mam na myśli, że obsługuje podobną funkcjonalność na poziomie klasy, ale nie oferuje ukrywania zawartych metod. (tzn. wszystkie zawarte metody są zawsze publiczne)
bvdb
Eksportujesz klasę, a funkcja wewnętrzna wywołuje funkcję zewnętrzną. Te funkcje są prywatnymi.
Nicolas Zozol,