Vorrei sapere cosa hanno in comune uomo e bambino e come differiscono.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Vorrei sapere cosa hanno in comune uomo e bambino e come differiscono.
class Person {
name: string;
age: number;
}
class child extends Person {}
class man implements Person {}
Risposte:
extends
si intende:La nuova classe è un bambino . Ottiene vantaggi derivanti dall'eredità. Ha tutte le proprietà, i metodi come genitore. Può sovrascrivere alcuni di questi e implementarne di nuovi, ma il materiale genitore è già incluso.
implements
si intende:La nuova classe può essere trattata come la stessa "forma" , mentre non è un bambino . Potrebbe essere passato a qualsiasi metodo in cui Person
è richiesto, indipendentemente dal fatto che abbia un genitore diverso daPerson
In OOP (linguaggi come C #, Java) useremmo
extends
trarre profitto dall'eredità (vedi wiki ). Piccola citazione:
... L'ereditarietà nella maggior parte dei linguaggi orientati agli oggetti basati su classi è un meccanismo in cui un oggetto acquisisce tutte le proprietà e i comportamenti dell'oggetto genitore. L'ereditarietà consente ai programmatori di: creare classi basate su classi esistenti ...
implements
sarà più per il polimorfismo (vedi wiki ). Piccola citazione:
... il polimorfismo è la fornitura di un'unica interfaccia per entità di diverso tipo ...
Quindi, possiamo avere un albero di eredità molto diverso dal nostro class Man
.
class Man extends Human ...
ma se dichiariamo anche che possiamo fingere di essere un tipo diverso - Person
:
class Man extends Human
implements Person ...
.. quindi possiamo usarlo ovunque, dove Person
è richiesto. Dobbiamo solo soddisfare le persone "interface"
(cioè implementare tutte le sue cose pubbliche) .
implement
altra classe? Questa è roba davvero interessanteLa bella faccia di Javascript (uno dei vantaggi) è il supporto integrato della digitazione Duck ( vedi wiki ). Piccola citazione:
"Se cammina come un'anatra e fa schifo come un'anatra, allora deve essere un'anatra."
Quindi, in Javascript, se due oggetti diversi ... avessero un metodo simile (ad esempio render()
) possono essere passati a una funzione che lo prevede:
function(engine){
engine.render() // any type implementing render() can be passed
}
Per non perderlo - possiamo fare lo stesso in Typescript - con più supporto per la digitazione. Ed è qui che
class implements class
ha il suo ruolo, dove ha senso
Nelle lingue OOP come C#
... non c'è modo di farlo ...
Interfacce che estendono le classi
Quando un tipo di interfaccia estende un tipo di classe, eredita i membri della classe ma non le loro implementazioni. È come se l'interfaccia avesse dichiarato tutti i membri della classe senza fornire un'implementazione. Le interfacce ereditano anche i membri privati e protetti di una classe base. Ciò significa che quando crei un'interfaccia che estende una classe con membri privati o protetti, quel tipo di interfaccia può essere implementato solo da quella classe o da una sua sottoclasse.
Ciò è utile quando si dispone di una grande gerarchia di ereditarietà, ma si desidera specificare che il codice funziona solo con sottoclassi che hanno determinate proprietà. Le sottoclassi non devono essere correlate oltre a ereditare dalla classe base. Per esempio:
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } } class TextBox extends Control { select() { } } // Error: Property 'state' is missing in type 'Image'. class Image implements SelectableControl { private state: any; select() { } } class Location { }
Allora mentre
extends
significa - ottiene tutto dal suo genitoreimplements
in questo caso è quasi come implementare un'interfaccia. L'oggetto figlio può fingere di essere genitore ... ma non ottiene alcuna implementazioneextends
-ricevi tutto dal genitore", si applica ai membri privati? Per esempio class Person {private name: string} class man extends Person{gender: string;}
ha man
avere il nome della proprietà?
Nel dattiloscritto (e in alcuni altri linguaggi OO) ci sono classi e interfacce.
Un'interfaccia non ha implementazione, è solo un "contratto" di quali membri / metodo ha questo tipo.
Per esempio:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
Le istanze che implementano questa Point
interfaccia devono avere due membri di tipo number: x
and y
, e un metodo distance
che riceve un'altra Point
istanza e restituisce un file number
.
L'interfaccia non implementa nessuno di questi.
Le classi sono le implementazioni:
class PointImplementation implements Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public distance(other: Point): number {
return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
}
}
Nel tuo esempio tratti la tua Person
classe una volta come una classe quando la estendi e una volta come un'interfaccia quando la implementi.
Il tuo codice:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
Ha un errore di compilazione che dice:
La classe "Man" implementa in modo errato l'interfaccia "Person".
La proprietà "name" non è presente nel tipo "Man".
E questo perché le interfacce mancano di implementazione.
Quindi, se sei implement
una classe, prendi solo il suo "contratto" senza l'implementazione, quindi dovrai farlo:
class NoErrorMan implements Person {
name: string;
age: number;
}
La conclusione è che nella maggior parte dei casi si desidera frequentare extend
un'altra classe e non quella implement
.
Ottima risposta da @ nitzan-tomer! Mi ha aiutato molto ... ho esteso un po 'la sua demo con:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
E come si comportano nelle funzioni che si aspettano un IPoint
tipo.
Quindi quello che ho imparato finora e che ho usato come regola empirica: se stai usando classi e metodi che si aspettano tipi generici, usa le interfacce come i tipi previsti. E assicurati che il genitore o la classe base utilizzi quell'interfaccia. In questo modo puoi usare tutte le sottoclassi in quelle per quanto implementano l'interfaccia.
Qui la demo estesa
extends
concentrarsi sull'ereditarietà e implements
concentrarsi sui vincoli sia che si tratti di interfacce che di classi.
extends
: La classe figlia (che è estesa) erediterà tutte le proprietà e i metodi della classe si estendeimplements
: La classe che utilizza la implements
parola chiave dovrà implementare tutte le proprietà e i metodi della classe che la utilizzaimplements
Per dirla in termini più semplici:
extends
: Qui ottieni tutti questi metodi / proprietà dalla classe genitore, quindi non devi implementarlo da soloimplements
: Ecco un contratto che la classe deve seguire. La classe deve implementare almeno i seguenti metodi / proprietàclass Person {
name: string;
age: number;
walk(): void {
console.log('Walking (person Class)')
}
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class child extends Person { }
// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
name: string;
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('Walking (man class)')
}
}
(new child('Mike', 12)).walk();
// logs: Walking(person Class)
(new man('Tom', 12)).walk();
// logs: Walking(man class)
Nell'esempio possiamo osservare che la classe figlia eredita tutto da Person mentre la classe man deve implementare tutto da Person stessa.
Se dovessimo rimuovere qualcosa dalla classe man, ad esempio il metodo walk, otterremmo il seguente errore in fase di compilazione :
La classe "uomo" implementa in modo errato la classe "Persona". Intendevi estendere "Persona" ed ereditare i suoi membri come sottoclasse? La proprietà "walk" non è presente nel tipo "man" ma è richiesta nel tipo "Person". (2720)