Qual é o motivo para usar a palavra-chave ‘new’ em Derived.prototype = new Base

O que faz o seguinte código:

WeatherWidget.prototype = new Widget; 

onde Widget é um construtor, e eu quero estender o Widget ‘class’ com uma nova function WeatherWidget .

Qual é a new palavra-chave lá e o que aconteceria se fosse deixada de fora?

 WeatherWidget.prototype = new Widget; 

A new palavra-chave chama Widget como um construtor e o valor de retorno é atribuído à propriedade prototype . (Se você omitir new , você não chamaria Widget menos que você adicionasse uma lista de argumentos, () . No entanto, chamar Widget dessa maneira pode não ser possível. Certamente teria o potencial de estragar o namespace global se não for modo estrito código e a implementação está em conformidade com ECMAScript Ed. 5.x lá, porque então this no construtor se referiria ao object global do ECMAScript.)

Mas essa abordagem realmente vem de um mau exemplo realmente viral no antigo Netscape JavaScript 1.3 Guide (espelhado no Oracle, anteriormente Sun).

Dessa forma, todas as suas instâncias WeatherWidget herdarão da mesma instância do Widget . A cadeia de protótipos será:

 [new WeatherWidget()] → [new Widget()] → [Widget.prototype] → … 

Isso pode ser útil, mas na maioria das vezes você não gostaria que isso acontecesse. Você não deve fazer isso aqui, a menos que queira que todas as suas instâncias WeatherWidget compartilhem entre si os valores de propriedade que eles herdam dessa instância do Widget , e somente através dela , a partir do Widget.prototype . Outro problema é que você precisa chamar o construtor pai dessa maneira, o que pode não permitir ser chamado sem argumentos como você faz, ou não inicializar corretamente. Certamente não tem nada a ver com a emulação de inheritance baseada em classs como conhecida, por exemplo, a partir de Java.

A maneira correta de implementar a inheritance baseada em classs nessas linguagens baseadas em protótipos é (originalmente concebida por Lasse Reichstein Nielsen em comp.lang.javascript em 2003, para clonagem de objects ):

 function Dummy () {} Dummy.prototype = Widget.prototype; WeatherWidget.prototype = new Dummy(); WeatherWidget.prototype.constructor = WeatherWidget; 

A propriedade prototype do constructor deve ser corrigida também, para que suas instâncias WeatherWidget w tenham w.constructor === WeatherWidget conforme o esperado, e não w.constructor === Widget . No entanto, esteja ciente de que é enumerável depois.

Dessa forma, WeatherWidget instâncias WeatherWidget herdarão propriedades por meio da cadeia de protótipos, mas não compartilharão valores de propriedade entre elas, pois elas herdam de Widget.prototype por meio de Dummy que não possui propriedades próprias:

 [new WeatherWidget()] → [new Dummy()] → [Widget.prototype] → … 

Em implementações do ECMAScript Ed. 5 e mais tarde, você pode e deve usar

 WeatherWidget.prototype = Object.create(Widget.prototype, { constructor: {value: WeatherWidget} }); 

em vez de. Isso tem a vantagem adicional de que a propriedade do constructor resultante não é gravável, enumerável ou configurável .

O construtor pai será chamado apenas se você o chamar explicitamente, a partir de WeatherWidget , por exemplo com

 function WeatherWidget (…) { Widget.apply(this, arguments); } 

Veja também Function.prototype.extend() no meu JSX: object.js para como generalizar isso. Usando esse código, ele se tornaria

 WeatherWidget.extend(Widget); 

Meu Function.prototype.extend() usa um segundo argumento opcional com o qual você pode aumentar facilmente o protótipo de instâncias WeatherWidget :

 WeatherWidget.extend(Widget, { foo: 42, bar: "baz" }); 

seria equivalente a

 WeatherWidget.extend(Widget); WeatherWidget.prototype.foo = 42; WeatherWidget.prototype.bar = "baz"; 

Você ainda precisará chamar o construtor pai explicitamente no construtor filho; essa parte não pode ser razoavelmente automatizada. Mas meu Function.prototype.extend() adiciona uma propriedade _super à instância Function que facilita:

 function WeatherWidget (…) { WeatherWidget._super.apply(this, arguments); } 

Outras pessoas implementaram extensões semelhantes.

De acordo com algumas regras de Javascript estranhas, o new Widget invoca o construtor em vez de retornar uma referência ao construtor. Esta pergunta realmente responde à questão da diferença entre var a = new Widget() e var a = Widget() .

Em palavras simples, a new palavra-chave diz ao Javascript para chamar a function Widget sob um conjunto de regras diferente de uma chamada de function normal. Saindo do topo da minha cabeça, os que eu lembro são:

  1. Existe um novo object criado
  2. Widget pode usar a palavra-chave this para se referir a esse object.
  3. Se Widget não retornar nada, esse novo object será criado.
  4. Esse object herdará algumas propriedades adicionais que indicarão que ele foi criado pelo Widget usado para rastrear cadeias de propriedades.

Sem a new palavra-chave, uma chamada para widget seria

  1. Se estiver no modo estrito, this será definido como undefined.
  2. Caso contrário, this se referirá ao object global. ( window chamada pelo navegador.)
  3. Se a function não retornar nada, a undefined será retornada.

Referência: new palavra-chave

 WeatherWidget.prototype = new Widget; 

cria uma nova instância do construtor Widget e a usa como object de protótipo do WeatherWidget . O uso da new palavra-chave cria o novo object, configura a cadeia de inheritance dele para Widget.prototype e aplica a function construtora a ele (onde é possível configurar propriedades individuais e Widget.prototype ou criar variables ​​com escopo particular).

Sem a new palavra-chave, seria uma atribuição da function Widget à propriedade prototype – o que não faz sentido. Se você adicionasse os colchetes opcionais (ou seja, Widget() ), ele invocaria a function normalmente, mas não como um construtor em uma nova instância, mas com o object global como contexto. Veja também a referência para this palavra this chave .

Observe que você não deve realmente usar esse código. Como dito, cria uma nova instância invocando a function construtora. Mas o propósito é apenas criar um object vazio que herda do object de protótipo do Widget , não instanciar algo (o que poderia causar algum dano, dependendo do código). Em vez disso, você deve usar Object.create (ou seu shim popular ):

 WeatherWidget.prototype = Object.create(Widget.prototype); 

veja também inheritance básica de Javascript contra inheritance prototípica de Crockford

Em inglês simples, você está estendendo uma aula para outra. Um protótipo só pode ser um object, então você configura o protótipo do WeatherWidget para uma nova instância do Widget . Se você removesse a new palavra-chave, estaria configurando o protótipo para a function de construtor literal que não faz nada.

 var Appendages = function(){ this.legs = 2 }; var Features = function() { this.ears = 4; this.eyes = 1; } // Extend Features class with Appendages class. Features.prototype = new Appendages; var sara = new Features(); sara.legs; // Returns 2. 

Entendendo que o protótipo pode ser qualquer object, algo assim também funcionaria:

 var appendages = { legs : 2 }; var Features = function() { this.ears = 4; this.eyes = 1; } // Extend Features class with Appendages class. Features.prototype = appendages; var sara = new Features(); sara.legs; // Returns 2. 

Em JavaScript, se a chave não for encontrada no object, ele verifica o object pais do qual você o expandiu. Assim, você pode alterar itens no object pai na hora da seguinte forma:

 var appendages = { legs : 2 }; var Features = function() { this.ears = 4; this.eyes = 1; } // Extend Features class with Appendages class. Features.prototype = appendages; var sara = new Features(); sara.legs; // Returns 2. appendages.hair = true; sara.hair; // Returns true. 

Note que tudo isso acontece durante a instanciação, o que significa que você não pode simplesmente trocar o protótipo depois de criar o object:

 var foo = {name : 'bob'}; var bar = {nachos : 'cheese'}; foo.prototype = bar; foo.nachos; // undefined 

No entanto, todos os navegadores modernos vêm com este novo método __proto__ , que permite que você faça isso:

 var foo = {name : 'bob'}; var bar = {nachos : 'cheese'}; foo.__proto__ = bar; foo.nachos // "cheese" 

Leia mais sobre como entender os protótipos JavaScript aqui . Este artigo da Pivotal Labs também é muito bom.

new é importante para a inheritance de protótipo ; ou seja
Crie um construtor com um método

 var Obj = function(){}; Obj.prototype = {}; Obj.prototype.foo = function(){console.log('foo');}; 

Faça um segundo construtor para estender o primeiro com

 var ExObj = function(){}; 

Agora, se nós prototipamos sem new ,

 ExObj.prototype = Obj; (new ExObj).foo(); // TypeError: Object # has no method 'foo' 

O que significa que nós não herdamos do protótipo do Obj , no entanto, se nós prototipamos com new

 ExObj.prototype = new Obj(); (new ExObj).foo(); // console logs 'foo' 

Além disso, adicionar novas coisas ao protótipo do ExObj não faz nenhuma alteração na sua base, o Obj .

As funções JavaScript são “MÚLTIPLAS (2) PERSONALIDADES” !!!

São funções regulares com input e saída, que chamamos de function() .

Também são construtores de objects JS, quando usamos a new palavra-chave. >>> MAS <<< os novos objetos criados são NOT INSTANCES dos construtores (como os objetos de classes na herança baseada em classes). Os novos objetos são instâncias do objeto da propriedade prototype do construtor.

Então, em WeatherWidget.prototype = você coloca o object que deseja herdar suas propriedades para os objects que o construtor irá criar, o que geralmente é uma new function() e não uma function.

O JavaScript criou uma enorme confusão na comunidade de programação, nomeando os objects criados pelos construtores, INSTANCES deles com a palavra-chave instanceof .
> function f(){}
undefined
> new f() instanceof f
true