javascript - 在函数表达式(或函数声明)中添加方法
问题描述
我想尽可能简单地向函数表达式添加一个方法。就我而言,我使用函数表达式,但函数声明也可以。由于函数是对象,我想这是可能的。但是怎么做?
细节:
我想尽可能简单直接地添加方法,所以我既不想使用构造函数也不想使用继承。
以下代码将方法 ( 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.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 初始化习惯用法?(我知道将它从函数中提取出来是另一种解决方案,但这会导致我想要避免的第一个解决方案,因为在函数表达式(或函数声明,无论您使用哪个)中包含属性定义会更好),在它们被使用之前。
解决方案
您说的是“函数文字”,但 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 的用户不会感到惊讶。
推荐阅读
- javascript - Vue图像src文件路径不起作用
- laravel-5 - 在 axios 获取后 {{ obj.data }} 未显示在 vue 模板中
- chatbot - 如何在 AWS Lex 中结束对话并停止对话?我想将对话委托给一个人
- vb.net - 查找给定日期和天数的日期
- javascript - 从javascript更改背景图像时无法找到图像
- ubuntu-16.04 - nmcli 连接到 ubuntu 16.04 中的特定 bssid
- javascript - onsubmit 返回 false 不起作用
- database - 在matlab中将数据写入大文件
- c# - 无法通过华为 U 盘调制解调器发送超过 140 条短信
- r - 如何计算逻辑向量中的序列