Qual é a palavra-chave “nova” em JavaScript?

A new palavra-chave em JavaScript pode ser bastante confusa quando é encontrada pela primeira vez, já que as pessoas tendem a pensar que o JavaScript não é uma linguagem de programação orientada a objects.

  • O que é isso?
  • Que problemas isso resolve?
  • Quando é apropriado e quando não?

Faz 5 coisas:

  1. Cria um novo object. O tipo desse object é simplesmente object .
  2. Ele define a propriedade interna, inacessível, [[protótipo]] (isto é, __proto__ ) deste object como sendo o object protótipo externo, acessível, da function construtora (cada object de function tem automaticamente uma propriedade protótipo ).
  3. Isso faz com que this variável aponte para o object recém-criado.
  4. Ele executa a function construtora, usando o object recém-criado sempre que this é mencionado.
  5. Ele retorna o object recém-criado, a menos que a function construtora retorne uma referência de object não null . Nesse caso, essa referência de object é retornada.

Nota: a function de construtor refere-se à function após a new palavra-chave, como em

 new ConstructorFunction(arg1, arg2) 

Quando isso for feito, se uma propriedade indefinida do novo object for solicitada, o script verificará o object [[prototype]] do object para a propriedade. É assim que você pode obter algo semelhante à inheritance de class tradicional em JavaScript.

A parte mais difícil sobre isso é o ponto número 2. Todo object (incluindo funções) tem essa propriedade interna chamada [[protótipo]] . Ele pode ser definido no momento da criação do object, com new , com Object.create ou com base no literal (funções padrão para Function.prototype, números para Number.prototype etc.). Só pode ser lido com Object.getPrototypeOf (someObject) . Não outra maneira de definir ou ler esse valor.

Funções, além da propriedade hidden [[prototype]] , também têm uma propriedade chamada prototype , e é isso que você pode acessar, e modificar, para fornecer propriedades e methods herdados para os objects que você faz.


Aqui está um exemplo:

 ObjMaker = function() {this.a = 'first';}; // ObjMaker is just a function, there's nothing special about it that makes // it a constructor. ObjMaker.prototype.b = 'second'; // like all functions, ObjMaker has an accessible prototype property that // we can alter. I just added a property called 'b' to it. Like // all objects, ObjMaker also has an inaccessible [[prototype]] property // that we can't do anything with obj1 = new ObjMaker(); // 3 things just happened. // A new, empty object was created called obj1. At first obj1 was the same // as {}. The [[prototype]] property of obj1 was then set to the current // object value of the ObjMaker.prototype (if ObjMaker.prototype is later // assigned a new object value, obj1's [[prototype]] will not change, but you // can alter the properties of ObjMaker.prototype to add to both the // prototype and [[prototype]]). The ObjMaker function was executed, with // obj1 in place of this... so obj1.a was set to 'first'. obj1.a; // returns 'first' obj1.b; // obj1 doesn't have a property called 'b', so JavaScript checks // its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype // ObjMaker.prototype has a property called 'b' with value 'second' // returns 'second' 

É como inheritance de class porque agora, qualquer object que você fizer usando o new ObjMaker() também parecerá ter herdado a propriedade ‘b’.

Se você quer algo como uma subclass, faça isso:

 SubObjMaker = function () {}; SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated! // Because we used 'new', the [[prototype]] property of SubObjMaker.prototype // is now set to the object value of ObjMaker.prototype. // The modern way to do this is with Object.create(), which was added in ECMAScript 5: // SubObjMaker.prototype = Object.create(ObjMaker.prototype); SubObjMaker.prototype.c = 'third'; obj2 = new SubObjMaker(); // [[prototype]] property of obj2 is now set to SubObjMaker.prototype // Remember that the [[prototype]] property of SubObjMaker.prototype // is ObjMaker.prototype. So now obj2 has a prototype chain! // obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype obj2.c; // returns 'third', from SubObjMaker.prototype obj2.b; // returns 'second', from ObjMaker.prototype obj2.a; // returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype // was created with the ObjMaker function, which assigned a for us 

Eu li uma tonelada de lixo sobre este assunto antes de finalmente encontrar esta página , onde isso é explicado muito bem com bons diagramas.

Suponha que você tenha essa function:

 var Foo = function(){ this.A = 1; this.B = 2; }; 

Se você chamar isso como uma function autônoma da seguinte forma:

 Foo(); 

Executar esta function adicionará duas propriedades ao object da window ( A e B ). Ele o adiciona à window porque window é o object que chamou a function quando você a executa assim, e this em uma function é o object que chamou a function. Pelo menos em Javascript.

Agora, chame assim com new :

 var bar = new Foo(); 

O que acontece quando você adiciona new a uma chamada de function é que um novo object é criado (apenas var bar = new Object() ) e que o dentro da function aponta para o novo Object você acabou de criar, em vez de para o object chamado a function. Então bar agora é um object com as propriedades A e B Qualquer function pode ser um construtor, nem sempre faz sentido.

Além da resposta de Daniel Howard, aqui está o que o new (ou pelo menos parece fazer):

 function New(func) { var res = {}; if (func.prototype !== null) { res.__proto__ = func.prototype; } var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return ret; } return res; } 

Enquanto

 var obj = New(A, 1, 2); 

é equivalente a

 var obj = new A(1, 2); 

Para iniciantes entender melhor

experimente o seguinte código no console do navegador.

 function Foo() { return this; } var a = Foo(); //returns window object var b = new Foo(); //returns empty object of foo a instanceof Window; // true a instanceof Foo; // false b instanceof Window; // false b instanceof Foo; // true 

Agora você pode ler a resposta do wiki da comunidade 🙂

então provavelmente não é para criar instâncias de object

É usado exatamente para isso. Você define um construtor de function da seguinte forma:

 function Person(name) { this.name = name; } var john = new Person('John'); 

No entanto, o benefício extra que ECMAScript tem é que você pode estender com a propriedade .prototype , para que possamos fazer algo como …

 Person.prototype.getName = function() { return this.name; } 

Todos os objects criados a partir desse construtor agora terão um getName por causa da cadeia de protótipos a que eles têm access.

JavaScript é uma linguagem de programação orientada a objects e é usada exatamente para criar instâncias. É baseado em protótipo, em vez de baseado em class, mas isso não significa que não seja orientado a objects.

Javascript é uma linguagem de programação dinâmica que suporta o paradigma de programação orientada a objects e é usada para criar novas instâncias de objects.

Classes não são necessárias para objects – Javascript é uma linguagem baseada em protótipos .

às vezes o código é mais fácil que palavras:

 var func1 = function (x) { this.x = x; } // used with 'new' only var func2 = function (x) { var z={}; zx = x; return z; } // used both ways func1.prototype.y = 11; func2.prototype.y = 12; A1 = new func1(1); // has A1.x AND A1.y A2 = func1(1); // undefined ('this' refers to 'window') B1 = new func2(2); // has B1.x ONLY B2 = func2(2); // has B2.x ONLY 

para mim, desde que eu não protótipo, eu uso o estilo de func2, pois me dá um pouco mais de flexibilidade dentro e fora da function.

A new palavra-chave é para criar novas instâncias de object. E sim, o javascript é uma linguagem de programação dinâmica, que suporta o paradigma de programação orientada a objects. A convenção sobre a nomenclatura de objects é sempre usar letras maiúsculas para objects que devem ser instanciados pela nova palavra-chave.

 obj = new Element(); 

Já existem algumas respostas muito boas, mas estou postando uma nova para enfatizar minha observação no caso III abaixo sobre o que acontece quando você tem uma declaração de retorno explícita em uma function que você está criando. Veja abaixo os casos:

Caso I :

 var Foo = function(){ this.A = 1; this.B = 2; }; console.log(Foo()); //prints undefined console.log(window.A); //prints 1 

Acima está um simples caso de chamar a function anônima apontada por Foo . Quando você chama essa function, ela retorna undefined . Como não há uma instrução de retorno explícita, o interpretador JavaScript insere forçosamente um return undefined; declaração no final da function. Aqui janela é o object de invocação (contextual this ) que obtém novas propriedades A e B

Caso II :

 var Foo = function(){ this.A = 1; this.B = 2; }; var bar = new Foo(); console.log(bar()); //illegal isn't pointing to a function but an object console.log(bar.A); //prints 1 

Aqui, o intérprete de JavaScript que vê a new palavra-chave cria um novo object que atua como o object de invocação (contextual) da function anônima apontada por Foo . Neste caso, A e B se tornam propriedades no object recém-criado (no lugar do object da janela). Como você não tem nenhuma instrução de retorno explícita, o interpretador JavaScript insere uma instrução de retorno para retornar o novo object criado devido ao uso de uma new palavra-chave.

Caso III :

 var Foo = function(){ this.A = 1; this.B = 2; return {C:20,D:30}; }; var bar = new Foo(); console.log(bar.C);//prints 20 console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword. 

Aqui, novamente, o interpretador JavaScript que vê a new palavra-chave cria um novo object que atua como o object de invocação (contextual) da function anônima apontada por Foo . Novamente, A e B se tornam propriedades no object recém-criado. Mas desta vez você tem uma declaração de retorno explícita, então o interpretador JavaScript não fará nada por si mesmo.

A coisa a notar no caso III é que o object que está sendo criado devido à new palavra-chave se perdeu do seu radar. bar está realmente apontando para um object completamente diferente que não é aquele que o interpretador JavaScript criou devido à new palavra-chave.

Bem JavaScript por si pode diferir muito de plataforma para plataforma, pois é sempre uma implementação da especificação original EcmaScript.

Em qualquer caso, independentemente da implementação, todas as implementações JavaScript que seguem a especificação do EcmaScript, darão a você uma Linguagem Orientada a Objetos. De acordo com o padrão ES:

ECMAScript é uma linguagem de programação orientada a objects para realizar cálculos e manipular objects computacionais dentro de um ambiente de host.

Portanto, agora que concordamos que o JavaScript é uma implementação do EcmaScript e, portanto, é uma linguagem orientada a objects. A definição da new operação em qualquer linguagem orientada a objects, diz que tal palavra-chave é usada para criar uma instância de object de uma class de um certo tipo (incluindo tipos anônimos, em casos como C #).

No EcmaScript nós não usamos classs, como você pode ler nas especificações:

O ECMAScript não usa classs como as do C ++, Smalltalk ou Java. Em vez disso, os objects podem ser criados de várias maneiras, inclusive por meio de uma notação literal ou por meio de construtores que criam objects e, em seguida, executam código que inicializa todos ou parte deles, atribuindo valores iniciais às suas propriedades. Cada construtor é uma function que possui uma propriedade denominada – prototype‖, usada para implementar as propriedades compartilhadas e de inheritance baseadas em protótipo. Objetos são criados por
usando construtores em novas expressões; por exemplo, a nova Data (2009,11) cria um novo object Date. Invocar um construtor sem usar new tem conseqüências que dependem do construtor. Por exemplo, Date () produz uma representação de string da data e hora atuais em vez de um object.

A new palavra-chave altera o contexto no qual a function está sendo executada e retorna um ponteiro para esse contexto.

Quando você não usa a new palavra-chave, o contexto sob o qual a function Vehicle() é executada é o mesmo contexto do qual você está chamando a function Vehicle . A palavra this chave this se referirá ao mesmo contexto. Quando você usa new Vehicle() , um novo contexto é criado para que a palavra this chave this dentro da function se refira ao novo contexto. O que você recebe em troca é o contexto recém-criado.

A new palavra-chave cria instâncias de objects usando funções como um construtor. Por exemplo:

 var Foo = function() {}; Foo.prototype.bar = 'bar'; var foo = new Foo(); foo instanceof Foo; // true 

Instâncias herdam do prototype da function construtora. Então, dado o exemplo acima …

 foo.bar; // 'bar'