La "nuova" parola chiave di JavaScript è considerata dannosa? [chiuso]


568

In un'altra domanda , un utente ha sottolineato che la newparola chiave era pericolosa da usare e ha proposto una soluzione per la creazione di oggetti che non utilizzava new. Non credevo fosse vero, soprattutto perché ho usato Prototype, Scriptaculous e altre eccellenti librerie JavaScript, e tutti usavano la newparola chiave.

Nonostante ciò, ieri stavo guardando il discorso di Douglas Crockford al YUI Theater e ha detto esattamente la stessa cosa, che non ha più usato la newparola chiave nel suo codice ( Crockford su JavaScript - Act III: Function the Ultimate - 50:23 minuti ).

È "cattivo" usare la newparola chiave? Quali sono i vantaggi e gli svantaggi dell'utilizzo?


90
NON è 'male' usare la nuova parola chiave. Ma se lo dimentichi, chiamerai il costruttore di oggetti come una normale funzione. Se il tuo costruttore non controlla il suo contesto di esecuzione, non noterà che 'this' punta a un oggetto diverso (normalmente l'oggetto globale) invece della nuova istanza. Pertanto il costruttore aggiungerà proprietà e metodi all'oggetto globale (finestra). Se controlli sempre che "this" sia un'istanza del tuo oggetto nella funzione object, non avrai mai questo problema.
Kristian B,

5
Non lo capisco Da un lato, Doug non scoraggia l'uso di new. Ma quando guardi la libreria YUI. Devi usare newovunque. Come var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); .
aditya_gaur,

2
@aditya_gaur Questo perché se hai bisogno di inizializzare un oggetto, dovresti hackerare un initmetodo se stai usando l' Object.createapproccio e chiamarlo dopo. Molto più semplice da usare, newche fa entrambe le cose, imposta la catena di prototipi e chiama un codice di inizializzazione.
Juan Mendes,

67
Non penso che questo avrebbe dovuto essere chiuso. Sì, è probabile che ispiri un po 'di veleno anti-fan di Crockford, ma stiamo parlando di consigli popolari per evitare sostanzialmente una caratteristica linguistica importante qui. Il meccanismo che fa pesare quasi nulla su ogni oggetto JQuery (per quanto riguarda la memoria) implica l'uso della parola chiave "new". Preferisci i metodi di fabbrica per invocare costantemente nuovi, ma non ridurre drasticamente le tue opzioni architettoniche e il potenziale delle prestazioni usando solo oggetti letterali. Hanno il loro posto e i costruttori hanno il loro posto. È un consiglio datato e scadente.
Erik Reppen,

2
TLDR: l'utilizzo newnon è pericoloso. L'omissione newè pericolosa e quindi negativa . Ma in ES5 puoi usare la modalità Strict , che ti protegge da quel pericolo e molti altri.
jkdev,

Risposte:


603

Crockford ha fatto molto per diffondere buone tecniche JavaScript. La sua posizione supponente su elementi chiave della lingua ha scatenato molte discussioni utili. Detto questo, ci sono troppe persone che prendono ogni annuncio di "cattivo" o "dannoso" come vangelo, rifiutando di guardare oltre l'opinione di un uomo. A volte può essere un po 'frustrante.

L'uso della funzionalità fornita dalla newparola chiave presenta diversi vantaggi rispetto alla creazione di ogni oggetto da zero:

  1. Eredità del prototipo . Sebbene sia spesso considerata con un mix di sospetto e derisione da parte di coloro che sono abituati ai linguaggi OO di classe, la tecnica di ereditarietà nativa di JavaScript è un mezzo semplice e sorprendentemente efficace di riutilizzo del codice. E la nuova parola chiave è il mezzo canonico (e disponibile solo multipiattaforma) per usarlo.
  2. Prestazione. Questo è un effetto collaterale del n. 1: se voglio aggiungere 10 metodi a ogni oggetto che creo, potrei semplicemente scrivere una funzione di creazione che assegni manualmente ogni metodo a ciascun nuovo oggetto ... Oppure, potrei assegnarli al funzione di creazione prototypee uso newper sradicare nuovi oggetti. Non solo è più veloce (non è necessario alcun codice per ogni singolo metodo sul prototipo), ma evita il palloncino di ogni oggetto con proprietà separate per ciascun metodo. Su macchine più lente (o in particolare su interpreti JS più lenti) quando vengono creati molti oggetti, ciò può significare un notevole risparmio di tempo e memoria.

E sì, newha uno svantaggio cruciale, abilmente descritto da altre risposte: se dimentichi di usarlo, il tuo codice si romperà senza preavviso. Fortunatamente, questo svantaggio è facilmente mitigato: basta aggiungere un po 'di codice alla funzione stessa:

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...
}

Ora puoi avere i vantaggi di newsenza doverti preoccupare dei problemi causati da un uso improprio accidentale. Potresti anche aggiungere un'asserzione al controllo se il pensiero di un codice non funzionante silenziosamente ti disturba. Oppure, come alcuni hanno commentato, utilizzare il segno di spunta per introdurre un'eccezione di runtime:

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

(Si noti che questo frammento è in grado di evitare di codificare il nome della funzione di costruzione in quanto, diversamente dall'esempio precedente, non è necessario istanziare effettivamente l'oggetto, pertanto può essere copiato in ciascuna funzione di destinazione senza modifiche.)

John Resig approfondisce questa tecnica nel suo semplice post sull'istanza "Class" , oltre a includere un mezzo per incorporare questo comportamento nelle "classi" per impostazione predefinita. Sicuramente merita una lettura ... come lo è il suo prossimo libro, Secrets of the JavaScript Ninja , che trova l'oro nascosto in questa e molte altre caratteristiche "dannose" del linguaggio JavaScript (il capitolo su withè particolarmente illuminante per quelli di noi che inizialmente hanno respinto questa caratteristica molto diffamata come un espediente).


96
if (! (this instanceof argument.callee)) throw Error ("Costruttore chiamato come funzione"); // Più generico, non richiede la conoscenza del nome dei costruttori, fai correggere il codice all'utente.
circa il

5
Se sei preoccupato per le prestazioni - e in realtà hai motivo di esserlo - allora non fare affatto il controllo. Ricordati di usare newo usa una funzione wrapper per ricordartelo. Ho il sospetto che se sei nel punto in cui conta, hai già esaurito altre ottimizzazioni come la memoizzazione, quindi le tue chiamate di creazione saranno localizzate comunque ...
Shog9

65
Usare arguments.calleeper verificare se sei stato chiamato con newpotrebbe non essere così buono, dal momento che arguments.calleenon è disponibile in modalità rigorosa. Meglio usare il nome della funzione.
Sean McMillan il

69
Se scrivo erroneamente un identificatore, il mio codice si rompe. Non dovrei usare identificatori? Non usare newperché puoi dimenticare di scriverlo nel tuo codice è altrettanto ridicolo come il mio esempio.
Thomas Eding,

16
Se si attiva la modalità rigorosa, se si dimentica di utilizzare il nuovo si otterrà un'eccezione quando si tenta di utilizzare questo: yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town Questo è più semplice dell'aggiunta di un'istanza di controllo a ciascun costruttore.
Stephenbez,

182

Ho appena letto alcune parti del suo libro di Crockfords "Javascript: The Good Parts". Ho la sensazione che consideri dannoso tutto ciò che lo ha mai morso:

Informazioni su switch fall through:

Non permetto mai che i casi di commutazione passino al caso successivo. Una volta ho trovato un bug nel mio codice causato da una caduta involontaria subito dopo aver fatto un discorso vigoroso sul perché la caduta attraverso a volte era utile. (pagina 97, ISBN 978-0-596-51774-8)

Informazioni su ++ e -

È noto che gli operatori ++ (incremento) e - (decremento) contribuiscono al cattivo codice incoraggiando l'eccessiva inganno. Sono secondi solo all'architettura difettosa nel consentire virus e altre minacce alla sicurezza. (pagina 122)

A proposito di nuovi:

Se si dimentica di includere il nuovo prefisso quando si chiama una funzione di costruzione, questo non sarà associato al nuovo oggetto. Purtroppo, questo sarà legato all'oggetto globale, quindi invece di aumentare il tuo nuovo oggetto, intaserai le variabili globali. È davvero brutto. Non esiste alcun avviso di compilazione e non esiste alcun avviso di runtime. (pagina 49)

Ce ne sono altri, ma spero che tu possa ottenere l'immagine.

La mia risposta alla tua domanda: No, non è dannoso. ma se dimentichi di usarlo quando dovresti potresti avere dei problemi. Se stai sviluppando in un buon ambiente, lo noti.

Aggiornare

Circa un anno dopo la stesura di questa risposta è stata rilasciata la quinta edizione di ECMAScript, con supporto per la modalità rigorosa . In modalità rigorosa, thisnon è più associato all'oggetto globale ma a undefined.


3
Sono completamente d'accordo. La soluzione: documenta sempre come gli utenti devono creare un'istanza dei tuoi oggetti. Usa un esempio e probabilmente gli utenti potranno tagliare / incollare. Ci sono costrutti / caratteristiche in ogni lingua che possono essere utilizzati in modo improprio con conseguente comportamento insolito / imprevisto. Non li rende dannosi.
Nicerobot,

45
Esiste una convenzione per avviare sempre i costruttori con una lettera maiuscola e tutte le altre funzioni con una lettera minuscola.
circa il

61
Ho appena realizzato che Crockford non prendere in considerazione durante nocivi e ... Non so quante volte ho creato un ciclo infinito perché ho dimenticato di incrementare una variabile ...
alcuni

5
Lo stesso vale per ++, -. Esprimono esattamente ciò che intendo nella lingua più chiara possibile. Li adoro! il passaggio da una parte all'altra potrebbe essere chiaro per alcuni, ma sono stanco di quelli. Li uso quando sono chiaramente più chiari ('cuso il gioco di parole, non ho potuto resistere).
PEZ,

30
La mia risposta a Crockford: la programmazione è difficile, andiamo a fare shopping. Sheesh!
Jason Jackson,

91

Javascript è un linguaggio dinamico e ci sono molti modi per rovinare dove un'altra lingua ti fermerebbe.

Evitare una caratteristica del linguaggio fondamentale come quella newsulla base del fatto che potresti incasinare è un po 'come rimuovere le tue nuove scarpe lucide prima di camminare attraverso un campo minato nel caso in cui potresti sporcarle.

Uso una convenzione in cui i nomi delle funzioni iniziano con una lettera minuscola e le "funzioni" che in realtà sono definizioni di classe iniziano con una lettera maiuscola. Il risultato è un indizio visivo abbastanza convincente che la "sintassi" è sbagliata:

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

Oltre a queste buone abitudini di denominazione aiutano. Dopo che tutte le funzioni fanno le cose e quindi dovrebbe esserci un verbo nel suo nome mentre le classi rappresentano oggetti e sono sostantivi e aggettivi senza verbo.

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

È interessante il modo in cui la colorazione della sintassi di SO ha interpretato il codice sopra.


8
Sì, stavo solo pensando la stessa cosa sulla colorazione della sintassi.
BobbyShaftoe,

4
Una volta mi sono dimenticato di digitare la parola "funzione". La parola dovrebbe essere evitata a tutti i costi. Un'altra volta non ho usato parentesi graffe in un'istruzione if / then multilinea. Quindi ora non uso parentesi graffe e scrivo solo condizionali di una riga.
Hal50000,

"Questo è chiaramente sbagliato" . Perché? Per le mie lezioni (che semplicemente fanno if (! this instanceof MyClass) return new MyClass()) preferisco in realtà la newsintassi -less. Perché? Perché le funzioni sono più generiche delle funzioni del costruttore . Uscire newrende facile cambiare una funzione di costruzione in una funzione normale ... O viceversa. L'aggiunta newrende il codice più specifico di quanto deve essere. E quindi meno flessibile. Confronta con Java dove si consiglia di accettare Listanziché in ArrayListmodo che il chiamante possa scegliere l'implementazione.
Stijn de Witt,

41

Sono un principiante di Javascript, quindi forse non sono troppo esperto nel fornire un buon punto di vista a questo. Eppure voglio condividere la mia opinione su questa "nuova" cosa.

Vengo dal mondo C # in cui l'uso della parola chiave "nuovo" è così naturale che è il modello di design di fabbrica che mi sembra strano.

Quando scrivo per la prima volta il codice in Javascript, non mi rendo conto che ci sono la "nuova" parola chiave e il codice come quello nel modello YUI e non mi ci vuole molto a correre in un disastro. Perdo traccia di ciò che una determinata riga dovrebbe fare quando guardo indietro al codice che ho scritto. Più caotico è che la mia mente non può davvero transitare tra i confini delle istanze di oggetto quando sto "eseguendo il dry-run" del codice.

Poi, ho trovato la "nuova" parola chiave che per me "separava" le cose. Con la nuova parola chiave, crea cose. Senza la nuova parola chiave, so che non la confonderò con la creazione di cose a meno che la funzione che sto invocando non mi dia forti indizi.

Ad esempio, con var bar=foo();non ho idea di quale barra potrebbe essere ... È un valore di ritorno o è un oggetto appena creato? Ma con var bar = new foo();lo so per certo che la barra è un oggetto.


3
D'accordo, e credo che il modello di fabbrica dovrebbe seguire una convenzione di denominazione come makeFoo ()
pluckyglen,

3
+1: la presenza di "nuovo" fornisce una dichiarazione di intenti più chiara.
belugabob,

4
Questa risposta è piuttosto strana, quando quasi tutto in JS è un oggetto. Perché è necessario sapere con certezza che una funzione è un oggetto quando tutte le funzioni sono oggetti?
Joshua Ramirez,

@JoshuaRamirez Il punto non è quello typeof new foo() == "object". È che newrestituisce un'istanza di fooe sai che puoi chiamare foo.bar()e foo.bang(). Tuttavia, ciò può essere facilmente mitigato usando @return di JsDoc Non che sto sostenendo il codice procedurale (evitando la parola new)
Juan Mendes

1
@JuanMendes Hmm ... Il tuo post mi ha fatto sembrare che ti piacesse il nuovo a causa della sua parola chiave esplicita nella tua base di codice. Posso scavarlo. Ecco perché uso un modello di modulo. Avrò una funzione chiamata createFoo o NewFoo o MakeFoo, non importa finché è esplicita. All'interno di ciò dichiaro variabili che vengono utilizzate come chiusure all'interno di un oggetto letterale restituito dalla funzione. Quell'oggetto letterale finisce per essere il tuo oggetto e la funzione era solo una funzione di costruzione.
Joshua Ramirez,

39

Un altro caso per il nuovo è quello che io chiamo Pooh Coding . Winnie the Pooh segue la sua pancia. Dico di andare con la lingua che stai usando, non contro di essa.

È probabile che i manutentori della lingua ottimizzeranno la lingua per gli idiomi che cercano di incoraggiare. Se inseriscono una nuova parola chiave nella lingua probabilmente pensano che abbia senso essere chiari quando si crea una nuova istanza.

Il codice scritto seguendo le intenzioni della lingua aumenterà in efficienza con ogni versione. E il codice che evita i costrutti chiave della lingua soffrirà col tempo.

EDIT: E questo va ben oltre le prestazioni. Non riesco a contare le volte che ho sentito (o detto) "perché diavolo hanno fatto quello ?" quando si trova un codice dall'aspetto strano. Si scopre spesso che al momento della stesura del codice c'era una "buona" ragione per questo. Seguire il Tao della lingua è la tua migliore assicurazione per non avere il tuo codice ridicolizzato tra qualche anno.


3
+1 per il link Pooh Coding - ora ho bisogno di trovare delle scuse per lavorare su questo nelle mie conversazioni ...
Shog9

LOL! Ho anni di esperienza in quel particolare campo e posso assicurarti che non troverai difficoltà. Spesso mi chiamano Pooh su robowiki.net. =)
PEZ

1
Non so se vedrai mai questo commento, ma quel link di Pooh Coding è morto.
Calvin,

Grazie per il testa a testa. La settimana scorsa abbiamo migrato robowiki.net in un nuovo wiki e al momento il vecchio contenuto non è raggiungibile. Mi affretterò a far funzionare quei vecchi collegamenti.
PEZ,

24

Ho scritto un post su come mitigare il problema di chiamare un costruttore senza la nuova parola chiave.
È principalmente didattico, ma mostra come è possibile creare costruttori che funzionano con o senza newe non richiedono l'aggiunta di codice boilerplate per testare thisin ogni costruttore.

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

Ecco l'essenza della tecnica:

/**
 * 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() {}
}

Ecco come usarlo:

// 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
evitare arguments.calleeè fantastico!
Gregg Lind,

2
surrogateConstructordovrebbe essere surrogateCtor(o viceversa).
David Conrad,

Ho gestito una raccolta di utilità simili ispirate a Crockford e ho scoperto che mi faceva sempre correre per trovare le implementazioni quando iniziavo un nuovo progetto. E questo avvolge una parte così fondamentale della programmazione: l'istanza di oggetti. Tutto questo lavoro, solo per abilitare il codice di istanza casuale? Apprezzo l'ingenuità di questo wrapper, onestamente, ma sembra solo generare codice incurante.
Joe Coder,

1
@joecoder Ho detto che era solo a scopo didattico, non sottoscrivo questo stile di codifica paranoico. Tuttavia, se stavo scrivendo una biblioteca di classe, sì, aggiungerei questa funzione in modo trasparente per i chiamanti
Juan Mendes,

22

La logica alla base del mancato utilizzo della nuova parola chiave è semplice:

Non utilizzandolo affatto, si evita la trappola che si manifesta con l'omissione accidentale. Il modello di costruzione utilizzato da YUI è un esempio di come è possibile evitare del tutto la nuova parola chiave "

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

In alternativa potresti farlo così:

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

Ma così facendo corri il rischio che qualcuno si dimentichi di usare la nuova parola chiave e che questo operatore sia completamente fubar. AFAIK non ha alcun vantaggio nel fare questo (a parte quello a cui sei abituato).

Alla fine del giorno: si tratta di essere sulla difensiva. Puoi usare la nuova dichiarazione? Sì. Rende il tuo codice più pericoloso? Sì.

Se hai mai scritto C ++, è come impostare i puntatori su NULL dopo averli eliminati.


6
No. Con "new foo ()" alcune proprietà sono impostate sull'oggetto restituito, come il costruttore.
circa il

34
Quindi, solo per chiarire questo: non dovresti usare il "nuovo" perché potresti dimenticarlo? Stai scherzando, vero?
Bombe,

16
@Bombe: in altre lingue la dimenticanza di "nuovo" comporterebbe un errore. In Javascript, continua a trasportare camion. Puoi dimenticare e non realizzare mai. E semplicemente guardare un codice errato non sarà affatto ovvio che cosa vada storto.
Kent Fredric,

3
@Greg: non vedo come la prima tecnica consenta l'uso di catene prototipo - i letterali di oggetti sono fantastici, ma buttare via le prestazioni e altri vantaggi forniti dai prototipi per paura sembra un po 'sciocco.
Shog9

5
@Bombe - Dovresti usare "nuovo" perché tu (e chiunque utilizzi il tuo codice) non commetterai mai un errore? Stai scherzando, vero?
Greg Dean,

20

Penso che "nuovo" aggiunga chiarezza al codice. E la chiarezza vale tutto. Buono a sapersi che ci sono insidie, ma evitarle evitando la chiarezza non mi sembra la strada giusta.


16

Caso 1: newnon è richiesto e dovrebbe essere evitato

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è obbligatorio, altrimenti verrà visualizzato un errore

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

5
Va notato che nel caso 1, chiamare il costruttore come una funzione ha senso solo se si intende la conversione del tipo (e non si sa se l'oggetto dello scafo ha un metodo di conversione, come toString()). In tutti gli altri casi, utilizzare valori letterali. Non String('asd') , ma semplicemente 'asd', e non Number(12) , ma semplicemente 12.
Punta orecchie

1
@PointedEars Un'eccezione a questa regola sarebbe Array: Array(5).fill(0) è ovviamente più leggibile di [undefined, undefined, undefined, undefined, undefined].fill(0)e(var arr = []).length = 5; arr.fill(0);
yyny il

@YoYoYonnY La mia affermazione è stata fatta nel contesto del caso 1 della risposta, che si riferisce all'uso di newcon costruttori per tipi di oggetti corrispondenti a tipi primitivi . Il valore letterale che stai suggerendo non equivale alla Arraychiamata (prova 0 in …) e il resto è un errore di sintassi :) Altrimenti hai ragione, anche se va notato che Array(5)può essere ambiguo se consideri implementazioni non conformi (e quindi un emulato Array.prototype.fill(…) ).
Pointed Ears

12

Ecco il sommario più breve che potrei fare dei due argomenti più forti a favore e contro l'uso newdell'operatore:

Discussione contro new

  1. Le funzioni progettate per essere istanziate come oggetti mediante l' newoperatore possono avere effetti disastrosi se vengono invocate in modo errato come normali funzioni. Il codice di una funzione in tal caso verrà eseguito nell'ambito in cui viene chiamata la funzione, anziché nell'ambito di un oggetto locale come previsto. Ciò può causare la sovrascrittura di variabili e proprietà globali con conseguenze disastrose.
  2. Infine, scrivere function Func(), quindi chiamare Func.prototype e aggiungere elementi in modo da poter chiamare new Func()per costruire il tuo oggetto sembra brutto per alcuni programmatori, che preferiscono utilizzare un altro stile di eredità dell'oggetto per motivi architettonici e stilistici.

Per ulteriori informazioni su questo argomento, consulta il fantastico e conciso libro di Douglas Crockford, Javascript: The Good Parts. In effetti, controlla comunque.

Argomento a favore di new

  1. L'uso newdell'operatore insieme all'assegnazione dei prototipi è rapido.
  2. Quelle cose sull'esecuzione accidentale del codice di una funzione di costruzione nello spazio dei nomi globale possono essere facilmente evitate se si include sempre un po 'di codice nelle funzioni di costruzione per verificare se vengono chiamate correttamente e, nei casi in cui non lo sono , gestendo la chiamata in modo appropriato come desiderato.

Vedi il post di John Resig per una semplice spiegazione di questa tecnica e per una spiegazione generalmente più profonda del modello di eredità che sostiene.


Un aggiornamento sugli argomenti 'use strict';opposti : # 1 può essere mitigato usando mode (o il metodo nel tuo link) # 2 Ha zucchero sinatico in ES6 , tuttavia il comportamento è lo stesso di prima.
ninMonkey,

9

Sono d'accordo con Pez e alcuni qui.

Mi sembra ovvio che "nuovo" sia la creazione di oggetti auto-descrittivi, in cui il modello YUI descritto da Greg Dean è completamente oscurato .

La possibilità che qualcuno possa scrivere var bar = foo;o var bar = baz();dove baz non è un metodo di creazione di oggetti sembra molto più pericolosa.


8

Penso che il nuovo sia malvagio, non perché se si dimentica di usarlo per errore potrebbe causare problemi, ma perché rovina la catena ereditaria, rendendo il linguaggio più difficile da capire.

JavaScript è orientato agli oggetti basato su prototipo. Quindi ogni oggetto DEVE essere creato da un altro oggetto in questo modo var newObj=Object.create(oldObj). Qui oldObj è chiamato il prototipo di newObj (quindi "basato sul prototipo"). Ciò implica che se una proprietà non viene trovata in newObj , verrà cercata in oldObj . newObj di default sarà quindi un oggetto vuoto ma a causa della sua catena di prototipi sembra avere tutti i valori di oldObj .

D'altra parte, se lo fai var newObj=new oldObj(), il prototipo di newObj è oldObj.prototype , che è inutilmente difficile da capire.

Il trucco è usare

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

È all'interno di questa funzione e solo qui dovrebbe essere usato il nuovo. Dopodiché usa semplicemente il metodo Object.create () . Il metodo risolve il problema del prototipo.


7
Ad essere sincero, non sono pazzo di questa tecnica: non aggiunge nulla di nuovo e, come dimostra la tua risposta, può persino finire per essere una stampella. IMHO, comprendere le catene di prototipi e la creazione di istanze di oggetti è fondamentale per comprendere JavaScript ... Ma se ti mette a disagio a usarli direttamente, allora usare una funzione di aiuto per occuparti di alcuni dettagli va bene, purché ricordi cosa stai facendo. FWIW: una variazione (un po 'più utile) su questo fa parte del quinto ed. ECMAScript. standard e già disponibile in alcuni browser, quindi dovresti stare attento a non ridefinirlo alla cieca!
Shog9

A proposito: non sono sicuro del motivo per cui hai creato questo CW, ma se vuoi ripubblicarlo con le correzioni di formattazione che ho fatto, fai attenzione a evitare quella casella di controllo ...
Shog9

2
Inutilmente difficile da capire? var c = new Car()è lo stesso che farevar c = Object.create(Car.prototype); Car.call(c)
Juan Mendes
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.