Добавить метод в выражение функции (или объявление функции) - PullRequest
0 голосов
/ 28 декабря 2018

Я хотел бы добавить метод к выражению функции настолько просто, насколько это возможно.В моем случае я использую выражение функции, но объявление функции также будет в порядке.Поскольку функции являются объектами, я думаю, что это возможно. Но как?


Подробности:

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

Следующий код добавляет метод (setListener) к функции (secondsEvent) без конструкторов и наследования, но не в выражении анонимной функции, чего я хотел бы достичь каким-либо образом (см. Комментарии):

function listener1 (date) {
    console.log("listener1: " + date);
}

function listener2 (date) {
    console.log("listener2: " + date);
}

var secondsEvent = function () {
    //The following causes "listener is not defined" in firefox console                                                      
    //listener: listener1,                                                                                                   

    //The following causes "function statement requires a name" in firefox console,                                          
    //and if I give the function a name, I get "secondsEvent.setListener is not a function".                                  
    //Thus I add the property after this function expression.                                                                   
    //setListener: function (newListener) {                                                                                  
    //    listener = newListener;                                                                                            
    //},                                                                                                                     
    secondsEvent.listener(new Date());
    var timeout = setTimeout(secondsEvent, 1000);
}

// Thus the following 5 lines are needed.                                                                                    
secondsEvent.listener = listener1;
secondsEvent.setListener = function (newListener) {
    secondsEvent.listener = newListener;
    console.log("listener now " + secondsEvent.listener.name);
}

secondsEvent();
secondsEvent.setListener(listener2);

Код дает следующий вывод:

listener1: Fri Dec 28 2018 21:55:05 GMT+0100 (Central European Standard Time) 
listener now listener2 
listener2: Fri Dec 28 2018 21:55:06 GMT+0100 (Central European Standard Time) 
listener2: Fri Dec 28 2018 21:55:07 GMT+0100 (Central European Standard Time) 
.....

Обновления:

Первоначально я использовал термин Дугласа Крокфорда "«литерал функции» вместо выражения функции, но теперь обновил заголовок и вопрос.

В ответ на предложение Теему я попробовал следующий код:

function listener1 (date) {
    console.log("listener1: "+date + "<br>");
}

function listener2 (date) {
    console.log("listener2: "+date + "<br>");
}

var secondsEvent = function () {
    secondsEvent.listener = listener1;
    secondsEvent.setListener = function (newListener) {
        secondsEvent.listener = newListener;
        console.log("listener now " + secondsEvent.listener.name);
    }
    clearTimeout(secondsEvent.timeout);
    secondsEvent.listener(new Date());
    secondsEvent.timeout = setTimeout(secondsEvent, 1000);
};

secondsEvent();
secondsEvent.setListener(listener2);

Однако его выходные данные выглядят следующим образом:

listener1: Sat Dec 29 2018 10:47:48 GMT+0100 (Central European Standard Time)<br> test.js:2:5
listener now listener2 test.js:27:2
listener1: Sat Dec 29 2018 10:47:49 GMT+0100 (Central European Standard Time)<br> test.js:2:5
listener1: Sat Dec 29 2018 10:47:50 GMT+0100 (Central European Standard Time)<br>

Чтобы не задавать свойства secondsEvent.listener и secondsEvent.setListener каждый раз, когда secondsEventназывается, я использую следующее:

secondsEvent.listener = secondsEvent.listener || listener1;
secondsEvent.setListener = secondsEvent.setListener || function (newListener) {
    secondsEvent.listener = newListener;
    console.log("listener now " + secondsEvent.listener.name);
}

Есть ли более хорошее решение для установки свойств только один раз?Может быть, некоторые JS инициализатор идиома?(Я знаю, что извлечение этого из функции было бы другим решением, но это приводит к моему первому решению, которого я хочу избежать, так как было бы намного лучше включить определения свойств в выражение функции (или объявление функции, в зависимости от того, что вы используете)), прежде чем они будут использованы.

Ответы [ 3 ]

0 голосов
/ 29 декабря 2018

Вы говорите о «функциональном литерале», но в JavaScript такого нет.Мы говорим о функциональном выражении .

Одна из вещей, которую вы могли бы рассмотреть, - это использование Object.assign, которое позволит объединить объект (предоставленный как литерал) в (функция) объект:

function listener1 (date) {
    console.log("listener1: "+date);
}

function listener2 (date) {
    console.log("listener2: "+date);
}

var secondsEvent = Object.assign(function () {
    clearTimeout(secondsEvent.timeout);
    secondsEvent.listener(new Date());
    secondsEvent.timeout = setTimeout(secondsEvent, 1000);
}, {
    listener: listener1,
    setListener(newListener) {
        this.listener = newListener;
        console.log("listener now " + this.listener.name);
    }
});

secondsEvent();
secondsEvent.setListener(listener2);

Традиционная альтернатива

Ниже приводится не то, что вы просили, но я все равно приведу это в качестве сравнения.

Более традиционныйспособ объединить поведение и данные - начать с объекта.Здесь мы не расширяем функцию дополнительными свойствами;функция становится методом объекта, который имеет свойства:

function listener1 (date) {
    console.log("listener1: "+date);
}

function listener2 (date) {
    console.log("listener2: "+date);
}

var secondsEvent = {
    listener: listener1,
    start() {
        clearTimeout(this.timeout);
        this.listener(new Date());
        this.timeout = setTimeout(() => this.start(), 1000);
    },
    setListener(newListener) {
        this.listener = newListener;
        console.log("listener now " + this.listener.name);
    }
};

secondsEvent.start(); // secondsEvent is not a function. We call a method
secondsEvent.setListener(listener2);

Хотя здесь вам нужно вызывать функцию с .start(), она имеет то преимущество, что она выглядит и работает как большинство других объектов: пользователи этого API не будутудивлен.

0 голосов
/ 29 декабря 2018

Я отвечаю только на самую первую часть вопроса и игнорирую «вариант использования».Есть старая и немного изношенная фраза: « Все в JS является объектом. » Да, все, кроме примитивов, было бы более правильным.

Но функции, они действительно являются объектами,вызываемые объекты.Это означает, что эти функциональные объекты могут иметь свойства в форме значений или методов.Первоначальный вопрос был: « [Как] добавить метод в функцию [объект] ».

Ответ довольно прост, получить ссылку на функцию и добавить свойство(метод также является свойством) для упомянутой функции, как если бы вы добавляли свойство к обычному объекту, и все.Либо это?Есть несколько ситуаций, когда свойство должно быть присвоено функции, и эта функция могла бы быть распределена в памяти различными способами.Теперь можно свести вопрос к следующему: «Как получить ссылку на функцию в той точке, в которой она необходима?»

Существует три основных способа определения функции:

  1. объявленная функция (объявленная функция всегда имеет имя) [fn1]
  2. выражение именованной функции (может быть присвоено переменной или использовано в другом месте) [fn2]
  3. anвыражение анонимной функции (может быть присвоено переменной или использовано в другом месте) [fn3]

# 1 - это самый простой случай, вы можете ссылаться на объявленную функцию где угодно втекущую область видимости, используя ее имя, включая само тело функции.Таким образом, вы можете создать метод для этой функции, выполнив fn1.method = function () {...} внутри тела fn1 s или вне функции, используя те же обозначения.

# 2 вы можете использоватьданное имя только в теле функции.Если вам нужно назначить метод вне этой функции, использовать имя переменной или в случае, если функция была передана в качестве аргумента другой функции, обратитесь к fn2 с именем аргумента.

# 3 не предоставляет никакой ссылки на саму функцию внутри тела функции.Однако, если эта функция назначена переменной, имя переменной можно использовать для ссылки на саму функцию внутри тела функции, при условии, что функция не выполняется как IIFE.Вне тела функции имя переменной может использоваться для ссылки на функцию, как только переменная будет инициализирована.

Что касается значения this в методах функции, вы не можете доверятьон ссылается на функцию «владение методом».Если вам нужно ссылаться на this в методах, лучше использовать реальные объекты вместо функций.

В качестве примечания, использование свойств объектов функций не является обычным случаем использования в JS.Обычно вместо них используются реальные объекты.Общий пример использования преимуществ функционального объекта - это jQuery's $, который на самом деле является функцией, но имеет также некоторые методы и свойства.

0 голосов
/ 29 декабря 2018

Синтаксис, который вы используете, выглядит как объект или более подходящий синтаксис класса.Из вашего вопроса не очень понятно, пытаетесь ли вы избегать занятий.Хотя вы упомянули о желании избегать конструкторов, поэтому я предполагаю, что вы имеете в виду, что не хотите использовать классы.

У вас могут быть методы в функциях

function methodFunction () {
   return {
       myMethod (argument) {
           if (argument) console.log(argument)
           return new Date()
       }
   }
}

methodFunction().myMethod('heres something i want to pass my function method')
// will console.log heres something i want to pass my function method
console.log(methodFunction().myMethod())
// will console.log the date as it is returned from the function method

Здесь мы впервые вызываемфункция, которую мы передаем в строке «вот что-то, что я хочу передать моему методу функции», который мы выходим из метода функции, где он входит в качестве аргумента «аргумент»

во второй раз, когда мы не передаемстрока, так что ничто не является консолью, зарегистрированной как побочный эффект функции, и вместо этого возвращаемая новая функция Date () записывается в консоль как значение, возвращаемое функцией

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...