简体   繁体   English

从JavaScript中的对象调用具有正确参数的函数

[英]Invoke a Function with the Correct Parameters from an Object in JavaScript

Let's say I have an object that looks like this: 假设我有一个看起来像这样的对象:

{
     'apple': 'nice',
     'banana': 'decent',
     'cherry': 'yuck',
}

and I have these two methods: 我有两种方法:

function eatItems(cherry, apple) { }
function throwItem(banana) { }

My two questions: 我的两个问题:

  1. Is it possible for me to invoke eatItem and send the arguments in the correct order? 我可以调用eatItem并以正确的顺序发送参数吗? Maybe something like: 也许像这样:

    eatItems.call(this, {'cherry': cherry, 'apple': apple}); eatItems.call(this,{'cherry':cherry,'apple':apple});

  2. What if I don't know what arguments eatItems receives, can I dynamically look up the names of the arguments for a function so I can know the order that I need to throw them in? 如果我不知道eatItems接收什么参数,该如何动态地查询一个函数的参数名称,以便知道将它们放入的顺序?

There's a way, indeed, and it involves calling toString on a function: 确实有一种方法,它涉及到在函数上调用toString

var source = eatItems.toString();
// => "function eatItems(cherry, apple) { }"

The next step is to parse the string you've got to get the names of the arguments: 下一步是解析要获取参数名称的字符串:

var args = source.substring(source.indexOf("(") + 1, source.indexOf(")")),
    argNames = /\S/.test(args) ? args.split(/\s*,\s*/) : [];

A few caveats: 一些警告:

  1. This solution has been kept quite simple. 该解决方案一直保持非常简单。 It doesn't handle comments in the function definition. 它不处理函数定义中的注释。
  2. Not every browser can correctly convert a function to a string (the PS3 browser comes to my mind), but they're a really small minority anyway. 并不是每个浏览器都能正确地将函数转换为字符串(我想到了PS3浏览器),但是无论如何它们只是很小的一部分。
  3. I haven't tested it, but there may be some performance issues on slower machines and/or older browsers with large functions. 我尚未对其进行测试,但是在速度较慢的计算机和/或功能较旧的旧版浏览器上可能存在一些性能问题。

And, overall, this solution is more like an exercise. 总体而言,此解决方案更像是一种练习。 I wouldn't recommend taking this pattern in Javascript. 我不建议在Javascript中采用这种模式。 Don't forget that some functions handle a variable number of arguments, and you won't find them listed in their definition. 别忘了有些函数处理可变数量的参数,并且您不会在它们的定义中找到它们。 Rethink your code, and find a better way. 重新考虑您的代码,并找到更好的方法。

If I understand correctly you want extract the argument names from the function, and inject data from an object based on those names. 如果我理解正确,则需要从函数中提取参数名称,并基于这些名称从对象中注入数据。 This can be accomplished by converting the function to a string, extracting the arguments, and applying the function with those arguments: 这可以通过将函数转换为字符串,提取参数并使用带有这些参数的函数来实现:

function inject(data, f) {
  var args = f.toString()
    .match(/function\s*?\((.+?)\)/)
    .pop()
    .split(',')
    .map(function(a){return data[a.trim()]})
  return function() {
    return f.apply(this, args)
  }
}

var data = {
  apple: 'nice',
  banana: 'decent',
  cherry: 'yuck',
}

var eat = inject(data, function(cherry, apple) {
  console.log(cherry, apple)
})

eat() //=> yuck, nice

The obvious problem with this approach is that it is highly dependent on the variable names, so when you minify your code, the variables will get mangled and the function will stop working. 这种方法的明显问题是它高度依赖于变量名,因此,当您压缩代码时,变量将被弄乱,函数将停止工作。 This is a known problem in AngularJS, which uses something similar for their dependency injection. 这是AngularJS中的一个已知问题,它对依赖项注入使用了类似的方法。

This is often an XY problem, or an anti-pattern at the very least. 这通常是XY问题,或者至少是反图案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM