【问题标题】:How do I wrap a javascript function with dynamic arguments?如何使用动态参数包装 javascript 函数?
【发布时间】:2017-01-22 15:47:36
【问题描述】:

我想包装一些动态创建的 javascript 函数,类似于 Daniel 在这里接受的答案: How do I store javascript functions in a queue for them to be executed eventually

// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
    return function() {
        fn.apply(context, params);
    };
}

不同之处在于我希望参数值在执行时是动态的 - 是否可以在参数中传递对变量的引用,该变量可以在包装后更新?

这是我想做的:

// I have a function to be wrapped
var sayStuff = function(a,b) {
    console.log(a);
    console.log(b);
}

// Variables I'd like to pass
var randomNumberA = 0;
var randomNumberB = 0;

// Wrap the function
var fun = wrapFunction(sayStuff, this, [*reference randomNumberA*,*reference randomNumberB*]);

// variables get changed
randomNumberA = Math.random()*100;
randomNumberB = Math.random()*100;

// Execute the function using current values of randomNumberA & randomNumberB
fun();

如果可能的话,我想在不改变 sayStuff 的情况下这样做,我有很多像这样的现有函数我希望包装,它们也可以在包装之外使用,所以理想情况下我不想替换带有对象的参数。 希望这是有道理的,谢谢!

【问题讨论】:

  • 虽然可能,但对于this 的上下文,我通常会说不,我不确定您究竟为什么要这样做?
  • 你应该仔细看看原语总是按值传递以及函数和方法之间的区别。当一个函数依赖于this 时,它就变成了一个方法,而你的函数都没有。
  • @Xotic750 所以我包装的函数是一堆音频过滤器。他们按顺序执行。但我想随机化它们的顺序和设置,所以我想把它们包装在一些通用的东西中。不过,他们的一些论点需要是动态的。我希望将每个对象包装在一个对象中,以便该对象成为我认为的上下文
  • 使用你自己的对象作为上下文应该没问题。

标签: javascript function dynamic arguments wrapper


【解决方案1】:

如果动态参数在上下文参数中定义,解决方案可以基于传递变量的名称,然后在执行时计算其当前值:

var wrapFunction = function(fn, context) {
  var xArg = arguments;
  return function() {
    var argsArray = [];
    for (var i = 2; i < xArg.length; i++) {
      argsArray.push(context[xArg[i]]);
    }
    fn.apply(context, argsArray);
  };
}

var sayStuff = function() {
  for (var i = 0; i < arguments.length; i++) {
    console.log('sayStuff func: ' + arguments[i]);
  }
}

var randomNumber1 = 0;
var randomNumber2 = 0;

var fun = wrapFunction(sayStuff, this, 'randomNumber1', 'randomNumber2');

randomNumber1 = Math.random()*100;
randomNumber2 = Math.random()*100;

console.log('randomNumber1: ' + randomNumber1);
console.log('randomNumber2: ' + randomNumber2);

fun();

【讨论】:

  • @Xotic750 对不起我的英语,你能简化一下你的想法吗?我敢肯定你说的是有用的东西。所以,我有兴趣学习。非常感谢。
  • this 可以是 undefined 尝试将代码包装在 (function () {...}()); 中需要额外的工作,所以这并不是 OP 问题的真正通用解决方案,但确实适用于他们非常具体例子。
  • 请注意,我还在 jsfiddle 中将 Javascript 选项设置为 no wrap - in &lt;body&gt;。如果您只是将代码粘贴到新的 jsfiddle 中,您还会发现它不适用于默认的 onload
  • 非常感谢您的解释。很高兴您的分享
  • 没问题,这不是一个很好的解释,只是几个 cmets。主题远不止于此。
【解决方案2】:

如果函数和变量将在同一范围内创建,您可以使用它:

var randomNumber = 0;
var fun = function(){ alert(randomNumber); }

randomNumber = 10;

// Now this will alert 10, because when fun is executed
// JS looks in his scope to find what randomNumber is.
fun();

这是因为 javascript 中的函数作为闭包工作,它们携带着它们的环境。见:https://en.wikipedia.org/wiki/Closure_(computer_programming)

因此,如果randomNumber 将被更改到您绑定该函数的范围之外,您需要使用一个对象,这是因为在 javascript 中我们没有“指针”或要传递的引用。一种方法是使用对象。

function giveMeAFunction(){
  var params = { randomNumber: 0 }
  var fun = function(){ alert(scope.randomNumber); }
  return {fun: fun, scope: scope};
}

var paramsAndFun = giveMeAFunction()
// Now you can change the variables in the scope and call the function
paramsAndFun.params.randomNumber = 10;
paramsAndFun.fun(); // Will alert 10

// Now if you replace the entire params object it will not work
// This is because you will replacing it with a new object while
// The one that is referenced in the scope where fun was created is
// the old one.
paramsAndFun.params = { randomNumber: 15 };
paramsAndFun.fun(); // will still alert 10

现在让我们来解决问题的一部分。

已经有Function.prototype.bind 功能可以帮助您。

例如:

var sayStuff = function(opts) {
    alert(otions.randomNumber);
}

var options = { randomNumber: 0 };
var fun = sayStuff.bind(this, options);

options.randomNumber = 10;

fun(); // Will print 10

这里发生了很多事情。对不起,如果我把一切都弄糊涂了。

【讨论】:

  • 啊,谢谢,没道理。我意识到我应该提到理想情况下我会保持 sayStuff 相同(刚刚更新了问题),因为它是一个已经存在的函数,如果可能的话,我想保持它的参数不变。如果这不可能,那么使用这样的对象肯定会起作用 - 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 2015-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多