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.


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


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 .


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ć.


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


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.


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... */ }

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.