basato sul prototipo e sull’eredità basata sulla class

In JavaScript, ogni object è allo stesso tempo un’istanza e una class. Per fare ereditarietà, puoi usare qualsiasi istanza di object come prototipo.

In Python, C ++, ecc. Ci sono classi e istanze, come concetti separati. Per fare ereditarietà, devi usare la class base per creare una nuova class, che può quindi essere usata per produrre istanze derivate.

Perché JavaScript è andato in questa direzione (orientamento dell’object basato su prototipo)? quali sono i vantaggi (e gli svantaggi) dell’OO basato sul prototipo rispetto all’OO tradizionale basato su classi?

Ci sono circa un centinaio di problemi terminologici qui, per lo più costruiti attorno a qualcuno (non tu) che cerca di far sembrare la loro idea come The Best.

Tutti i linguaggi object oriented devono essere in grado di gestire diversi concetti:

  1. incapsulamento dei dati insieme alle operazioni associate sui dati, variamente noti come membri dei dati e funzioni dei membri, o come dati e metodi, tra le altre cose.
  2. l’ereditarietà, la capacità di dire che questi oggetti sono proprio come quell’altro set di oggetti, ECCEZIONE per questi cambiamenti
  3. polimorfismo (“molte forms”) in cui un object decide da solo quali metodi devono essere eseguiti, in modo che si possa dipendere dalla lingua per indirizzare correttamente le richieste.

Ora, per quanto riguarda il confronto:

La prima cosa è l’intera domanda “class” vs “prototipo”. L’idea originariamente iniziava in Simula, dove con un metodo basato sulla class ogni class rappresentava un insieme di oggetti che condividevano lo stesso spazio di stato (leggi “possibili valori”) e le stesse operazioni, formando così una class di equivalenza. Se guardi indietro a Smalltalk, dato che puoi aprire una class e aggiungere metodi, questo è effettivamente lo stesso di quello che puoi fare in Javascript.

Successivamente i linguaggi OO volevano essere in grado di utilizzare il controllo di tipo statico, quindi abbiamo ottenuto la nozione di una serie fissa impostata in fase di compilazione. Nella versione open-class, hai avuto più flessibilità; nella versione più recente, avevi la possibilità di verificare alcuni tipi di correttezza nel compilatore che altrimenti avrebbero richiesto test.

In un linguaggio “class-based”, la copia avviene al momento della compilazione. In un linguaggio prototipo, le operazioni vengono memorizzate nella struttura dei dati prototipo, che viene copiata e modificata in fase di esecuzione. In astratto, però, una class è ancora la class di equivalenza di tutti gli oggetti che condividono lo stesso spazio e metodi dello stato. Quando aggiungi un metodo al prototipo, stai effettivamente creando un elemento di una nuova class di equivalenza.

Ora, perché farlo? principalmente perché rende un meccanismo semplice, logico, elegante in fase di esecuzione. ora, per creare un nuovo object o per creare una nuova class, è sufficiente eseguire una copia profonda, copiando tutti i dati e la struttura dei dati del prototipo. L’ereditarietà e il polimorfismo si ottengono più o meno gratuitamente: la ricerca del metodo consiste sempre nel chiedere un dizionario per un’implementazione del metodo per nome.

La ragione per cui è stato scritto Javascript / ECMA è che quando abbiamo iniziato 10 anni fa, avevamo a che fare con computer meno potenti e browser meno sofisticati. La scelta del metodo basato sul prototipo significava che l’interprete poteva essere molto semplice pur preservando le proprietà desiderabili dell’orientamento dell’object.

Un confronto, che è leggermente sbilanciato verso l’approccio basato sui prototipi, potrebbe essere trovato nella carta – Self: The power of simplicity . Il documento formula i seguenti argomenti a favore dei prototipi:

Creazione copiando . La creazione di nuovi oggetti dai prototipi viene eseguita con una semplice operazione, copiando, con una semplice metafora biologica, la clonazione. La creazione di nuovi oggetti dalle classi viene eseguita mediante l’istanziazione, che include l’interpretazione delle informazioni sul formato in una class. L’istanziazione è simile alla costruzione di una casa da un piano. La copia ci attrae come metafora più semplice dell’istanza.

Esempi di moduli preesistenti . I prototipi sono più concreti delle classi perché sono esempi di oggetti piuttosto che descrizioni di formato e inizializzazione. Questi esempi possono aiutare gli utenti a riutilizzare i moduli rendendoli più facili da capire. Un sistema basato su prototipi consente all’utente di esaminare un rappresentante tipico piuttosto che richiedere che abbia un senso dalla sua descrizione.

Supporto per oggetti unici nel loro genere . Il sé fornisce un quadro che può facilmente includere oggetti unici nel loro genere con il proprio comportamento. Poiché ogni object ha un nome slot e gli slot possono contenere lo stato o il comportamento, qualsiasi object può avere slot o comportamenti univoci. I sistemi basati su classi sono progettati per le situazioni in cui vi sono molti oggetti con lo stesso comportamento. Non esiste alcun supporto linguistico per un object che possieda il proprio comportamento univoco, ed è scomodo (si pensi al modello Singleton ) per creare una class a cui è garantito avere una sola istanza. Il sé soffre di nessuno di questi svantaggi. Qualsiasi object può essere personalizzato con il proprio comportamento. Un object unico può contenere il comportamento univoco e non è necessaria una “istanza” separata.

Eliminazione del meta-regresso . Nessun object in un sistema basato su classi può essere autosufficiente; un altro object (la sua class) è necessario per esprimere la sua struttura e il suo comportamento. Questo porta ad un meta-regressore concettualmente infinito: un point è un’istanza di Point di class, che è un’istanza di Metaclass Point , che è un’istanza di Metametaclass Point , ad infinitum. D’altra parte, nei sistemi basati su prototipi un object può includere il proprio comportamento; nessun altro object è necessario per respirare la vita in esso. I prototipi eliminano il meta-regresso.

Self è probabilmente la prima lingua per implementare i prototipi. (È stato anche pioniere di altre tecnologie interessanti come JIT, che in seguito si sono fatte strada verso la JVM. Quindi leggere gli altri articoli di Self dovrebbe essere anche istruttivo).

Dovresti dare un’occhiata a un grande libro su JavaScript di Douglas Crockford . Fornisce un’ottima spiegazione di alcune delle decisioni progettuali prese dai creatori di JavaScript.

Uno degli aspetti importanti della progettazione di JavaScript è il suo prototipale sistema di ereditarietà. Gli oggetti sono cittadini di prima class in JavaScript, così tanto che anche le funzioni regolari vengono implementate come oggetti (l’object ‘Funzione’ è preciso). Secondo me, quando era stato originariamente progettato per funzionare all’interno di un browser, era pensato per essere utilizzato per creare molti oggetti singleton. Nel DOM del browser, trovi quella finestra, il documento ecc. Tutti gli oggetti singleton. Inoltre, JavaScript è un linguaggio dinamico a caratteri generici (al contrario di Python che è fortemente tipizzato, linguaggio dinamico), di conseguenza, un concetto di estensione dell’object è stato implementato attraverso l’uso della proprietà ‘prototype’.

Quindi penso che ci siano alcuni pro per OO basati su prototipi come implementati in JavaScript:

  1. Adatto in ambienti con caratteri generici, non è necessario definire tipi espliciti.
  2. Rende incredibilmente facile implementare il modello singleton (confronta JavaScript e Java a questo proposito e saprai di cosa sto parlando).
  3. Fornisce modi per applicare un metodo di un object nel contesto di un object diverso, aggiungendo e sostituendo metodi in modo dinamico da un object ecc. (Cose che non sono possibili in lingue fortemente tipizzate).

Ecco alcuni degli aspetti negativi di OO prototipo:

  1. Non è un modo semplice per implementare variabili private. È ansible implementare le private vars usando la magia di Crockford usando le chiusure , ma sicuramente non è così banale come usare variabili private come Java o C #.
  2. Non so ancora come implementare più eredità (per quello che vale) in JavaScript.