A palavra-chave "nova" do JavaScript é considerada prejudicial? [fechadas]


568

Em outra pergunta , um usuário apontou que a newpalavra - chave era perigosa e propôs uma solução para a criação de objetos que não era usada new. Eu não acreditava que isso fosse verdade, principalmente porque usei Prototype, Scriptaculous e outras excelentes bibliotecas JavaScript, e todos eles usaram a newpalavra - chave.

Apesar disso, ontem eu estava assistindo a palestra de Douglas Crockford no teatro YUI e ele disse exatamente a mesma coisa, que ele não usava mais a newpalavra - chave em seu código ( Crockford em JavaScript - Ato III: Função Final - 50:23 minutos ).

É 'ruim' usar a newpalavra - chave? Quais são as vantagens e desvantagens de usá-lo?


90
NÃO é 'ruim' usar a nova palavra-chave. Mas se você esquecer, estará chamando o construtor de objetos como uma função regular. Se o construtor não verificar seu contexto de execução, ele não notará que 'this' aponta para um objeto diferente (normalmente o objeto global) em vez da nova instância. Portanto, seu construtor estará adicionando propriedades e métodos ao objeto global (janela). Se você sempre verificar se 'this' é uma instância do seu objeto na função de objeto, nunca terá esse problema.
Kristian B

5
Eu não entendo isso. Por um lado, doug desencoraja o uso de new. Mas quando você olha para a biblioteca YUI. Você tem que usar em newqualquer lugar. Tais como var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); .
Aditya_gaur

2
@aditya_gaur Isso porque se você precisar de alguma inicialização de um objeto, teria que hackear um initmétodo se estiver usando a Object.createabordagem e chamar depois. Muito mais fácil de usar, o newque faz as duas coisas, define a cadeia de protótipos e chama algum código inicializador.
Juan Mendes

67
Eu não acho que isso deveria ter sido fechado. Sim, é provável que inspire algum veneno anti-fã de Crockford, mas estamos falando de conselhos populares para basicamente evitar um recurso importante do idioma aqui. O mecanismo que faz todo objeto JQuery pesar quase nada (no que diz respeito à memória) envolve o uso da palavra-chave 'new'. Prefira métodos de fábrica a invocar constantemente novos, mas não reduza drasticamente suas opções de arquitetura e potencial de desempenho usando apenas literais de objetos. Eles têm o seu lugar e os construtores têm o seu lugar. É um conselho antigo e péssimo.
precisa

2
TLDR: O uso newnão é perigoso. Omitir newé perigoso e, portanto, ruim . Mas no ES5, você pode usar o Modo Estrito , que protege você contra esse perigo e muitos outros.
jkdev

Respostas:


603

Crockford fez muito para popularizar boas técnicas de JavaScript. Sua posição opinativa sobre os principais elementos da linguagem provocou muitas discussões úteis. Dito isto, existem muitas pessoas que tomam cada proclamação de "mau" ou "prejudicial" como evangelho, recusando-se a olhar além da opinião de um homem. Às vezes pode ser um pouco frustrante.

O uso da funcionalidade fornecida pela newpalavra-chave tem várias vantagens sobre a construção de cada objeto do zero:

  1. Herança de protótipo . Embora muitas vezes sejam encaradas com uma mistura de suspeita e escárnio por aqueles acostumados a linguagens OO baseadas em classes, a técnica de herança nativa do JavaScript é um meio simples e surpreendentemente eficaz de reutilização de código. E a nova palavra-chave é o meio canônico (e apenas disponível em várias plataformas) de usá-lo.
  2. Atuação. Este é um efeito colateral do nº 1: se eu quiser adicionar 10 métodos a cada objeto que eu criar, eu poderia escrever uma função de criação que atribua manualmente cada método a cada novo objeto ... Ou poderia atribuí-los ao método funções de criação prototypee uso newpara carimbar novos objetos. Além de ser mais rápido (não é necessário código para todos os métodos do protótipo), ele evita o balão de cada objeto com propriedades separadas para cada método. Em máquinas mais lentas (ou especialmente, intérpretes JS mais lentos) quando muitos objetos estão sendo criados, isso pode significar uma economia significativa de tempo e memória.

E sim, newtem uma desvantagem crucial, habilmente descrita por outras respostas: se você esquecer de usá-lo, seu código será quebrado sem aviso. Felizmente, essa desvantagem é facilmente mitigada - basta adicionar um pouco de código à própria função:

function foo()
{
   // if user accidentally omits the new keyword, this will 
   // silently correct the problem...
   if ( !(this instanceof foo) )
      return new foo();

   // constructor logic follows...
}

Agora você pode ter as vantagens de newnão ter que se preocupar com problemas causados ​​por uso indevido acidental. Você pode até adicionar uma asserção à verificação se o pensamento de código quebrado funcionar silenciosamente o incomoda. Ou, como alguns comentaram, use a verificação para introduzir uma exceção de tempo de execução:

if ( !(this instanceof arguments.callee) ) 
   throw new Error("Constructor called as a function");

(Observe que esse fragmento é capaz de evitar codificar o nome da função do construtor, pois, diferentemente do exemplo anterior, ele não precisa instanciar o objeto - portanto, ele pode ser copiado em cada função de destino sem modificação.)

John Resig detalha essa técnica em seu post de Instanciação "Classe" Simples , além de incluir um meio de transformar esse comportamento em suas "classes" por padrão. Definitivamente vale a pena ler ... assim como seu próximo livro, Secrets of the JavaScript Ninja , que encontra ouro oculto neste e em muitos outros recursos "prejudiciais" da linguagem JavaScript (o capítulo sobre withé especialmente esclarecedor para aqueles que inicialmente descartaram esse recurso muito difamado como um artifício).


96
if (! (this instance of argument.callee)) throw Error ("Construtor chamado como função"); // Mais genérico, não requer conhecimento do nome dos construtores, faça o usuário corrigir o código.
algum

5
Se você está preocupado com o desempenho - e realmente tem motivos para estar -, não faça a verificação. Lembre-se de usar newou use uma função de invólucro para lembrá-la para você. Eu suspeito que se você está no ponto onde importa, você já exaustos outras otimizações, como memoization, assim que suas chamadas de criação será localizado de qualquer maneira ...
Shog9

65
Usar arguments.calleepara verificar se você foi chamado newpode não ser tão bom, pois arguments.calleenão está disponível no modo estrito. Melhor usar o nome da função.
Sean McMillan

69
Se eu digitar incorretamente um identificador, meu código será quebrado. Não devo usar identificadores? Não usar newporque você pode esquecer de escrevê-lo em seu código é tão ridículo quanto o meu exemplo.
Thomas Eding

16
Se você ativar o modo estrito, se você esquecer de usar new, receberá uma exceção ao tentar usar isso: yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town Isso é mais fácil do que adicionar uma instância de cheque a cada construtor.
stephenbez

182

Acabei de ler algumas partes de seu livro de Crockfords "Javascript: The Good Parts". Tenho a sensação de que ele considera tudo o que já o mordeu como prejudicial:

Sobre o switch:

Eu nunca permito que os casos de troca passem para o próximo caso. Certa vez, encontrei um bug no meu código causado por uma queda não intencional imediatamente após ter feito um discurso vigoroso sobre o motivo pelo qual a queda era às vezes útil. (página 97, ISBN 978-0-596-51774-8)

Sobre ++ e -

Sabe-se que os operadores ++ (incremento) e - (decremento) contribuem para códigos incorretos, incentivando truques excessivos. Eles perdem apenas para a arquitetura defeituosa, permitindo vírus e outras ameaças à segurança. (página 122)

Sobre o novo:

Se você esquecer de incluir o novo prefixo ao chamar uma função de construtor, isso não será vinculado ao novo objeto. Infelizmente, isso será vinculado ao objeto global; portanto, em vez de aumentar seu novo objeto, você estará sobrecarregando as variáveis ​​globais. Isso é muito ruim. Não há aviso de compilação nem aviso de tempo de execução. (página 49)

Há mais, mas espero que você entenda.

Minha resposta para sua pergunta: não, não é prejudicial. mas se você esquecer de usá-lo quando tiver, poderá ter alguns problemas. Se você está desenvolvendo em um bom ambiente, percebe isso.

Atualizar

Cerca de um ano após a redação dessa resposta, foi lançada a 5ª edição do ECMAScript, com suporte ao modo estrito . No modo estrito, thisnão está mais vinculado ao objeto global, mas a undefined.


3
Eu concordo completamente. A solução: sempre documente como os usuários precisam instanciar seus objetos. Use um exemplo e os usuários provavelmente recortam / colam. Existem construções / recursos em todos os idiomas que podem ser mal utilizados, resultando em comportamento incomum / inesperado. Não os torna prejudiciais.
Nicerobot

45
Existe uma convenção para sempre iniciar construtores com uma letra maiúscula e todas as outras funções com uma letra minúscula.
alguns

61
Eu só percebi que Crockford não consideram ENQUANTO prejudicial ... Eu não sei quanto tempo eu criei um laço infinitivo porque eu esqueci de incrementar uma variável ...
alguns

5
O mesmo vale para ++, -. Eles expressam exatamente o que pretendo na linguagem mais clara possível. Eu os amo! algumas interrupções podem ser claras para alguns, mas estou cansada disso. Uso-os quando são claramente mais claros (desculpe o trocadilho, não pude resistir).
PEZ

30
Minha resposta para Crockford: A programação é difícil, vamos às compras. Sheesh!
Jason Jackson

91

Javascript sendo uma linguagem dinâmica, há um zilhão de maneiras de atrapalhar onde outro idioma o impediria.

Evitar um recurso fundamental da linguagem, como newna base de que você pode estragar tudo, é como remover seus sapatos novos e brilhantes antes de caminhar por um campo minado, para o caso de você ficar enlameado.

Uso uma convenção em que os nomes das funções começam com uma letra minúscula e 'funções' que são realmente definições de classe começam com uma letra maiúscula. O resultado é uma pista visual bastante convincente de que a 'sintaxe' está errada: -

var o = MyClass();  // this is clearly wrong.

Além disso, bons hábitos de nomeação ajudam. Depois que todas as funções fazem as coisas e, portanto, deve haver um verbo em seu nome, enquanto as classes representam objetos e são substantivos e adjetivos sem verbo.

var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.

É interessante como a coloração da sintaxe do SO interpretou o código acima.


8
Sim, eu estava pensando a mesma coisa sobre a coloração da sintaxe.
BobbyShaftoe

4
Uma vez eu esqueci de digitar a palavra 'função'. A palavra deve ser evitada a todo custo. Em outra ocasião, não usei chaves em uma instrução if / then com várias linhas. Então agora eu não uso chaves e apenas escrevo condicionais de uma linha.
precisa saber é o seguinte

"Isso está claramente errado" . Por quê? Para minhas aulas (o que simplesmente acontece if (! this instanceof MyClass) return new MyClass()), eu realmente prefiro a newsintaxe -less. Por quê? Porque funções são mais genéricas que funções construtoras . Sair newfacilita a mudança de uma função de construtor para uma função regular ... Ou o contrário. A adição newtorna o código mais específico do que precisa. E, portanto, menos flexível. Compare com Java, onde é recomendável aceitar, em Listvez de, ArrayListpara que o chamador possa escolher a implementação.
Stijn de Witt

41

Eu sou iniciante em Javascript, então talvez eu não tenha muita experiência em fornecer um bom ponto de vista para isso. No entanto, quero compartilhar minha opinião sobre essa coisa "nova".

Eu vim do mundo C #, onde o uso da palavra-chave "novo" é tão natural que é o padrão de design da fábrica que me parece estranho.

Quando codifico pela primeira vez em Javascript, não percebo que exista a palavra-chave e o código "novos", como o padrão YUI, e não demoro muito tempo para entrar em desastre. Perco a noção do que uma linha específica deveria estar fazendo ao olhar para trás o código que escrevi. Mais caótico é que minha mente não pode realmente transitar entre os limites das instâncias de objeto quando estou "executando a seco" o código.

Então, encontrei a "nova" palavra-chave que, para mim, "separava" as coisas. Com a nova palavra-chave, ela cria coisas. Sem a nova palavra-chave, sei que não a confundirei com a criação de coisas, a menos que a função que estou invocando me dê fortes pistas disso.

Por exemplo, com var bar=foo();eu não tenho pistas sobre qual barra poderia ser ... É um valor de retorno ou é um objeto recém-criado? Mas com var bar = new foo();eu sei com certeza bar é um objeto.


3
Concordou, e eu acredito que o padrão de fábrica devem seguir uma convenção de nomenclatura como makefoo ()
pluckyglen

3
+1 - a presença de 'novo' fornece uma declaração de intenção mais clara.
22710 belugabob

4
Essa resposta é meio estranha, quando quase tudo em JS é um objeto. Por que você precisa ter certeza de que uma função é um objeto quando todas as funções são objetos?
Joshua Ramirez

@ JoshuaRamirez O ponto não é esse typeof new foo() == "object". É que newretorna uma instância de fooe você sabe que pode chamar foo.bar()e foo.bang(). No entanto, que pode ser facilmente atenuado com o uso @return do JSDoc Não que eu estou defendendo para o código processual (evitando a palavra new)
Juan Mendes

1
@JuanMendes Hmm ... Sua postagem me pareceu que você gostou de algo novo por causa de sua palavra-chave explícita em sua base de código. Eu posso cavar isso. É por isso que eu uso um padrão de módulo. Vou ter uma função chamada createFoo ou NewFoo ou MakeFoo, não importa, desde que seja explícito. Dentro disso, declaro variáveis ​​que são usadas como fechamentos dentro de um objeto literal que é retornado da função. Esse literal de objeto acaba sendo seu objeto, e a função era apenas uma função de construção.
Joshua Ramirez

39

Outro argumento para o novo é o que chamo de Pooh Coding . Winnie the Pooh segue sua barriga. Eu digo: vá com o idioma que você está usando, não contra ele.

As chances são de que os mantenedores do idioma otimizarão o idioma para os idiomas que tentam incentivar. Se eles colocarem uma nova palavra-chave no idioma, provavelmente pensam que faz sentido ficar claro ao criar uma nova instância.

O código escrito seguindo as intenções do idioma aumentará em eficiência a cada versão. E o código que evitar as principais construções da linguagem sofrerá com o tempo.

EDIT: E isso vai muito além do desempenho. Não posso contar as vezes que ouvi (ou disse) "por que diabos eles fizeram isso ?" ao encontrar código de aparência estranha. Muitas vezes acontece que, no momento em que o código foi escrito, havia alguma "boa" razão para isso. Seguir o Tao do idioma é o seu melhor seguro para não ter seu código ridicularizado daqui a alguns anos.


3
+1 para o link Pooh Coding - Agora eu preciso encontrar desculpas para trabalhar isso em minhas conversas ...
Shog9

RI MUITO! Tenho anos de experiência nesse campo em particular e posso garantir que você não encontrará dificuldades. Eles costumam me chamar de Pooh no robowiki.net. =)
PEZ

1
Não sei se você verá esse comentário, mas o link Pooh Coding está morto.
Calvin

Obrigado pela atenção. Migramos o robowiki.net para um novo wiki na semana passada e o conteúdo antigo está inacessível no momento. Vou me apressar em fazer esses links antigos funcionarem.
PEZ

24

Eu escrevi um post sobre como atenuar o problema de chamar um construtor sem a nova palavra-chave.
É principalmente didático, mas mostra como você pode criar construtores que funcionam com ou sem newe não requer que você adicione código padrão para testar thisem cada construtor.

http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

Aqui está a essência da técnica:

/**
 * Wraps the passed in constructor so it works with
 * or without the new keyword
 * @param {Function} realCtor The constructor function.
 *    Note that this is going to be wrapped
 *    and should not be used directly 
 */
function ctor(realCtor){
  // This is going to be the actual constructor
  return function wrapperCtor(){
    var obj; // object that will be created
    if (this instanceof wrapperCtor) {
      // Called with new
      obj = this;
    } else {
      // Called without new. Create an empty object of the
      // correct type without running that constructor
      surrogateCtor.prototype = wrapperCtor.prototype;
      obj = new surrogateCtor();
    }
    // Call the real constructor function
    realCtor.apply(obj, arguments);
    return obj;
  }

  function surrogateCtor() {}
}

Veja como usá-lo:

// Create our point constructor
Point = ctor(function(x,y){
  this.x = x;
  this.y = y;
});

// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);

6
evitar arguments.calleeé incrível!
22812 Gregg Lind

2
surrogateConstructordeve ser surrogateCtor(ou vice-versa).
David Conrad

Eu mantive uma coleção de utilitários semelhantes inspirados em Crockford e descobri que ele sempre me fazia correr para encontrar as implementações quando inicio um novo projeto. E isso envolve uma parte fundamental da programação: instanciação de objetos. Todo esse trabalho, apenas para habilitar o código de instanciação aleatória? Agradeço sinceramente a engenhosidade desse invólucro, mas parece gerar uma codificação descuidada.
Joe Coder

1
@ joecoder Eu mencionei que isso era apenas para fins didáticos, não assino esse estilo de codificação paranóia. No entanto, se eu estivesse escrevendo uma biblioteca de classes, sim, acrescentaria esse recurso de maneira transparente aos chamadores #
Juan Mendes

22

A lógica por trás do não uso da nova palavra-chave é simples:

Ao não usá-lo, você evita a armadilha que vem com a omissão acidental. O padrão de construção usado pelo YUI é um exemplo de como você pode evitar completamente a nova palavra-chave "

var foo = function () {
    var pub= { };
    return pub;
}
var bar = foo();

Como alternativa, você poderia fazer isso:

function foo() { }
var bar = new foo();

Mas, ao fazer isso, você corre o risco de alguém esquecer de usar a nova palavra-chave, e o operador this ser todo fubar. AFAIK, não há vantagem em fazer isso (a não ser que você esteja acostumado).

No final do dia: é sobre ser defensivo. Você pode usar a nova declaração? Sim. Isso torna seu código mais perigoso? Sim.

Se você já escreveu C ++, é como definir ponteiros para NULL depois de excluí-los.


6
Não. Com "new foo ()", algumas propriedades são definidas no objeto retornado, como o construtor.
algum

34
Então, apenas para deixar isso claro: você não deve usar “novo” porque pode esquecê-lo? Você está brincando, certo?
Bombe

16
@Bombe: em outros idiomas, esquecer "novo" resultaria em erro. Em Javascript, ele continua sendo transportado. Você pode esquecer e nunca perceber. E simplesmente olhar código errôneo não será óbvio para o que está errado.
Kent Fredric

3
@ Greg: Não vejo como a primeira técnica permite o uso de cadeias de protótipos - os literais de objetos são ótimos, mas jogar fora o desempenho e outras vantagens oferecidas pelos protótipos por medo parece um pouco tolo.
Shog9

5
@Bombe - Você deve usar "new" porque você (e qualquer pessoa que use seu código) nunca cometerá um erro? Você está brincando, certo?
Greg Dean

20

Eu acho que "novo" adiciona clareza ao código. E a clareza vale tudo. É bom saber que existem armadilhas, mas evitá-las evitando a clareza não me parece o caminho.


16

Caso 1: newnão é obrigatório e deve ser evitado

var str = new String('asd');  // type: object
var str = String('asd');      // type: string

var num = new Number(12);     // type: object
var num = Number(12);         // type: number

Caso 2: newé necessário, caso contrário, você receberá um erro

new Date().getFullYear();     // correct, returns the current year, i.e. 2010
Date().getFullYear();         // invalid, returns an error

5
Deve-se notar que no caso 1, chamar o construtor como uma função só faz sentido se você estiver pretendendo conversão de tipo (e não souber se o objeto do casco possui um método de conversão, como toString()). Em todos os outros casos, use literais. Não String('asd') , mas simplesmente 'asd', e não Number(12) , mas simplesmente 12.
PointedEars

1
@PointedEars Uma exceção a essa regra seria Array: Array(5).fill(0) é, obviamente, mais legível do que [undefined, undefined, undefined, undefined, undefined].fill(0)e(var arr = []).length = 5; arr.fill(0);
yyny

@YoYoYonnY Minha declaração foi feita no contexto do caso 1 da resposta, que se refere ao uso de newcom construtores para tipos de objetos correspondentes a tipos primitivos . O literal que você está sugerindo não é equivalente à Arraychamada (try 0 in …), e o resto é um erro de sintaxe :) Caso contrário, você está correto, embora deva-se notar também que Array(5)pode ser ambíguo se você considerar implementações não conformes (e portanto, um emulado Array.prototype.fill(…) ).
PointedEars

12

Aqui está o breve resumo que eu poderia fazer dos dois argumentos mais fortes a favor e contra o uso do newoperador:

Argumento contra new

  1. Funções projetadas para serem instanciadas como objetos usando o newoperador podem ter efeitos desastrosos se forem invocadas incorretamente como funções normais. O código de uma função nesse caso será executado no escopo em que a função é chamada, em vez de no escopo de um objeto local, como pretendido. Isso pode fazer com que variáveis ​​e propriedades globais sejam substituídas com consequências desastrosas.
  2. Finalmente, escrever function Func()e, em seguida, chamar Func.prototype e adicionar itens a ele para que você possa chamar new Func()para construir seu objeto parece feio para alguns programadores, que preferem usar outro estilo de herança de objetos por razões arquitetônicas e estilísticas.

Para saber mais sobre esse argumento, consulte o grande e conciso livro de Douglas Crockford, Javascript: The Good Parts. De fato, confira de qualquer maneira.

Argumento a favor de new

  1. O uso do newoperador junto com a atribuição de protótipo é rápido.
  2. O problema de executar acidentalmente o código de uma função de construtor no espaço de nomes global pode ser facilmente evitado se você sempre incluir um pouco de código nas funções de construtor para verificar se elas estão sendo chamadas corretamente e, nos casos em que não estão. , manipulando a chamada adequadamente, conforme desejado.

Veja o post de John Resig para uma explicação simples dessa técnica e para uma explicação geralmente mais profunda do modelo de herança que ele defende.


Uma atualização sobre os argumentos contra: # 1 pode ser mitigado usando o 'use strict';modo (ou o método no seu link) # 2 Possui açúcar sinático no ES6 , no entanto, o comportamento é o mesmo de antes.
NinMonkey 11/11

9

Eu concordo com pez e alguns aqui.

Parece-me óbvio que "novo" é a criação auto-descritiva de objetos, onde o padrão YUI que Greg Dean descreve é completamente obscuro .

A possibilidade de alguém escrever var bar = foo;ou var bar = baz();onde o baz não é um método de criação de objetos parece muito mais perigoso.


8

Eu acho que novo é ruim, não porque se você esquece de usá-lo por engano, pode causar problemas, mas porque estraga a cadeia de herança, tornando a linguagem mais difícil de entender.

JavaScript é orientado a objeto baseado em protótipo. Portanto, todo objeto DEVE ser criado a partir de outro objeto como esse var newObj=Object.create(oldObj). Aqui oldObj é chamado de protótipo de newObj (daí "baseado em protótipo"). Isso implica que, se uma propriedade não for encontrada em newObj , ela será pesquisada em oldObj . O newObj, por padrão, será um objeto vazio, mas devido à sua cadeia de protótipos, parece ter todos os valores de oldObj .

Por outro lado, se o fizer var newObj=new oldObj(), o protótipo de newObj é oldObj.prototype , que é desnecessariamente difícil de entender.

O truque é usar

Object.create=function(proto){
  var F = function(){};
  F.prototype = proto;
  var instance = new F();
  return instance;
};

Está dentro dessa função e somente aqui o novo deve ser usado. Após isso, basta usar o método Object.create () . O método resolve o problema do protótipo.


7
Para ser honesto, não sou louco por essa técnica - ela não acrescenta nada de novo e, como sua resposta ilustra, ela pode até acabar sendo uma muleta. IMHO, entender as cadeias de protótipos e a instanciação de objetos é crucial para entender o JavaScript ... Mas se você se sentir desconfortável em usá-las diretamente, usar uma função auxiliar para cuidar de alguns detalhes é bom, desde que você se lembre do que está fazendo. fazendo. FWIW: uma variação (um pouco mais útil) disso faz parte do ECMAScript 5th ed. std e já está disponível em alguns navegadores - portanto, tenha cuidado para não redefini-lo cegamente!
Shog9

BTW: Eu não sei por que você fez isso CW, mas se você quiser re post-it com as correções de formatação que fiz, ter cuidado para evitar que a caixa ...
Shog9

2
Desnecessariamente difícil de entender? var c = new Car()é o mesmo que fazer #var c = Object.create(Car.prototype); Car.call(c)
Juan Mendes
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.