Sublinhado o prefixo dos nomes de propriedades e métodos em JavaScript

240

O prefixo de sublinhado no JavaScript é apenas uma convenção, como, por exemplo, nos métodos de classe privada do Python?

Na documentação do Python 2.7:

Variáveis ​​de instância "privadas" que não podem ser acessadas, exceto de dentro de um objeto, não existem no Python. No entanto, existe uma convenção seguida pela maioria dos códigos Python: um nome prefixado com um sublinhado (por exemplo, _spam) deve ser tratado como uma parte não pública da API (seja uma função, um método ou um membro de dados) .

Isso também se aplica ao JavaScript?

Tomemos, por exemplo, este código JavaScript:

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

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

Além disso, variáveis ​​prefixadas com sublinhado são usadas.

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

Apenas convenções? Ou há mais por trás do prefixo de sublinhado?


Eu admito que minha pergunta é bem parecida com essa pergunta , mas não esclareceu a importância do prefixo de sublinhado no JavaScript.

Kenny Meyer
fonte
Veja também stackoverflow.com/questions/17359885/…
Jon Onstott

Respostas:

33

Bem-vindo a 2019!

Parece que uma proposta para estender a sintaxe da classe para permitir que a #variável prefixada seja privada foi aceita. O Chrome 74 é enviado com esse suporte.

_ nomes de variáveis ​​prefixados são considerados privados por convenção, mas ainda são públicos.

Essa sintaxe tenta ser concisa e intuitiva, embora seja bastante diferente de outras linguagens de programação.

Por que o símbolo # foi escolhido, entre todos os pontos de código Unicode?

  • @ foi o favorito inicial, mas foi escolhido pelos decoradores. O TC39 considerou a troca de decoradores e sigilos do estado privado, mas o comitê decidiu adiar o uso existente de usuários de transpiladores.
  • _ causaria problemas de compatibilidade com o código JavaScript existente, que permitia _ no início de um identificador ou nome de propriedade (público) por um longo tempo.

Essa proposta chegou ao estágio 3 em julho de 2017. Desde então, houve um amplo pensamento e uma longa discussão sobre várias alternativas. No final, esse processo de pensamento e o envolvimento contínuo da comunidade levaram a um consenso renovado sobre a proposta neste repositório. Com base nesse consenso, as implementações estão avançando nessa proposta.

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

Karuhanga
fonte
257

Isso é apenas uma convenção. A linguagem Javascript não atribui nenhum significado especial aos identificadores que começam com caracteres sublinhados.

Dito isto, é uma convenção bastante útil para um idioma que não suporta encapsulamento imediatamente. Embora não haja maneira de impedir alguém de abusar das implementações de suas classes, pelo menos isso esclarece sua intenção e documenta esse comportamento como errado em primeiro lugar.

Frédéric Hamidi
fonte
4
Sim. Mesmo que o idioma não o "suporte", é uma convenção realmente útil.
Juho Vepsäläinen
Problema sério. jsfiddle.net/VmFSR Como você pode ver lá, o nome do valor criado só pode ser acessado prefixando o novo valor, criado, usando _eu adoraria saber o que está acontecendo !? por que não é this.name?
Muhammad Umer
1
@ Muhammad Umer, não sei se entendi seu comentário. console.log(someone._name = "Jean Dupont");funciona tão bem quanto console.log(someone.name);atribui e avalia o membro com prefixo sublinhado atrás da propriedade. Como você pode ver , há há encapsulamento garantida através de sublinhados :)
Frédéric Hamidi
3
Por padrão, o Visual Studio tenta ajudá-lo a respeitar isso. O mecanismo javascript IntelliSense mostra propriedades "particulares", de dentro do objeto, ao usar a variável "this". Mas, quando chamado de fora, oculta todos os atributos sublinhados.
foxontherock
1
@Karuhanga, ele respondeu isso em 2010 - é claro que as coisas mudaram em 10 anos #
Kenny Meyer
99

O JavaScript realmente suporta o encapsulamento, através de um método que envolve ocultar membros em fechamentos (Crockford). Dito isto, às vezes é complicado, e a convenção de sublinhado é uma convenção muito boa para usar em coisas que são particulares, mas que você realmente não precisa esconder.

Zach
fonte
19
Voto positivo para esclarecer como obter fechamentos, voto negativo por dizer sublinhados é uma boa convenção. Então eu não vou votar de qualquer maneira :)
Jason
3
Ocultar membros em fechamentos às vezes pode dificultar a testabilidade. Confira este artigo: adequatelygood.com/2010/7/Writing-Testable-JavaScript
Zach Lysobey
4
@ Jason - Apenas curioso, por que você considera sublinhado uma má convenção?
Tamás Pap
5
@TamasPap - Algumas razões, mas apenas a minha opção: 1) Uma muleta para forçar o JS a um estilo de outras línguas 2) Se estiver acessível, será usado. O sublinhado pode desarrumar e distorcer o código externo. 3) Confuso para novos programadores de JS.
Jason
9
Mesmo com o fechamento, ainda é tecnicamente possível obter acesso à chamada variável "privada". A convenção _ pelo menos permite que os desenvolvedores saibam fazê-lo por seu próprio risco (ou algo assim).
sarink
14

O JSDoc 3 permite que você anote suas funções com a @access private(anteriormente a @privatetag), que também é útil para transmitir sua intenção a outros desenvolvedores - http://usejsdoc.org/tags-access.html

philrabin
fonte
10

"Apenas convenções? Ou há mais por trás do prefixo de sublinhado?"

Além das convenções de privacidade, eu também queria ajudar a conscientizar que o prefixo de sublinhado também é usado para argumentos que dependem de argumentos independentes, especificamente nos mapas de âncora do URI. As chaves dependentes sempre apontam para um mapa.

Exemplo (de https://github.com/mmikowski/urianchor ):

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

A âncora do URI no campo de pesquisa do navegador é alterada para:

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

Esta é uma convenção usada para conduzir um estado de aplicativo com base em alterações de hash.

Sam Araiza
fonte
8

import/exportagora está fazendo o trabalho com o ES6. Eu ainda tendem a prefixar funções não exportadas com _se a maioria das minhas funções for exportada.

Se você exportar apenas uma classe (como em projetos angulares), ela não será necessária.

export class MyOpenClass{

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

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

}

function close(){ /*... this is really private... */ }
Nicolas Zozol
fonte
Eu não acho que a importação / exportação ofereça suporte para métodos de classe privada de forma alguma. Quero dizer, ele suporta uma funcionalidade semelhante no nível da classe, mas não oferece ocultar os métodos contidos. (ou seja, todos os métodos contidos são sempre público)
bvdb
Você exporta a classe e a função interna chama fora da função. Essas funções são privadas.
Nicolas Zozol 15/10