递归地连接javascript函数参数

时间:2009-01-31 23:46:46

标签: javascript recursion variadic-functions

我遇到了一个javascript难题: 编写一行JavaScript代码,用于连接传递给函数的所有字符串:


    function concatenate(/*any number of strings*/) {
      var string = /*your one line here*/
      return string;
    } 

@ meebo

看到函数参数表示为索引对象可能是一个数组,我认为可以以递归方式完成。但是我的递归实现会抛出错误。 - “conc.arguments.shift不是函数” -


    function conc(){
        if (conc.arguments.length === 0) 
            return "";
        else 
            return conc.arguments.shift() + conc(conc.arguments);
}

似乎conc.arguments不是数组,但可以通过数字索引访问并具有长度属性???令人困惑 - 请分享意见和其他递归实施。

由于

6 个答案:

答案 0 :(得分:12)

arguments is said to be类似于数组的对象。正如您已经看到的那样,您可以通过索引访问其元素,但是您没有所有可用的Array方法。类似Array的对象的其他示例是getElementsByTagName()或getElementsByClassName()返回的HTML集合。 jQuery,如果你曾经使用它,它也是一个类似数组的对象。在查询了一些DOM对象之后,在DOM选项卡中使用Firebug检查生成的jQuery对象,你会看到我的意思。

这是我对Meebo问题的解决方案:

function conc(){
    if (arguments.length === 0)
        return "";
    else
        return Array.prototype.slice.call(arguments).join(" ");
}

alert(conc("a", "b", "c"));

Array.prototype.slice.call(arguments)是将arguments转换为可验证的Array对象的好方法。在Firefox Array.slice.call(arguments)就足够了,但它在IE6中不起作用(至少),所以前一版本是常用的。此外,这个技巧不适用于IE6中DOM API方法返回的集合(至少);它会抛出一个错误。顺便说一下,可以使用call代替apply

关于类似数组的对象的一点解释。在JavaScript中,您可以使用几乎任何东西来命名对象的成员,而数字也不例外。所以你可以构造一个看起来像这样的对象,这是完全有效的JavaScript:

var Foo = {
    bar : function() {
        alert('I am bar');
    },

    0 : function() {
        alert('I am 1');
    },

    length : 1
}

上述对象是一个类似于Array的对象,原因有两个:

  1. 它的成员名称是数字,因此它们就像数组索引
  2. 它具有length属性,没有该属性,您无法使用构造将对象转换为可验证的数组:Array.prototype.slice.call(Foo);
  3. Function对象的arguments对象与Foo对象非常相似,只是它有其特殊用途。

答案 1 :(得分:7)

Mozilla on the subject

  

arguments对象不是数组。它   类似于数组,但没有任何数组   除长度外的属性。例如,   它没有pop方法。   但它可以转换为真实的   阵列:

var args = Array.prototype.slice.call(arguments);

因此,您的问题的解决方案非常简单:

var string = Array.prototype.slice.call(arguments).join("");
BTW:它进一步指出:

  

arguments对象是本地的   所有变量都可用   功能;作为财产的论据   无法再使用该功能。

您应该只使用arguments代替func.arguments

答案 2 :(得分:6)

这有效:

function concatenate(){
    return [].join.call(arguments, "");
}
alert(concatenate("one", "two", "three"));

答案 3 :(得分:1)

参数列表不是真正的数组。我认为你可以借用数组方法并在带有“call”或“apply”的参数上使用它们。

答案 4 :(得分:1)

你可以这样做:

function concatenate() {
    if (arguments.length > 1) {
        return arguments[0] + concatenate.apply(this, Array.prototype.splice.call(arguments, 1));
    }
    return arguments[0];
}

答案 5 :(得分:0)

它可以与Array.prototype的至少6种不同方法(我怀疑还有更多)配合使用,即joinslicespliceconcatreduceflat。可能最短的方法是使用join,这是@@ svinto的上述解决方案。 g与@GeorgSchölly的答案相同。

Voilà的六个解决方案:

function f(){
  return [].join.call(arguments,'');
}
function g(){
  return [].slice.call(arguments).join('');
}
function h(){
  return [].splice.call(arguments,0).join('');
}
function i(){
  return [].concat.apply([], arguments).join('');
}
function j(){
  return [].reduce.call(arguments,function(buff,x){return buff+x},'');
}
function k(){
  return [].flat.call(arguments).join('');
}
document.getElementById('F').textContent = f('a','b','c');
document.getElementById('G').textContent = g('a','b','c');
document.getElementById('H').textContent = h('a','b','c');
document.getElementById('I').textContent = i('a','b','c');
document.getElementById('J').textContent = j('a','b','c');
document.getElementById('K').textContent = k('a','b','c');
<pre id='F'></pre>
<pre id='G'></pre>
<pre id='H'></pre>
<pre id='I'></pre>
<pre id='J'></pre>
<pre id='K'></pre>