Similitudine concettuale tra i modelli di eredità di Ruby e di JavaScript

1

Per eliminare qualche potenziale confusione, lasciatemi iniziare con le seguenti dichiarazioni

  • Per quanto ho capito, l'ereditarietà riguarda principalmente l'invio dinamico.
  • Capisco come funziona l'ereditarietà basata sulla tabella puntatore virtuale e presumo che questo sia ciò a cui si riferisce l'ereditarietà "classica".
  • Presumo che l'ereditarietà "pura" di classe OO in stile si riferisca all'ereditarietà classica o alle ricerche di metodi basati su tabelle hash.
  • Capisco come funziona l'ereditarietà prototipica e come sia fondamentalmente diversa dall'ereditarietà basata sulla classe.
  • So come Ruby ha costanti, variabili di istanza, variabili di classe, classi di singleton, ecc. che si comportano diversamente dai metodi in termini di ereditarietà e ricerca. Questa domanda si concentra sulla ricerca del metodo.
  • So come i metodi non sono cittadini di prima classe in Ruby rispetto alle funzioni di JavaScript.
  • So che JavaScript ha valori diversi dagli oggetti e che Ruby non lo fa.

Nessuna delle lingue menzionate usa ciò che io chiamo ereditarietà di classe.

La cosa che mi dà fastidio è che le persone sembrano riferirsi a cose simili usando termini contrastanti. So come funziona la ricerca delle proprietà di JavaScript e la considero strettamente correlata a come funziona la ricerca dei metodi di Ruby. La domanda è mirata alla differenza tra ciò che è etichettato come "eredità prototipica" con la ricerca basata su prototipo e "l'ereditarietà OO basata sulla classe" con la ricerca basata sulla superclasse.

In sostanza, un prototipo JavaScript sembra comportarsi come una classe Ruby in termini di ricerca del metodo (con l'eccezione che Ruby attraversa anche i moduli inclusi), tuttavia sento spesso che Ruby è puramente orientato agli oggetti e JavaScript non ha 'vera' eredità. La differenza concettuale che vedo è che gli oggetti funzione di prima classe di JavaScript usano la stessa ricerca di qualsiasi altro valore, mentre la ricerca del metodo di Ruby ovviamente funziona solo sui metodi.

Per parafrasare, quando si esegue l'espressione obj.method() , JavaScript non sa che sta cercando una funzione in obj , trova semplicemente un valore (magari usando anche un getter) e prova a chiamarlo, mentre Ruby sa Cerca un metodo e usa le regole per la ricerca del metodo. La differenza è leggermente più evidente quando "method ()" non è preceduto da un punto, JavaScript quindi cerca una variabile racchiudendo gli ambiti lessicali, mentre Ruby cerca l'ambito corrente per le variabili locali e varie superclassi per i metodi.

-

La prima differenza pratica che viene in mente è che AFAIK non ha una vera analogia basata su OO con il codice sottostante, e che Ruby sembra simulare questa mancanza usando regole complicate cercando in modo diverso tipi di simboli diversi pur essendo come dinamico possibile.

class A { // Some base class
  print() {
    // this.props is used. If this was a function call it could easily be implemented in Ruby.
    console.log(this.prop); // the this-binding stays the same
  }
}

A.prototype.prop = 'A'; // Define <prop> in the base prototype.

class B extends A {}

instance = new B();
instance.print(); // 'A'

B.prototype.prop = 'B'; // Define <prop> in the inherited prototype
instance.print(); // 'B'

instance.prop = 'instance'; // Define <prop> in the object itself
instance.print(); // 'instance'

Tuttavia, i seguenti esempi di codice sono molto simili nel loro funzionamento.

class A # Some base class
  def print
    puts 'A'
  end
end

class B < A; end # 'real' inheritance
class C < B; end # ditto

instance = C.new
instance.print # 'A'

class B
  def print # Shadowing of <print> in the top class
    puts 'B'
  end
end

instance.print # 'B'

class C
  def print # Shadowing in the middle class
    puts 'C'
  end
end

instance.print # 'C'

def instance.print # Shadowing using a singleton method
  puts 'instance'
end

instance.print # 'instance'
class A {
  print() {
    console.log('A');
  }
}

class B extends A {}
class C extends B {}

instance = new C()
instance.print() // 'A'

B.prototype.print = function print() { // Shadowing of <print> in the top prototype
  console.log('B');
}

instance.print() // 'B'

C.prototype.print = function print() { // Shadowing in the middle prototype
  console.log('C');
}

instance.print(); // 'C'

instance.print = function print() { // Shadowing using the object itself
  console.log('instance');
}

instance.print(); // 'instance'

Il codice qui sopra, cioè essere in grado di utilizzare metodi con collegamenti dinamici e di restringere gradualmente il loro percorso di ricerca, rappresenta l'unica somiglianza tra i due modelli di ereditarietà?

    
posta Ianis Vasilev 12.08.2016 - 16:31
fonte

0 risposte

Leggi altre domande sui tag