JavaScript:具有多个值的参数

时间:2015-03-10 16:14:31

标签: javascript function

此函数循环遍历JavaScript嵌套数组(递归)并替换其中的字符串:

function replaceRecur(tree, str, newStr) {
  for (var i = 1; i < tree.length; i++) {
    if (Array.isArray(tree[i])) {
      replaceRecur(tree[i], str, newStr)
    } else {
      tree[i] = tree[i].replace(str, newStr)
    }
  }
}

用法示例:

function replaceQuotes(tree, callback) {
  var str1 = /"(?=\b)/g
    , str2 = /"(?!\b)/g
    , newStr1 = '“'
    , newStr2 = '”'

  replaceRecur(tree, str1, newStr1)
  replaceRecur(tree, str2, newStr2)

  callback(null, tree) 
}

我应该如何修改replaceRecur,以便每个参数允许两个值?

示例:

function replaceQuotes(tree, callback) {
  var str = ['/"(?=\b)/g/', '"(?!\b)/g']
    , newStr = '“ ”' // not sure whether to use arrays or strings
                     // what's more common?

  replaceRecur(tree, str, newStr)

  callback(null, tree) 
}

(原因是,我不想重复replaceRecurstrnewStr两次。我想保留代码DRY。)

修改

示例输入(以防万一):

[ 'markdown',
  [ 'para', '“a paragraph”' ],
  [ 'hr' ],
  [ 'para', '\'another paragraph\'' ],
  [ 'para', 'test--test' ],
  [ 'para', 'test---test' ],
  [ 'bulletlist',
    [ 'listitem', '“a list item”' ],
    [ 'listitem', '“another list item”' ] ] ]

6 个答案:

答案 0 :(得分:3)

创建一个函数,该函数执行结构的递归遍历并调用值的回调。然后,您可以将替换函数编写为传入的回调函数:

function traverse(tree, callback) {
  for (var i = 0; i < tree.length; ++i) {
    if (Array.isArray(tree[i]))
      traverse(tree[i], callback);
    else
      tree[i] = callback(tree[i]);
  }
}

function replaceTwo(tree, s1from, s1to, s2from, s2to) {
  traverse(tree, function(element) {
    return element.replace(s1from, s1to).replace(s2from, s2to);
  });
}

您现在可以编写各种不同的函数来转换树内容,而无需重写递归部分。

答案 1 :(得分:1)

不幸的是,JavaScript中没有重载。

一个干净的解决方案是使用replaceRecur,但在内部检查typeof个参数,以确定您是否要使用_replaceRecur2_replaceRecur1

function replaceRecur(tree, arg1, arg2) {
  if(typeof(arg1) === "function"){
    _replaceRecur2(tree, arg1);
  } else {
    _replaceRecur1(tree, arg1, arg2);
  }
}

function _replaceRecur1(tree, str, newStr) {
  for (var i = 1; i < tree.length; i++) {
    if (Array.isArray(tree[i])) {
      _replaceRecur1(tree[i], str, newStr)
    } else {
      tree[i] = tree[i].replace(str, newStr)
    }
  }
}

function _replaceQuotes2(tree, callback) {
  var str1 = /"(?=\b)/g
    , str2 = /"(?!\b)/g
    , newStr1 = '“'
    , newStr2 = '”'

  _replaceRecur1(tree, str1, newStr1)
  _replaceRecur1(tree, str2, newStr2)

  callback(null, tree) 
}

答案 2 :(得分:1)

  

不确定是否使用数组或字符串

使用数组,您可能想要替换多个内容。你不会改变replaceRecur,它就好了。而是引入一个新功能

function replaceMultipleRecur(tree, strArr, newStrArr) {
    … // (in the simplest occasion a loop over the arrays with calls to replaceRecur)
}
function replaceQuotes(tree) {
    return replaceMultipeRecur([/"(?=\b)/g, /"(?!\b)/g], ['“', '”']);
}
  

我不想重复replaceRecur,str和newStr两次

您可以通过传递匹配所有案例的正则表达式和replacer callback而不是字符串来简单地使用您的exsting函数。

function replaceQuotes(tree) {
  replaceRecur(tree, /("\b)|("\B)/g, function(m, l, r) {
      return l ? '“' : '”';
  });
  return tree
}

答案 3 :(得分:1)

如果您想更多地抽象代码,可以采用以下方法:

&#13;
&#13;
function maprec(x, callback) {
    return x.map ? x.map(function(x) {
        return maprec(x, callback);
    }) : callback(x);
}

function pipe() {
    var fns = arguments;
    return function(x) {
        return [].reduce.call(fns, function(a, f) { return f(a) }, x);
    }
}

// test/demo:

tree = ['foo "bar" !', ['baz', ['ccc "hi" ', 'd']], 'eee', ['"foo?"']];

converted = maprec(tree, pipe(
    function(x) { return x.replace(/"(?=\b)/g, '{') },
    function(x) { return x.replace(/"(?=\B)/g, '}') }
));

document.write("<pre>" + JSON.stringify(converted));
&#13;
&#13;
&#13;

好的,我们在这做了什么?首先,我们定义maprec,一个递归映射器,它与map相同,但尊重嵌套结构。第二个实用程序pipe是函数编写器,它接受一堆函数并返回一个新函数,按顺序将这些函数应用于参数,类似于grep | sort | uniq之类的unix管道(由此得名)。请注意,这与通常的compose不同,后者是右关联的。最后,我们使用maprec(tree, pipe(replacer1, replacer2))来完成实际工作。

(我使用{}而不是花哨的引号使它们在控制台窗口中看起来更明显。)

为了说明流水线的力量,这是一个更高级的例子:

fancyQuotes = pipe(
    function(x) { return x.replace(/"(?=\b)/g, '&laquo;') },
    function(x) { return x.replace(/"(?=\B)/g, '&raquo;') }
);

trim = "".trim.call.bind("".trim);

wrap = function(x) { return this.replace(/\$/g, x)};
wrap.in = wrap.bind;

converted = maprec(tree, pipe(
    fancyQuotes,
    trim,
    wrap.in("<p>$</p>")));

答案 4 :(得分:0)

前言:我和Bergi在一起comment above,只是两次调用函数并不意味着你在重复自己。将复杂性添加到一个简单的函数以避免调用它不一定是个好主意。


但是对于你的问题:你可以在函数中添加两个参数,如果没有给出则忽略它们:

function replaceRecur(tree, str1, newStr1, str2, newStr2) {
  for (var i = 1; i < tree.length; i++) {
    if (Array.isArray(tree[i])) {
      replaceRecur(tree[i], str1, newStr1, str2, newStr2);
    } else {
      tree[i] = tree[i].replace(str1, newStr1);
      if (typeof str2 !== "undefined") {
        tree[i] = tree[i].replace(str2, newStr2);
      }
    }
  }
}

事实上,你可以通过循环无休止地继续这样做。

function replaceRecur(tree, str, newStr/*, str2, newStr2, ...*/) {
  for (var i = 1; i < tree.length; i++) {
    if (Array.isArray(tree[i])) {
      replaceRecur.apply(this, arguments);
    } else {
      for (var arg = 1; arg + 1 < arguments.length; arg += 2) {
        tree[i] = tree[i].replace(arguments[arg], arguments[arg + 1]);
      }
    }
  }
}

请注意,在使用arguments伪阵列的某些JavaScript引擎上,会对性能产生负面影响。在现代引擎上它根本不重要。

用法:

replaceRecur(tree, /"(?=\b)/g, '“', /"(?!\b)/g, '”');

答案 5 :(得分:0)

只需更改else即可在数组中应用每个正则表达式。

else {
    //array is the array of regex's passed
    array.forEach(function(item) {
        tree[i] = tree[i].replace(item, newStr);
    });
}