js 代码,函数中如何进行追加写入新代码

2020-08-06 08:52:43 +08:00
 mostkia

这里有一个很基本的函数:

function box(val){
	console.log('假设这是函数原有代码');
	val();  //这是回调函数
}

现在控制台运行它的结果是这样的:

box(function(){console.log('回调函数 01')});  //返回 [假设这是函数原有代码] + [回调函数 01 ] 
box(function(){console.log('回调函数 02')});  //返回 [假设这是函数原有代码] + [回调函数 02 ] 

很正常,上一次的结果被这次的参数替代掉了

现在要达到的需求:

box(function(){console.log('回调函数 01')});  //返回 [假设这是函数原有代码] + [回调函数 01 ] 
box(function(){console.log('回调函数 02')});  //返回 [假设这是函数原有代码] + [回调函数 01 ] + [回调函数 02 ] 

说简单点就是:如何在一个函数内追加新的代码片段,更新这个 box 函数,还不能执行它(它也是回调函数,有条件才能激活的) 请问该如何做到,如果有懂得 v 友,还希望不要吝啬赐教。

4097 次点击
所在节点    JavaScript
30 条回复
krixaar
2020-08-06 08:57:54 +08:00
没看明白,你为啥不能传个存了一堆不同函数的数组进去一个个跑?
mostkia
2020-08-06 09:03:22 +08:00
@krixaar 因为传入函数是随机的,不是预置在内部的,否则就好处理了😂而且可能随时增加新的函数进去,怎么说呢,有点类似于这个吧 window.addEventListener,写入了一个回调,再次写入一个新的,不会覆盖上次的代码。
kop1989
2020-08-06 09:07:12 +08:00
首先,这个需求不符合代码设计逻辑,典型的腐败代码。
理论上讲,一个 function,输入相同的参数,输出也应该是固定逻辑的。值不一定相同,但是逻辑处理要稳定。

其次,如果这个需求描述正确的话:
1 、box 是否能改?如果能改则可以传递 function 的数组解决。
2 、如果 box 不能改,则从回调函数入手,你可以把逻辑累加这个过程放在 box 外面维护。
yaphets666
2020-08-06 09:08:49 +08:00
function(...arg) {
arg.forEach(item=>{
item()
})
}
en20
2020-08-06 09:08:55 +08:00
加个参数 eval 一下?
hoythan
2020-08-06 09:09:29 +08:00
他的意思明显就是想要实现 php 的 filter 和 action 功能。
journey0ad
2020-08-06 09:10:14 +08:00
闭包+数组
ccraohng
2020-08-06 09:10:44 +08:00
看起来是要把以前传入的也保留?
顶层用一个数组,每次传入保存进去,返回所有数组的执行结果
tyx1703
2020-08-06 09:12:38 +08:00
闭包可解

const box = (() => {
const callbacks = [];
return (callback)=> {
if (callback instanceof Function) {
callbacks.push(callback);
return;
}
callbacks.forEach(callback => {
callback();
});
}
})();
ianva
2020-08-06 09:23:55 +08:00
``` javascript
const box = (() => {
const callbackList = [];
return callback => {
callbackList.push(callback);
callbackList.forEach(item => item());
};
})();
```
mostkia
2020-08-06 09:28:14 +08:00
@kop1989 是的,我也感觉不太符合正常的代码逻辑,不过具体项目只有我最清楚,关于这方面我会仔细考虑的,感谢你的意见。
@en20 @journey0ad @ccraohng @tyx1703 看来意见是出奇的一致,我朝这个方向研究一下,我一开始也感觉闭包可以做到,但以往都是传递保留数据,没试过函数,一下子不知道该从何入手。

感谢诸位出谋划策,不一一 @了,已发感谢~
cin
2020-08-06 09:29:55 +08:00
var box = val => {
const fn0 = () => {
console.log('假设这是函数原有代码')
}
const fns = [fn0]
box = fn => {
fns.push(fn)
fns.forEach(fn => fn())
}
box(val)
}
azcvcza
2020-08-06 09:30:19 +08:00
要存东西,里面的状态要独立,且可更新,在 js 里就只能用闭包了
ianva
2020-08-06 09:31:17 +08:00
JavaScript 这个语言就闭包这一个特性能拿的出手吧,其他都是点缀,还是要多了解
mostkia
2020-08-06 09:39:48 +08:00
@ianva 好的,的确得多了解
@cin 感谢,已经找到思路了
@azcvcza 好的,目前已经解决这个问题。
cyrbuzz
2020-08-06 09:55:48 +08:00
在更进一步,数组外层再用一个对象(可以用 weakMap 不会造成垃圾回收的负担额)包裹。
liberty1900
2020-08-06 10:02:33 +08:00
这个就是简单的 memorization, 写过 react 或者尝试过函数式编程应该都知道
都说在 JS 里函数是第一公民,其实意思是函数就和普通变量一样,但实际函数可以做的更多,实际上应该是特等公民
wellsc
2020-08-06 10:09:08 +08:00
@ianva 还有原型链
stillsilly
2020-08-06 10:09:15 +08:00
用装饰者模式

运行结果截图:
https://i.loli.net/2020/08/06/UlrdQPqua1sCiDK.png

代码:
function box(){
console.log('假设这是函数原有代码');
}
function 装饰 box(){
var _box = box
function 新加的函数(){
console.log('这是新加的函数')
}
box = function (){
_box()
新加的函数()
}

}
装饰 box()
box()
libook
2020-08-06 10:29:29 +08:00
基本思路就是在这个函数能被调用的整个生命周期里,开辟一个存储空间来存每次传入的 callback,然后每次调用这个函数都从这个存储空间里读出之前所有传入过的 callback 一起调用。

上面楼层都给出了实际的代码。

有一个问题需要注意,就是你开辟的存储空间是有限的,在长时间高频调用的情况下,理论上有可能达到上限而抛出错误,而且因为每次执行的函数数量递增,执行需要的计算量和时长也会逐渐增加。

从代码可读性上,可以调整代码结构或增加注释来让看代码的人很快意识到这个函数的特殊性。
比如可以创建一个 Class,实例化的对象的状态保存在对象内部,通过调用对象的方法来实现你的功能。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/696018

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX