Vedo due aree di comportamento diverso che derivano dai due meccanismi:
- L'oggetto puntatore è un oggetto separato dalla funzione di riferimento e avrà un'identità separata dalla funzione e da altri puntatori alla funzione
- L'oggetto puntatore può avere comportamenti oltre a quelli della funzione originale. Ad esempio, nella CLI:
- Le istanze delegate conoscono il relativo
this
(e possono associarlo al metodo)
- Le istanze delegate possono contenere puntatori a più funzioni
(Nota: questo deriva dalla mia esperienza in C # / VB.NET e Javascript.Altre lingue possono avere diverse varianti di entrambi i meccanismi.)
Equality di riferimento all'oggetto
Se una funzione è un "oggetto reale", qualsiasi variabile che punta alla funzione punta effettivamente allo stesso oggetto:
//Javascript
var fn = console.log;
var fn1 = console.log;
console.log(fn === fn1); //prints true
Gli oggetti puntatore hanno una propria identità, anche quando entrambi puntano alla stessa funzione:
//C#
Action action = Console.WriteLine;
Action action2 = Console.WriteLine;
Console.WriteLine(Object.ReferenceEquals(action, action2)); //prints False
Comportamenti aggiuntivi dell'oggetto puntatore
Associazione target
Gli oggetti funzione non hanno alcuna conoscenza della classe a cui sono collegati:
//Javascript
var a1 = {
data: 5,
writeData: function() {
'use strict'; //otherwise 'this' would be the global object; 'this.data' would probably return 'undefined'
console.log(this.data);
}
};
var action = a1.writeData;
action(); //Uncaught TypeError: Cannot read property 'data' of undefined
Pertanto, parte del chiamare la funzione come metodo di istanza, è il vincolo implicito di this
all'interno della funzione dell'oggetto:
a1.writeData(); //prints 5
Possiamo anche legare esplicitamente this
con bind
, apply
o call
:
action = a1.writeData.bind(a1);
action(); //prints 5
Tuttavia (come @amon ha sottolineato in questa risposta ), l'istanza delegata conserva tali informazioni:
//C#
public class A {
public int Data;
public void WriteData() {
Console.WriteLine(this.Data);
}
}
var a1 = new A() {Data=4};
Action action = a1.WriteData;
perché action
contiene la conoscenza della destinazione dei metodi:
Console.WriteLine(action.Target == a1); //prints True
Delegato multicast
Le variabili / proprietà Javascript che si riferiscono a un oggetto funzione funzionano come riferimenti a qualsiasi altro oggetto e pertanto non possono riferirsi a più oggetti funzione contemporaneamente.
D'altro canto, un'istanza delegata in .NET può puntare a più funzioni:
//C#
public static class Writers {
public static void WriteOne() {
Console.WriteLine(1);
}
public static void WriteTwo() {
Console.WriteLine(2);
}
}
action = Writers.WriteOne;
action += Writers.WriteTwo;
action(); //prints 1, and then prints 2