Подтвердить что ты не робот

Как мне наследовать функции 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__ является нестандартным и устаревшим.

Как я должен наследовать прототипное создание объекта, но иметь этот объект в качестве функции.

Object.create возвращает объект не функцию.

new Constructor возвращает объект не функцию.

Мотивация: - кросс-браузер 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;
};

Я не считаю, что это возможно, поэтому мы должны, вероятно, предложить Function.create список рассылки es-discuss

/*
  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;
  };
})();

Связанная дискуссия по электронной почте

Как упоминалось в потоке es-discuss, существует оператор прототипа ES: strawman <|, который позволил бы это сделать.

Посмотрим, как это будет выглядеть с помощью <|

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
4b9b3361

Ответ 1

Я надеюсь, что я понимаю это право.

Я считаю, что вы хотите, чтобы функтор являлся экземпляром предопределенного прототипа (да, класса, а не классического класса), а также напрямую вызываемого? Правильно? Если это так, то это имеет смысл и очень мощный и гибкий (особенно в очень асинхронной среде, такой как JavaScript). К сожалению, нет способа сделать это изящно в JavaScript без манипуляции __proto__. Вы можете сделать это, разложив анонимную функцию и скопировав все ссылки на все методы (которые, как представляется, направляют вас на курс), чтобы действовать как прокси-класс. Недостатками этого являются...

  • Это очень дорогостоящее с точки зрения времени выполнения.
  • (functorObj instanceof MyClass) никогда не будет true.
  • Свойства не будут доступны напрямую (если все они были назначены по ссылке, это будет другая история, но примитивы назначаются по значению). Это можно решить с помощью аксессуаров с помощью defineProperty или просто названных методов доступа, если это необходимо (кажется, что это то, что вы ищете, просто добавьте все свойства к функтору с помощью defineProperty через getters/setters вместо просто функций if вам не нужна поддержка кросс-движков/обратная совместимость).
  • Вероятно, вы столкнетесь с крайними случаями, когда конечные собственные прототипы (например, Object.prototype или Array.prototype [если вы наследуете это]) могут работать не так, как ожидалось.
  • Вызов functorObj(someArg) всегда сделает объект this объектом, независимо от того, вызвал ли он functorObj.call(someOtherObj, someArg) (это не относится к вызовам методов, хотя)
  • Поскольку объект-функтор создается во время запроса, он будет заблокирован во времени, и манипуляция с исходным прототипом не повлияет на выделенные объекты-объекты, такие как нормальный объект (изменение MyClass.prototype не повлияет на какие-либо объекты-функторы и верно и обратное).

Если вы используете его мягко, хотя, ничто из этого не должно быть большой проблемой.

В вашем прототипе вашего класса определите что-то вроде...

// 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;
};

Результирующее использование будет выглядеть примерно так...

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.

Вы даже можете связать бесчисленное количество других объектов/функций/и т.д., пока корова не вернется домой. Просто отредактируйте запрос прокси.

Надеюсь, что это поможет. О, и, конечно, вы можете изменить поток factory так, чтобы конструктор, вызываемый без оператора new, затем создавал новый объект и возвращал объект-функтор. Однако вы предпочитаете (вы могли бы сделать это и другими способами).

Наконец, чтобы любая функция стала исполняющим оператором для функтора в немного более элегантной форме, просто сделайте прокси-функцию методом Function.prototype и передайте ей объект для обертывания, если вы хотите сделать что-то вроде (вам придется поменять templateFunction на this и this с аргументом, конечно)...

var functor = (function() { /* something */ }).asFunctor(aobj);