Oltre ad essere più familiare ai programmatori C ++ / Java, l'unico vantaggio che posso pensare è che prototipi e costruttori hanno probabilmente un supporto migliore per l'ereditarietà tradizionale in stile OOP.
Immagina di avere classe A con metodo foo () e classe B con metodo bar () che chiama foo (). Vogliamo che la classe B sia derivata da A, in modo che possa semplicemente chiamare foo () direttamente e tutto funzioni. Con costruttori e prototipi, questo è facile:
var A = function() {
this.x = 42;
};
A.prototype.foo = function() {
return this.x;
};
var B = function() {
this.y = 7;
};
B.prototype = new A;
B.prototype.constructor = B;
B.prototype.bar = function() {
return this.x * this.y;
};
var a = new A;
var b = new B;
console.log(a.foo()); // 42
console.log(b.foo()); // 42
console.log(b.bar()); // 294
Con chiusure, puoi usare l'approccio "mixin" per i membri pubblici e i metodi, ma per i privati sei praticamente bloccato.
var A = function() {
var x = 42;
return {
foo: function() {
return x;
}
};
};
var B = function() {
var y = 7;
var obj = {
bar: function() {
return x * y;
}
};
// mix in A's public members
var a = A();
Object.keys(a).forEach(function(key) {
obj[key] = a[key];
});
return obj;
};
var a = A();
var b = B();
console.log(a.foo()); // 42
console.log(b.foo()); // 42
console.log(b.bar()); // Uncaught ReferenceError: x is not defined
Per quanto posso dire, l'unico modo per far funzionare questo frammento è rendere x pubblico e usare "this.x", a quel punto potrebbe anche non essere più utilizzare le chiusure. Le chiusure possono implementare l'accesso "privato", ma non l'accesso "protetto", quindi se vuoi fare l'ereditarietà tradizionale devi comunque lasciare tutto pubblico.
Naturalmente, se non si fa molta eredità, questo è un non-problema. Al mio lavoro non ereditiamo quasi mai nulla, quindi usiamo anche le chiusure per impostazione predefinita.