encapsulação em JavaScript

este será o meu último post na série” JavaScript for (C/)AL Developers ” hoje. Se eu continuasse blogando sobre coisas quase puras de JavaScript, você poderia razoavelmente perguntar se este é de fato um blog de navegação ou um JavaScript. Ainda é NAV, e enquanto as coisas sobre as quais estou prestes a escrever é puramente um conceito JavaScript, eu acho que é altamente relevante para qualquer desenvolvedor de controle adicional. Então, segura na minha cerveja, e aguenta comigo por mais uma.

uma das queixas que muitas vezes ouço sobre JavaScript é que em JavaScript não há encapsulação. Isso é quase completamente verdade, exceto pelo fato de que é inteiramente falso.

Onde está o problema em primeiro lugar, e então qual é a solução? Vamos mergulhar.Imagine que está a declarar um construtor. Imagine por um segundo que estamos no mundo ES5 (que, infelizmente, temos que usar se queremos que nossos controles adicionais sejam totalmente compatíveis com todas as plataformas em que NAV e Business Central são suportados).Este é o meu código.:

obviamente, isto mostra 42, que é a minha idade actual.

em Breve, ele será meu aniversário, então isso mostra 43:

Agora, enquanto eu absolutamente adoraria ser capaz de fazer algo assim na vida real:

… isso não vai acontecer. Em um mundo decente orientado a objetos, “idade” deve ser uma propriedade encapsulada, e você não deve ser capaz de chamar vjeko.idade = 25 anos. C# and “normal” object-oriented languages have a concept of encapsulation, they can handle this using private fields, but JavaScript has no concept of private. Qualquer coisa definida sobre isso dentro do construtor do objeto (ou mais tarde em uma instância de um objeto construído) é totalmente acessível a todo código que tem acesso a essa instância. No meu exemplo acima, qualquer um pode definir a idade e escapar impune.Pode dizer-se que JavaScript não tem encapsulação. E como eu disse acima, você estaria completamente errado.

a solução

por mais óbvia que seja que não podemos declarar nada como privado diretamente, ainda há coisas que podemos usar. Um belo conceito que dá jeito é chamado fechamento. Encerramentos são explicados em um milhão de blogs, sites de documentação e exemplos de código em toda a internet, e você pode pesquisar o bejesus fora deles em seu próprio ritmo, então eu não vou investigar para explicar encerramentos aqui. Vou simplesmente aplicá-los para resolver o problema da encapsulação.Há pelo menos duas maneiras de lidar com isto. Vamos primeiro fazer a mais óbvia: uma função de acesso.Imagine o mundo sem propriedades onde você não pode fazer objeto.propriedade = valor (como vjeko.idade = 25 anos no nosso caso,por Mais que eu adorasse!). Nesse mundo, você teria funções getter e setter:

(ignora por um momento o facto de que ainda estou a usar isto.idade para “encapsular” a “propriedade”)

obviamente, você seria capaz de chamá-los assim:

então, se você quisesse ter a idade apenas para leitura, você simplesmente deixaria cair a função setter setAge. Se isto.a idade era realmente privada (o que não é), isso faria o truque para você. O problema é que nada definido nisto é privado, é acessível a qualquer pessoa que tenha acesso a qualquer instância do objeto. É o mais público possível.

para resolver este problema, a primeira coisa que precisamos fazer é mover a declaração da função getter do protótipo para a instância. Os membros protótipos estão mais próximos do que nós chamaríamos de estático em c#, mesmo que em tempo de execução eles têm certos traços comportamentais de ambos os membros estáticos e instância. No entanto, primeiro vamos mover o membro de distância do protótipo, e em instância:

Isto resolve apenas a primeira parte do problema, o fato de que getAge foi definido no protótipo, ao invés de incluir na instância. No entanto, com uma simples mudança como esta:

… nós resolvemos o problema completamente:

a idade está agora totalmente encapsulada. Você pode acessá-lo através da função getter, mas você não pode configurá-lo diretamente, porque ele só é acessível no escopo de fechamento deste.função de instância de getAge.

implementar plenamente a classe Pessoa, você precisa mover o growOlder função a partir do protótipo para a instância:

E isso funciona exatamente como você quer que ele funcione:

Mas por que isso funciona? Funciona por causa dos encerramentos. O parâmetro idade do construtor foi capturado no escopo de fechamento das funções getAge e growOlder, permitindo-lhe acessar o seu valor de ambas as funções, mas tornando-o completamente inacessível a qualquer outra pessoa, em qualquer outro lugar.

solução ainda melhor

você poderia dizer que você não quer acessá-la através de uma função getter, e que você precisa de uma sintaxe completa de propriedade apenas para leitura. Você quer sua idade apenas de leitura e encapsulado ao mesmo tempo. Apanhei-te! JavaScript não pode encapsular isso! Excepto que pode.

I addressed the Object.defineProperty method in my previous post, and if you read that one, you can immediately see how it can be applied here.

assim, vamos definir uma propriedade de instância de leitura da classe de pessoa:

pronto. Não doeu. E funciona:

aí está. Encapsulação completa em JavaScript para ajudá-lo a escrever um código bom e isolado, e assumir o seu controle adicionando ao real kick-a$ level.

Happy JavaScripting, and I hope to get more time to blog about other cool and useful JavaScript tips and tricks for (C/)AL developers.

Deixe uma resposta

O seu endereço de email não será publicado.