首页 > 解决方案 > 在函数表达式(或函数声明)中添加方法

问题描述

我想尽可能简单地向函数表达式添加一个方法。就我而言,我使用函数表达式,但函数声明也可以。由于函数是对象,我想这是可能的。但是怎么做?


细节:

我想尽可能简单直接地添加方法,所以我既不想使用构造函数也不想使用继承。

以下代码将方法 ( 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) 
.....

更新:

最初,我使用 Douglas Crockford 的术语“函数文字”而不是函数表达式,但现在更新了标题和问题。

为了回应 Teemu 的建议,我尝试了以下代码:

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.listenersecondsEvent.setListener每次secondsEvent调用,我使用以下内容:

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

是否有更好的解决方案只设置一次属性?也许是一些 js 初始化习惯用法?(我知道将它从函数中提取出来是另一种解决方案,但这会导致我想要避免的第一个解决方案,因为在函数表达式(或函数声明,无论您使用哪个)中包含属性定义会更好),在它们被使用之前。

标签: javascriptfunctionobject

解决方案


您说的是“函数文字”,但 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 的用户不会感到惊讶。


推荐阅读