2012-11-05 12 views
7

Sto lavorando a un progetto JavaScript e mi chiedevo solo perché un'istanza dell'oggetto non eredita lo defineProperty() e altri metodi, piuttosto che dover chiamare il metodo superclasse (superoggetto?) Object.Perché Object.defineProperty() piuttosto che this.defineProperty() (per oggetti)?

Ho esaminato lo MDN docs e ci sono in effetti metodi di proprietà "non standard".

Ma quelli sono deprecati. Perché il passaggio dovrebbe essere ai metodi Object?

Mi sembra che qualcosa come instance.defineProperty(...) sia meglio di Object.defineProperty(instance, ...). Direi lo stesso anche su alcuni degli altri metodi Object.

+0

strettamente correlati: [Perché sono stati i metodi degli oggetti ES5 non aggiunto al Object.prototype?] (Http: // StackOverflow. it/q/9735026/1048572) – Bergi

risposta

7

È per evitare collisioni: in generale, problemi con oggetti che non hanno la proprietà con il valore che ci si aspetta.
Gli oggetti in JS vengono spesso utilizzati come mappe valore-chiave e le chiavi possono essere stringhe arbitrarie, ad esempio __defineGetter__, hasOwnProperty o qualcosa di meno speciale. Ora quando vuoi invocare una funzione di questo tipo su un oggetto sconosciuto - come hasOwnProperty viene spesso usata nelle funzioni di enumerazione generica, dove può essere passato qualsiasi JSON - non puoi mai essere sicuro se hai una proprietà sovrascritta (che potrebbe anche non essere una funzione) o l'originale che si desidera, o se l'oggetto eredita la proprietà. Per evitare questo problema (o anche this IE bug), dovresti usare Object.prototype.hasOwnProperty.call - che è brutto.

Quindi, il namespace di tutte quelle funzioni su Object è utile solo, è un'API più pulita che separa i metodi di riflessione dall'interfaccia dell'applicazione dell'oggetto. Ciò aiuta anche l'ottimizzazione (semplificando l'analisi statica) e semplifica la limitazione dell'accesso all'API di riflessione nelle sandbox, almeno lo design idea.

Si potrebbe essere contenti di avere un defineProperty nel prototipo, ma è possibile utilizzarlo in modo sicuro solo quando si lavora con oggetti noti. Se si vuole ancora (come si sa quando usare e quando non), è possibile utilizzare

Object.defineProperty(Object.prototype, "defineProperty", { 
    writable: true, 
    enumberable: false, 
    value: function(prop, descr) { 
     return Object.defineProperty(this, prop, descr); 
    } 
}); 
+7

Vale anche la pena notare che gli oggetti non devono ereditare da 'Object.prototype' in ES5. Possono ereditare dal nulla tramite 'Object.create (null)', oppure possono ereditare da un oggetto che eredita da 'null'. Questo è un comportamento molto utile, ma se un oggetto non eredita da 'Object.prototype', non avrà metodi definiti su' Object.prototype'.Qualsiasi libreria che voglia usare 'defineProperty' genericamente dovrebbe fare' var defineProperty = Function.prototype.call.bind (Object.prototype.defineProperty); ', quindi ha senso solo definirlo come una funzione di utilità in ogni caso invece di un metodo. –

+1

@Nathan: ottimi punti, grazie. – Bergi

+0

In realtà, la vera ragione è per sandboxing e una migliore API - potrei provarlo ma "rationale_for_es3_1_static_object_methodsaug26.pdf" è morto. –

2

Interessante. L'unica ragione per cui sono arrivato finora è che alla gente piace riscrivere i prototipi e avere questo metodo "nascosto" come questo potrebbe aiutarti a evitare alcuni bug. Soprattutto a causa del buon nome del metodo poiché è più probabile che venga riscritto rispetto, ad esempio, a __defineGetter__.

Sembra che molte funzionalità dipendano da questa funzionalità (link), quindi ha senso renderlo più globale e sicuro in questo contesto.

2

E 'fatto così per evitare collisioni - ricorda, ogni metodo su Object.prototype è un metodo anche in ogni singolo oggetto definito dall'utente.

Immaginate un oggetto in cui volete un metodo personalizzato defineProperty - che si romperebbe completamente quando Object.defineProperty era sul suo prototipo.

Problemi correlati