¿Cómo heredo las funciones de javascript?


// Don't break the function prototype.
// pd - https://github.com/Raynos/pd
var proto = Object.create(Function.prototype, pd({
  "prop": 42
}));

var f = function() { return "is a function"; };
f.__proto__ = proto;

console.log(f.hasOwnProperty("prop")); // false
console.log(f.prop); // 42
console.log(f()); // "is a function"

.__proto__ no es estándar y está obsoleto.

Cómo se supone que herede prototípicamente creando un objeto pero teniendo ese objeto como función.

Object.create devuelve un Objeto, no una función.

new Constructor devuelve un Objeto, no una función.

Motivación: - Un navegador cruzado finherit

var finherit = function (parent, child) {
    var f = function() { 
        parent.apply(this, arguments);
        child.apply(this, arguments);
    };
    f.__proto__ = parent;
    Object.keys(child).forEach(function _copy(key) {
        f[key] = child[key];
    });
    return f;
};

No creo que esto sea posible, por lo que probablemente deberíamos proponer un Function.create al correo es-discuss list

/*
  Creates a new function whose prototype is proto.
  The function body is the same as the function fbody.
  The hash of propertydescriptors props is passed to defineproperties just like
  Object.create does.
*/
Function.create = (function() {
  var functionBody = function _getFunctionBody(f) {
    return f.toString().replace(/.+\{/, "").replace(/\}$/, "");
  };
  var letters = "abcdefghijklmnopqrstuvwxyz".split("");

  return function _create(proto, fbody, props) {
    var parameters = letters.slice(0, fbody.length);
    parameters.push(functionBody(fbody));
    var f = Function.apply(this, parameters);
    f.__proto__ = proto;
    Object.defineProperties(f, props);
    return f;
  };
})();

Relacionado es-discutir correo

Como se menciona en el hilo es-discuss existe un ES: strawman <| prototipo de operador que permitiría esto.

Veamos cómo se vería usando <|

var f1 = function () {
  console.log("do things");
};

f1.method = function() { return 42; };

var f2 = f1 <| function () {
  super();
  console.log("do more things");
}
console.log(f1.isPrototypeOf(f2)); // true
console.log(f2()); // do things do more things
console.log(f2.hasOwnProperty("method")); // false
console.log(f2.method()); // 42
Author: chrisjlee, 2011-09-24

2 answers

Espero estar entendiendo este derecho.

Creo que quieres un funtor que sea tanto una instancia de un prototipo predefinido (sí, una clase, simplemente no una clase clásica) como directamente llamable? ¿Verdad? Si es así, entonces esto tiene perfecto sentido y es muy potente y flexible (especialmente en un entorno altamente asíncrono como JavaScript). Lamentablemente no hay manera de hacerlo elegantemente en JavaScript sin manipular __proto__. Usted puede hacerlo por factoring hacia fuera un función anónima y copiar todas las referencias a todos los métodos (que parece ser la dirección que se dirigía) para actuar como una clase proxy. Las desventajas de esto son...

  1. Es muy costoso en términos de tiempo de ejecución.
  2. (functorObj instanceof MyClass) nunca será true.
  3. Las propiedades no serán directamente accesibles (si todas se asignaran por referencia, esto sería una historia diferente, pero las primitivas se asignan por valor). Esto se puede resolver con accesores a través de defineProperty o simplemente métodos de acceso con nombre si es necesario (parece que eso es lo que está buscando, simplemente agregue todas las propiedades al funtor con defineProperty a través de getters/setters en lugar de solo funciones si no necesita compatibilidad con motores cruzados/compatibilidad hacia atrás).
  4. Es probable que se encuentre con casos extremos donde los prototipos nativos finales (como Object.prototipo o matriz.prototype [si estás heredando eso]) puede no funcionar como se espera.
  5. Llamando functorObj(someArg) siempre hacer el this context sea el objeto, independientemente de si se llama functorObj.call(someOtherObj, someArg) (este no es el caso de las llamadas a métodos)
  6. Debido a que el objeto funtor se crea en el momento de la solicitud, se bloqueará en el tiempo y la manipulación del prototipo inicial no afectará a los objetos funtor asignados como un objeto normal se vería afectado (modificando MyClass.prototype no afectará a ningún objeto funtor y lo contrario también es cierto).

Sin embargo, si lo usa suavemente, nada de esto debe ser un gran tratar.

En tu prototipo de tu clase define algo como...

// This is you're emulated "overloaded" call() operator.
MyClass.prototype.execute = function() {
   alert('I have been called like a function but have (semi-)proper access to this!');
};

MyClass.prototype.asFunctor = function(/* templateFunction */) {
   if ((typeof arguments[0] !== 'function') && (typeof this.execute !== 'function'))
      throw new TypeError('You really should define the calling operator for a functor shouldn\'t you?');
   // This is both the resulting functor proxy object as well as the proxy call function
   var res = function() {
      var ret;
      if (res.templateFunction !== null)
         // the this context here could be res.asObject, or res, or whatever your goal is here
         ret = res.templateFunction.call(this, arguments);
      if (typeof res.asObject.execute === 'function')
         ret = res.asObject.execute.apply(res.asObject, arguments);
      return ret;
   };
   res.asObject = this;
   res.templateFunction = (typeof arguments[0] === 'function') ? arguments[0] : null;
   for (var k in this) {
      if (typeof this[k] === 'function') {
         res[k] = (function(reference) {
            var m = function() {
               return m.proxyReference.apply((this === res) ? res.asObject : this, arguments);
            };
            m.proxyReference = reference;
            return m;
         })(this.asObject[k]);
      }
   }
   return res;
};

El uso resultante se vería algo así...

var aobj = new MyClass();
var afunctor = aobj.asFunctor();
aobj.someMethodOfMine(); // << works
afunctor.someMethodOfMine(); // << works exactly like the previous call (including the this context).
afunctor('hello'); // << works by calling aobj.execute('hello');

(aobj instanceof MyClass) // << true
(afunctor instanceof MyClass) // << false
(afunctor.asObject === aobj) // << true

// to bind with a previous function...
var afunctor = (new MyClass()).asFunctor(function() { alert('I am the original call'); });
afunctor() // << first calls the original, then execute();
// To simply wrap a previous function, don't define execute() in the prototype.

Incluso podrías encadenar un sinnúmero de otros objetos/funciones/etc hasta que las vacas volvieran a casa. Solo refactoriza un poco la llamada del proxy.

Espero que eso ayude. Ah, y por supuesto se podría cambiar el flujo de fábrica para que un constructor llamado sin el operador new luego instancie un nuevo objeto y devuelve el objeto functor. Obstante usted prefiere (seguramente podría hacerlo de otras maneras también).

Finalmente, para que cualquier función se convierta en el operador de ejecución de un funtor de una manera un poco más elegante, simplemente haga que la función proxy sea un método de Function.prototype y pásele el objeto a envolver si desea hacer algo como (tendría que intercambiar templateFunction con this y this con el argumento, por supuesto)...

var functor = (function() { /* something */ }).asFunctor(aobj);
 9
Author: mr.stobbe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-14 07:06:48

Con ES6 es posible heredar de Function, ver (duplicar) pregunta

La clase Javascript hereda de la clase de función

default export Attribute extends Function {
...
}
 0
Author: Stefan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-23 15:09:12