Як розширити функцію за допомогою класів ES6?


105

ES6 дозволяє розширювати спеціальні об'єкти. Тому можливо успадкувати від функції. Такий об’єкт можна назвати функцією, але як я можу реалізувати логіку такого виклику?

class Smth extends Function {
  constructor (x) {
    // What should be done here
    super();
  }
}

(new Smth(256))() // to get 256 at this call?

Будь-який метод класу отримує посилання на екземпляр класу через this. Але коли він викликається функцією, thisпосилається на window. Як я можу отримати посилання на екземпляр класу, коли він викликається як функція?

PS: Те саме питання російською мовою.


17
Ах, нарешті , хто - то поставив це Queston :-)
Берги

1
Просто зробіть super(x)(тобто передайте його далі Function)? Не впевнений, чи Functionнасправді можна продовжити.
Фелікс Клінг

Майте на увазі, що проблеми із розширенням вбудованих класів все ще існують. Спеціалізація припускає, що це можливо, але я зіткнувся з проблемами, що поширюються Error, серед інших.
ssube

1
Майте на увазі, що Functionце просто конструктор функцій. Реалізацію функції потрібно передати конструктору. Якщо ви не хочете Smthприйняти реалізацію, ви повинні надати її в конструкторі, тобто super('function implementation here').
Фелікс Клінг

1
@Qwertiy: Я б заперечував, що це виняток , а не загальний випадок. Це також дуже специфічно для функціональних виразів , але ви використовуєте Functionконструктор (час виконання), який сильно відрізняється від виразу функції (синтаксису).
Фелікс Клінг

Відповіді:


49

superВиклик буде викликати Functionконструктор, який рядок коду. Якщо ви хочете отримати доступ до даних свого примірника, ви можете просто їх жорстко ввести:

class Smth extends Function {
  constructor(x) {
    super("return "+JSON.stringify(x)+";");
  }
}

але це насправді не задовольняє. Ми хочемо використовувати закриття.

Маючи повернуту функцію - це закриття, яке може отримати доступ до змінних вашого примірника , але не просто. Хороша річ у тому, що вам не потрібно дзвонити, superякщо ви цього не хочете - ви все одно можете returnдовільно використовувати об'єкти від конструкторів класу ES6. У цьому випадку ми б це зробили

class Smth extends Function {
  constructor(x) {
    // refer to `smth` instead of `this`
    function smth() { return x; };
    Object.setPrototypeOf(smth, Smth.prototype);
    return smth;
  }
}

Але ми можемо зробити ще краще і абстрагувати це Smth:

class ExtensibleFunction extends Function {
  constructor(f) {
    return Object.setPrototypeOf(f, new.target.prototype);
  }
}

class Smth extends ExtensibleFunction {
  constructor(x) {
    super(function() { return x; }); // closure
    // console.log(this); // function() { return x; }
    // console.log(this.prototype); // {constructor: …}
  }
}
class Anth extends ExtensibleFunction {
  constructor(x) {
    super(() => { return this.x; }); // arrow function, no prototype object created
    this.x = x;
  }
}
class Evth extends ExtensibleFunction {
  constructor(x) {
    super(function f() { return f.x; }); // named function
    this.x = x;
  }
}

Справді, це створює додатковий рівень опосередкованості у ланцюжку спадкування, але це не обов'язково погано (можна поширити його замість рідного Function). Якщо ви хочете цього уникнути, використовуйте

function ExtensibleFunction(f) {
  return Object.setPrototypeOf(f, new.target.prototype);
}
ExtensibleFunction.prototype = Function.prototype;

але зауважте, що Smthстатичні Functionвластивості не будуть динамічно успадковувати


Я хочу отримати доступ до стану класу з функції.
Qwertiy

2
@Qwertiy: Тоді скористайтеся другою пропозицією Бергі.
Фелікс Клінг

@ AlexanderO'Mara: Якщо ви хочете, щоб ваші Smthекземпляри були instanceof Smth(як очікували всі), ви не можете мутувати мутацію прототипу функції . Ви можете пропустити Object.setPrototypeOfвиклик, якщо вам не потрібен цей або будь-який із способів прототипу, оголошених у вашому класі.
Бергі

@ AlexanderO'Mara: Також Object.setPrototypeOfне стільки небезпека оптимізації, скільки це робиться відразу після створення об'єкта. Це просто, якщо ви мутуєте [[прототип]] об'єкта вперед і назад протягом його життя, це буде погано.
Бергі

1
@amn Ні, ви цього не робите, коли не використовуєте thisі returnоб'єкт.
Бергі

32

Це підхід до створення об'єктів, що дзвонять, які правильно посилаються на своїх членів об'єкта та підтримують правильне успадкування, не псуючи прототипи.

Просто:

class ExFunc extends Function {
  constructor() {
    super('...args', 'return this.__self__.__call__(...args)')
    var self = this.bind(this)
    this.__self__ = self
    return self
  }

  // Example `__call__` method.
  __call__(a, b, c) {
    return [a, b, c];
  }
}

Розгорніть цей клас і додайте __call__метод, докладніше нижче ...

Пояснення в коді та коментарі:

// This is an approach to creating callable objects
// that correctly reference their own object and object members,
// without messing with prototypes.

// A Class that extends Function so we can create
// objects that also behave like functions, i.e. callable objects.
class ExFunc extends Function {
  constructor() {
    super('...args', 'return this.__self__.__call__(...args)');
    // Here we create a function dynamically using `super`, which calls
    // the `Function` constructor which we are inheriting from. Our aim is to create
    // a `Function` object that, when called, will pass the call along to an internal
    // method `__call__`, to appear as though the object is callable. Our problem is
    // that the code inside our function can't find the `__call__` method, because it
    // has no reference to itself, the `this` object we just created.
    // The `this` reference inside a function is called its context. We need to give
    // our new `Function` object a `this` context of itself, so that it can access
    // the `__call__` method and any other properties/methods attached to it.
    // We can do this with `bind`:
    var self = this.bind(this);
    // We've wrapped our function object `this` in a bound function object, that
    // provides a fixed context to the function, in this case itself.
    this.__self__ = self;
    // Now we have a new wrinkle, our function has a context of our `this` object but
    // we are going to return the bound function from our constructor instead of the
    // original `this`, so that it is callable. But the bound function is a wrapper
    // around our original `this`, so anything we add to it won't be seen by the
    // code running inside our function. An easy fix is to add a reference to the
    // new `this` stored in `self` to the old `this` as `__self__`. Now our functions
    // context can find the bound version of itself by following `this.__self__`.
    self.person = 'Hank'
    return self;
  }
  
  // An example property to demonstrate member access.
  get venture() {
    return this.person;
  }
  
  // Override this method in subclasses of ExFunc to take whatever arguments
  // you want and perform whatever logic you like. It will be called whenever
  // you use the obj as a function.
  __call__(a, b, c) {
    return [this.venture, a, b, c];
  }
}

// A subclass of ExFunc with an overridden __call__ method.
class DaFunc extends ExFunc {
  constructor() {
    super()
    this.a = 'a1'
    this.b = 'b2'
    this.person = 'Dean'
  }

  ab() {
    return this.a + this.b
  }
  
  __call__(ans) {
    return [this.ab(), this.venture, ans];
  }
}

// Create objects from ExFunc and its subclass.
var callable1 = new ExFunc();
var callable2 = new DaFunc();

// Inheritance is correctly maintained.
console.log('\nInheritance maintained:');
console.log(callable2 instanceof Function);  // true
console.log(callable2 instanceof ExFunc);  // true
console.log(callable2 instanceof DaFunc);  // true

// Test ExFunc and its subclass objects by calling them like functions.
console.log('\nCallable objects:');
console.log( callable1(1, 2, 3) );  // [ 'Hank', 1, 2, 3 ]
console.log( callable2(42) );  // [ 'a1b2', Dean', 42 ]

// Test property and method access
console.log(callable2.a, callable2.b, callable2.ab())

Переглянути на repl.it

Подальше пояснення bind:

function.bind() працює так, як function.call() , і вони поділяють подібний метод підпису:

fn.call(this, arg1, arg2, arg3, ...);більше на mdn

fn.bind(this, arg1, arg2, arg3, ...); більше про mdn

В обох першому аргументі визначено thisконтекст всередині функції. Додаткові аргументи також можуть бути пов'язані зі значенням. Але там, де callнегайно викликає функцію із пов'язаними значеннями, bindповертає "екзотичний" об'єкт функції, який прозоро обертає оригінал, зthis заданими аргументами та будь-якими аргументами.

Отже, коли ви визначаєте функцію, то bindдеякі її аргументи:

var foo = function(a, b) {
  console.log(this);
  return a * b;
}

foo = foo.bind(['hello'], 2);

Ви викликаєте пов'язану функцію лише з рештою аргументів, її контекст задається в цьому випадку ['hello'].

// We pass in arg `b` only because arg `a` is already set.
foo(2);  // returns 4, logs `['hello']`

Ви можете додати пояснення, чому bindпрацює (тобто чому він повертає екземпляр ExFunc)?
Бергі

@Bergi bindповертає прозорий функціональний об'єкт, який обертає об'єкт функції, на який він був викликаний, і який є нашим об'єктом, що дзвониться, просто з thisвідскоком контексту. Таким чином, він дійсно повертає прозоро завернутий екземпляр ExFunc. Публікація оновлена ​​з додатковою інформацією про bind.
Адрієн

1
@Bergi Усі доступні / задачі та методи доступні, властивості / атрибути повинні бути призначені constructorпісля bindв ExFunc. У підкласах ExFunc всі учасники доступні. Щодо instanceof; в es6 пов'язаних функціях називають екзотикою, тому їх внутрішня робота не очевидна, але я думаю, що вона передає дзвінок своїй оберненій цілі, через Symbol.hasInstance. Це дуже схоже на проксі, але це простий спосіб досягти бажаного ефекту. Їх підпис схожий не однаковий.
Адріан

1
@Adrien , але з внутрішньої сторони __call__не можуть отримати доступ this.aабо this.ab(). наприклад repl.it/repls/FelineFinishedDesktopenvironment
віднімають

1
@rob добре помічений, є помилка посилання, я оновив відповідь та код із виправленням та новим поясненням.
Адрієн

20

Ви можете обернути примірник Smth у проксі-сервер із apply(а може бути construct) пасткою:

class Smth extends Function {
  constructor (x) {
    super();
    return new Proxy(this, {
      apply: function(target, thisArg, argumentsList) {
        return x;
      }
    });
  }
}
new Smth(256)(); // 256

Класна ідея. Подобається це. Чи слід реалізовувати якусь логіку замість того, щоб розміщуватись у застосуванні?
Qwertiy

4
Проксі-сервер несе чималі накладні витрати, чи не так? Також thisє ще порожня функція (чек new Smth().toString()).
Бергі

2
@Bergi Поняття про продуктивність не має. MDN має велике червоне жирне попередження setPrototypeOfі нічого не говорить про проксі. Але я думаю, проксі можуть бути настільки ж проблемними, як і setPrototypeOf. І приблизно toString, це може бути затінено спеціальним методом в Smth.prototype. Народний в будь-якому випадку залежить від реалізації.
Оріол

@Qwertiy Ви можете додати constructпастку, щоб вказати поведінку new new Smth(256)(). І додайте спеціальні методи, що тінять рідні, які отримують доступ до коду функції, як, наприклад toString, зазначив Бергі.
Оріол

Я вважаю, ваш applyметод реалізований так, як він повинен бути використаний, або це лише демонстрація, і мені потрібно переглянути більше інформації Proxyта Reflectправильно її використати?
Qwertiy

3

Я взяв пораду з відповіді Бергі і загорнув її в модуль NPM .

var CallableInstance = require('callable-instance');

class ExampleClass extends CallableInstance {
  constructor() {
    // CallableInstance accepts the name of the property to use as the callable
    // method.
    super('instanceMethod');
  }

  instanceMethod() {
    console.log("instanceMethod called!");
  }
}

var test = new ExampleClass();
// Invoke the method normally
test.instanceMethod();
// Call the instance itself, redirects to instanceMethod
test();
// The instance is actually a closure bound to itself and can be used like a
// normal function.
test.apply(null, [ 1, 2, 3 ]);

3

Оновлення:

На жаль, це не спрацьовує, тому що тепер повертає об’єкт функції замість класу, тому, здається, це насправді неможливо зробити без зміни прототипу. Кульгав.


В основному проблема полягає в тому, що немає можливості встановити thisзначення для Functionконструктора. Єдиний спосіб реально зробити це - використовувати.bind метод згодом, однак це не дуже зручно для класу.

Це можна зробити в базовому класі помічників, однак thisвоно стає доступним лише після початковогоsuper дзвінка, тому це трохи хитро.

Приклад роботи:

'use strict';

class ClassFunction extends function() {
    const func = Function.apply(null, arguments);
    let bound;
    return function() {
        if (!bound) {
            bound = arguments[0];
            return;
        }
        return func.apply(bound, arguments);
    }
} {
    constructor(...args) {
        (super(...args))(this);
    }
}

class Smth extends ClassFunction {
    constructor(x) {
        super('return this.x');
        this.x = x;
    }
}

console.log((new Smth(90))());

(Для прикладу потрібен сучасний браузер або node --harmony .)

В основному розширення базової функції ClassFunctionбуде обертати Functionвиклик конструктора з власною функцією, яка схожа на .bind, але дозволяє прив'язувати пізніше, під час першого виклику. Потім вClassFunction конструкторі він викликає повернуту функцію, від superякої тепер пов'язана функція, передаючи, thisщоб закінчити налаштування спеціальної функції прив'язки.

(super(...))(this);

Це все досить складно, але це не дозволяє мутувати прототип, який з міркувань оптимізації вважається поганою формою і може генерувати попередження на консолях браузера.


1
Ви надмірно ускладнюєте речі. boundбуде посилатися на функцію, яку ви отримуєте returnз цього анонімного класу. Просто назвіть його та зверніться до нього безпосередньо. Я також порекомендував би не уникати передачі рядків коду навколо, з ними просто безлад (на кожному кроці процесу розробки).
Бергі

Це на extendsсамому ділі не здається , працювати , як і очікувалося, так як Function.isPrototypeOf(Smth)і також new Smth instanceof Functionє помилковими.
Бергі

@Bergi Який двигун JS ви використовуєте? console.log((new Smth) instanceof Function);це trueдля мене в вузлі v5.11.0 і останньої Firefox.
Олександр О'Мара

На жаль, неправильний приклад. Це new Smth instanceof Smthне працює з вашим рішенням. Крім того, жодні методи не Smthбудуть доступні для ваших примірників - як тільки ви повернете стандарт Function, а не a Smth.
Бергі

1
@ Bergi Darn це, схоже, ти маєш рацію. Однак, схоже, розширення будь-яких натурних типів має ту саму проблему. extend Functionтакож робить new Smth instanceof Smthпомилковим.
Олександр О'Мара

1

По-перше, я прийшов до вирішення arguments.callee, але це було жахливо.
Я очікував, що він порушиться в глобальному жорсткому режимі, але здається, він працює навіть там.

class Smth extends Function {
  constructor (x) {
    super('return arguments.callee.x');
    this.x = x;
  }
}

(new Smth(90))()

Це було поганим способом через використання arguments.callee, передавання коду як рядка та змушування його виконання в не строгому режимі. Але applyз'явилася ідея перекрити .

var global = (1,eval)("this");

class Smth extends Function {
  constructor(x) {
    super('return arguments.callee.apply(this, arguments)');
    this.x = x;
  }
  apply(me, [y]) {
    me = me !== global && me || this;
    return me.x + y;
  }
}

І тест, показуючи, що я здатний виконувати цю функцію по-різному:

var f = new Smth(100);

[
f instanceof Smth,
f(1),
f.call(f, 2),
f.apply(f, [3]),
f.call(null, 4),
f.apply(null, [5]),
Function.prototype.apply.call(f, f, [6]),
Function.prototype.apply.call(f, null, [7]),
f.bind(f)(8),
f.bind(null)(9),
(new Smth(200)).call(new Smth(300), 1),
(new Smth(200)).apply(new Smth(300), [2]),
isNaN(f.apply(window, [1])) === isNaN(f.call(window, 1)),
isNaN(f.apply(window, [1])) === isNaN(Function.prototype.apply.call(f, window, [1])),
] == "true,101,102,103,104,105,106,107,108,109,301,302,true,true"

Версія з

super('return arguments.callee.apply(arguments.callee, arguments)');

насправді містить bindфункціональність:

(new Smth(200)).call(new Smth(300), 1) === 201

Версія з

super('return arguments.callee.apply(this===(1,eval)("this") ? null : this, arguments)');
...
me = me || this;

робить callі applyна windowнесумісне:

isNaN(f.apply(window, [1])) === isNaN(f.call(window, 1)),
isNaN(f.apply(window, [1])) === isNaN(Function.prototype.apply.call(f, window, [1])),

тому чек слід перенести на apply:

super('return arguments.callee.apply(this, arguments)');
...
me = me !== global && me || this;

1
Що ви насправді намагаєтесь зробити?
Дякую

2
Я думаю, що класи завжди в суворому режимі: stackoverflow.com/questions/29283935/…
Alexander O'Mara

@ AlexanderO'Mara, до речі, thisвікно, не визначене, тому створена функція не в суворому режимі (принаймні, в хромі).
Qwertiy

Будь ласка, перестаньте занижувати цю відповідь. Я вже писав, що це поганий шлях. Але це дійсно відповідь - він працює як у FF, так і в Chrome (не потрібно перевіряти Edge).
Qwertiy

Я здогадуюсь, це працює, тому що Functionне в суворому режимі. Хоча це жахливо, але це цікаво +1. Напевно, ви більше не зможете ходити ланцюжком.
Олександр О'Мара

1

Це розроблене нами рішення, яке задовольняє всі мої потреби в розширенні функцій і досить добре обслуговувало мене. Перевагами цієї методики є:

  • Під час розширення ExtensibleFunctionкод є ідіоматичним для розширення будь-якого класу ES6 (ні, спілкування з конструкторами претендентів або проксі-серверами).
  • Лабораторія прототипу зберігається через усі підкласи та instanceof/ .constructorповертає очікувані значення.
  • .bind() .apply()і .call()всі функціонують, як очікувалося. Це робиться шляхом відміни цих методів для зміни контексту "внутрішньої" функції на відміну відExtensibleFunction екземпляра (або його підкласу).
  • .bind()повертає новий екземпляр конструктора функцій (будь то ExtensibleFunctionабо підклас). Він використовує Object.assign()для того, щоб властивості, що зберігаються у зв'язаній функції, відповідали властивостям функції, що походить.
  • Закриття вшановують, а функції стрілок продовжують підтримувати належний контекст.
  • "Внутрішня" функція зберігається через a Symbol, який може бути затуманений модулями або IIFE (або будь-якою іншою поширеною технікою приватизації посилань).

І без зайвих помилок, код:

// The Symbol that becomes the key to the "inner" function 
const EFN_KEY = Symbol('ExtensibleFunctionKey');

// Here it is, the `ExtensibleFunction`!!!
class ExtensibleFunction extends Function {
  // Just pass in your function. 
  constructor (fn) {
    // This essentially calls Function() making this function look like:
    // `function (EFN_KEY, ...args) { return this[EFN_KEY](...args); }`
    // `EFN_KEY` is passed in because this function will escape the closure
    super('EFN_KEY, ...args','return this[EFN_KEY](...args)');
    // Create a new function from `this` that binds to `this` as the context
    // and `EFN_KEY` as the first argument.
    let ret = Function.prototype.bind.apply(this, [this, EFN_KEY]);
    // For both the original and bound funcitons, we need to set the `[EFN_KEY]`
    // property to the "inner" function. This is done with a getter to avoid
    // potential overwrites/enumeration
    Object.defineProperty(this, EFN_KEY, {get: ()=>fn});
    Object.defineProperty(ret, EFN_KEY, {get: ()=>fn});
    // Return the bound function
    return ret;
  }

  // We'll make `bind()` work just like it does normally
  bind (...args) {
    // We don't want to bind `this` because `this` doesn't have the execution context
    // It's the "inner" function that has the execution context.
    let fn = this[EFN_KEY].bind(...args);
    // Now we want to return a new instance of `this.constructor` with the newly bound
    // "inner" function. We also use `Object.assign` so the instance properties of `this`
    // are copied to the bound function.
    return Object.assign(new this.constructor(fn), this);
  }

  // Pretty much the same as `bind()`
  apply (...args) {
    // Self explanatory
    return this[EFN_KEY].apply(...args);
  }

  // Definitely the same as `apply()`
  call (...args) {
    return this[EFN_KEY].call(...args);
  }
}

/**
 * Below is just a bunch of code that tests many scenarios.
 * If you run this snippet and check your console (provided all ES6 features
 * and console.table are available in your browser [Chrome, Firefox?, Edge?])
 * you should get a fancy printout of the test results.
 */

// Just a couple constants so I don't have to type my strings out twice (or thrice).
const CONSTRUCTED_PROPERTY_VALUE = `Hi, I'm a property set during construction`;
const ADDITIONAL_PROPERTY_VALUE = `Hi, I'm a property added after construction`;

// Lets extend our `ExtensibleFunction` into an `ExtendedFunction`
class ExtendedFunction extends ExtensibleFunction {
  constructor (fn, ...args) {
    // Just use `super()` like any other class
    // You don't need to pass ...args here, but if you used them
    // in the super class, you might want to.
    super(fn, ...args);
    // Just use `this` like any other class. No more messing with fake return values!
    let [constructedPropertyValue, ...rest] = args;
    this.constructedProperty = constructedPropertyValue;
  }
}

// An instance of the extended function that can test both context and arguments
// It would work with arrow functions as well, but that would make testing `this` impossible.
// We pass in CONSTRUCTED_PROPERTY_VALUE just to prove that arguments can be passed
// into the constructor and used as normal
let fn = new ExtendedFunction(function (x) {
  // Add `this.y` to `x`
  // If either value isn't a number, coax it to one, else it's `0`
  return (this.y>>0) + (x>>0)
}, CONSTRUCTED_PROPERTY_VALUE);

// Add an additional property outside of the constructor
// to see if it works as expected
fn.additionalProperty = ADDITIONAL_PROPERTY_VALUE;

// Queue up my tests in a handy array of functions
// All of these should return true if it works
let tests = [
  ()=> fn instanceof Function, // true
  ()=> fn instanceof ExtensibleFunction, // true
  ()=> fn instanceof ExtendedFunction, // true
  ()=> fn.bind() instanceof Function, // true
  ()=> fn.bind() instanceof ExtensibleFunction, // true
  ()=> fn.bind() instanceof ExtendedFunction, // true
  ()=> fn.constructedProperty == CONSTRUCTED_PROPERTY_VALUE, // true
  ()=> fn.additionalProperty == ADDITIONAL_PROPERTY_VALUE, // true
  ()=> fn.constructor == ExtendedFunction, // true
  ()=> fn.constructedProperty == fn.bind().constructedProperty, // true
  ()=> fn.additionalProperty == fn.bind().additionalProperty, // true
  ()=> fn() == 0, // true
  ()=> fn(10) == 10, // true
  ()=> fn.apply({y:10}, [10]) == 20, // true
  ()=> fn.call({y:10}, 20) == 30, // true
  ()=> fn.bind({y:30})(10) == 40, // true
];

// Turn the tests / results into a printable object
let table = tests.map((test)=>(
  {test: test+'', result: test()}
));

// Print the test and result in a fancy table in the console.
// F12 much?
console.table(table);

Редагувати

Оскільки я був у настрої, я подумав, що опублікую пакунок для цього в npm.


1

Існує просте рішення, яке використовує функціональні можливості JavaScript: передайте "логіку" як аргумент функції конструктору вашого класу, призначте методи цього класу цій функції, а потім поверніть цю функцію від конструктора як результат :

class Funk
{
    constructor (f)
    { let proto       = Funk.prototype;
      let methodNames = Object.getOwnPropertyNames (proto);
      methodNames.map (k => f[k] = this[k]);
      return f;
    }

    methodX () {return 3}
}

let myFunk  = new Funk (x => x + 1);
let two     = myFunk(1);         // == 2
let three   = myFunk.methodX();  // == 3

Вищевказане було протестовано на Node.js 8.

Недоліком наведеного вище прикладу є те, що він не підтримує методи, успадковані від ланцюга надкласових класів. Щоб підтримати це, просто замініть "Object. GetOwnPropertyNames (...)" чимось, що повертає також імена успадкованих методів. Як це зробити, я вважаю, пояснюється в якомусь іншому запитанні-відповіді щодо переповнення стека :-). До речі. Було б добре, якби ES7 також додав метод для створення імен успадкованих методів ;-).

Якщо вам потрібна підтримка успадкованих методів, одна можливість - додати статичний метод до вищевказаного класу, який повертає всі успадковані та локальні назви методів. Потім зателефонуйте цьому від конструктора. Якщо потім розширити цей клас Funk, ви отримаєте цей статичний метод також успадкований.


Я думаю, що цей приклад дає просту відповідь на початкове запитання "... як я можу реалізувати логіку такого виклику". Просто передайте це як аргумент, що оцінюється функцією, конструктору. У наведеному вище коді клас Funk явно не розширює функцію, хоча це, можливо, не потрібно. Як ви бачите, ви можете викликати його "екземпляри", як ви викликаєте будь-яку звичайну функцію.
Логіка Пану
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.