您可以动态地建立方法调用链吗?

时间:2018-06-26 14:51:49

标签: javascript methods dynamic

我遇到了一些代码,试图重构他们将JavaScript作为字符串编写并将其放在HTML脚本标签中,然后将其写入DOM的位置。非常难看且无法维护。但是,这允许他们做的一件事是通过附加到字符串来构建函数调用。

var methods = '';
for (key in obj) {
  methods += 'func1("'+key+'", "'+obj[key]+'").';
}    
var scriptString = '<script>func2().' + methods + 'func3();</script>'

结果可能是:

'<script>func2().func1("key1", "value1").func1("key2", "value2").func3();</script>'

因此,由于我真的不赞成在JavaScript内的HTML字符串内编写JavaScript ...有人知道如何使用纯JavaScript来实现相同的结果吗?有没有一种方法可以通过迭代对象来将方法连续地追加到函数调用中?

2 个答案:

答案 0 :(得分:1)

您可以创建一个函数,该函数针对对象中的所有键/值对重复调用func1方法。

var script = function(obj) {
    var value = func2();
    for (var key in obj) {
        value = value.func1(key, obj[key]);
    }
    value.func3();
};

答案 1 :(得分:1)

Array.reduce()应该可以满足您的大部分需求。

棘手的部分是.func1()方法调用链,在此依赖于对象的键/值对。如果您不习惯使用Array.reduce()方法,我建议您通读MDN documentation,但是它基本上遍历一个数组,对前一个结果执行转换,直到到达最后,返回最终结果。这可以发挥我们的优势,因为方法链接只是对前一个方法调用的返回值的方法调用。但是,由于这是一个数组方法,因此我们需要首先将对象的条目放入数组中……这就是Object.entries()进入的地方。

请注意,我的大部分语法都包含新功能,目标浏览器可能会或可能不支持这些新功能。如有必要,请确保使用Transpiler和polyfills处理向后移动。

请参见以下示例:

const wrapperFunc = (obj) => {

    // Start with func2()
    const func2Result = func2()
  
    // Chain to func1() for each entry in obj (the tricky part)
    const func1Result = Object.entries(obj).reduce(

        // Call func1 method on previous result to get the next result
        (prevResult, [ key, val ]) => prevResult.func1(key, val),

        // Initial "prevResult" value used above
        func2Result
    )
  
    // Chain to func3()
    return func1Result.func3()
}

// Inject object to be used for func1() calls
wrapperFunc({
    key1: 'value1',
    key2: 'value2'
})

此外,这是第二个更复杂的示例,其中包含一些已实现的方法。与上面的示例不同,该示例实际上可以运行。

class MyObject {
  constructor() {
    this.innerString = ''
  }

  // Chainable method (returns this)
  func1(key, val) {
    this.innerString += `${key}, ${val} `
    return this
  }

  func3() {
    return this.innerString.trim()
  }
}


const func2 = function () {
  return new MyObject()
}

const wrapperFunc = (obj) => {

  // Start with func2()
  const func2Result = func2()

  // Chain to func1() for each entry in obj (the tricky part)
  const func1Result = Object.entries(obj).reduce(

    // Call func1 method on previous result to get the next result
    (prevResult, [ key, val ]) => prevResult.func1(key, val),

    // Initial "prevResult" value used above
    func2Result
  )

  // Chain to func3()
  return func1Result.func3()
}

// Inject object to be used for func1() calls
console.log(wrapperFunc({
  key1: 'value1',
  key2: 'value2'
}))