objetos - ¿Puede un objeto JavaScript tener una cadena de prototipo, pero también ser una función?
prototype javascript ejemplos (6)
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () { };
c.prototype = a;
var d = new c();
d.b(); // returns "bar"
d(); // throws exception, d is not a function
¿Hay alguna forma de que d
sea una función y aún así heredar propiedades de a
?
Esto es algo que he estado tratando de hacer desde hace un tiempo. Un agradecimiento especial a los autores anteriores por su aporte.
Aquí hay una implementación encadenada de usar un "objeto invocable":
var $omnifarious = (function(Schema){
var fn = function f(){
console.log(''ran f!!!'');
return f;
};
Schema.prototype = {
w: function(w){ console.log(''w''); return this; },
x: function(x){ console.log(''x''); return this; },
y: function(y){ console.log(''y''); return this; }
};
fn.__proto__ = (new Schema()).__proto__;
return fn;
})(function schema(){ console.log(''created new schema'', this); });
console.log(
$omnifarious()().w().x().y()()()
);
Además, con este enfoque de "Esquema", es posible crear una interface
reutilizable utilizando Object.freeze()
en el prototype
Schema
o en el objeto __proto__
. Esto podría verse más o menos así: fn.__proto__ = Object.freeze(new Schema().__proto__)
- este no es un ejemplo práctico y es posible que se necesiten más. Dicho eso, es una discusión diferente. ¡Inténtalo y me cuentas!
Espero que esto sea útil.
Respuesta corta: no es posible.
Esta línea de tu código:
var d = new c();
automáticamente asume que d
es un objeto. A menos que c
sea un constructor de un objeto incorporado, p. Ej., Function
. Pero si c
ya está definido por el idioma, no puede manipular su prototipo y no puede "heredarlo" de lo que quiera. Bueno, en algunos intérpretes puedes hacerlo, pero no puedes hacerlo de forma segura con todos los intérpretes: el estándar dice: "¡no te metas con objetos estándar o el intérprete te golpeará!".
Los objetos integrados son "únicos" y JavaScript no proporciona formas de duplicarlos. No es posible recrear Cadena, Número, Función, etc. sin recurrir a trucos incompatibles.
¿Tiene que ser realmente una cadena de prototipos? Puede usar un patrón de mixin para hacer que una función tenga todas las propiedades de a en su lugar. Incluso puedes envolverlo en una buena sintaxis "nueva" para fingir si realmente quieres.
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
var f = function(){
return a();
};
//mixin all properties on a
for(var prop in a){
f[prop] = a[prop];
}
return f; //just returns the function instead of "this"
};
var d = new c(); //doesn''t need the new keyword, but just for fun it still works
alert(d()); //show "foo"
alert(d.b()); //shows "bar"
Puede agregar propiedades a d sin afectar a. La única diferencia entre esto y lo que desea es que los cambios en un will no afecten las "instancias" existentes de c.
Sí, es posible si usa la propiedad __proto__
mencionada por Daniel Cassidy. El truco está en que c
realmente devuelva una función que se ha unido a su cadena de prototipos.
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
var func = function() {
return "I am a function";
};
func.__proto__ = a;
return func;
}
c.prototype = a;
var d = new c();
d.b(); // returns "bar"
d(); // returns "I am a function"
Sin embargo, necesitará hacer algunos ajustes adicionales de la cadena de prototipos si desea que los resultados sean mejores.
d instanceof c // true
d instanceof a // false
c instanceof a // false
En realidad, resulta que esto es posible , aunque de una manera no estándar .
Mozilla, Webkit, Blink / V8, Rhino y ActionScript proporcionan una propiedad __proto__
no estándar, que permite cambiar el prototipo de un objeto una vez creado. En estas plataformas, es posible el siguiente código:
function a () {
return "foo";
}
a.b = function () {
return "bar";
}
function c () {
return "hatstand";
}
c.__proto__ = a;
c(); // returns "hatstand"
c.b(); // returns "bar"; inherited from a
Esto podría ser útil para cualquiera que no tenga que preocuparse por la compatibilidad multiplataforma.
Sin embargo, tenga en cuenta que solo las propiedades de un objeto se pueden heredar. Por ejemplo:
var d = {};
d.__proto__ = a;
d.b(); // returns "bar"
d(); // throws exception -- the fact that d is inheriting from a function
// doesn''t make d itself a function.
Basado en una discusión sobre meta sobre una pregunta similar , estoy publicando esta respuesta aquí en base a @ alexander-mills original
Esto ahora se puede hacer de una manera compatible con los estándares
Primero crea un objeto que hereda la Function
const obj = Object.create(Function.prototype); // Ensures availability of call, apply ext
A continuación, agregue métodos y propiedades personalizadas para obj
A continuación declara la función
const f = function(){
// Hello, World!
};
Y establecer obj
como el prototipo de f
Object.setPrototypeOf(f,obj);
Demostración
const obj = Object.create(Function.prototype);
// Define an ''answer'' method on ''obj''
obj.answer = function() {
// Call this object
this.call(); // Logs ''Hello, World''
console.log(''The ultimate answer is 42'');
}
const f = function() {
// Standard example
console.log(''Hello, World'');
};
Object.setPrototypeOf(f, obj);
// ''f'' is now an object with an ''answer'' method
f.answer();
// But is still a callable function
f();