我正在尝试编写一个函数,它要么接受字符串列表,要么接受单个字符串。如果它是一个字符串,那么我想把它转换成一个只有一个项的数组,这样我就可以在上面循环,而不用担心出错。

那么如何检查变量是否为数组?


当前回答

 var length = 16;                               // Number
 var lastName = "Johnson";                      // String
 var cars = ["Saab", "Volvo", "BMW"];           // Array
 var x = {firstName:"John", lastName:"Doe"};

 Object.prototype.myCheck= function(){
 if (this.constructor === Array){
          alert('array');
        }else if (this.constructor === Object)
       {
         alert('object');
        }else if (this.constructor === Number)
        {
          alert('number');
        }else if (this.constructor === String)
        {
          alert('string');
        }

 }
 cars.myCheck();
 lastName.myCheck();
 length.myCheck();

其他回答

此函数将几乎所有内容转换为数组:

function arr(x) {
    if(x === null || x === undefined) {
        return [];
    }
    if(Array.isArray(x)) {
        return x;
    }
    if(isString(x) || isNumber(x)) {
        return [x];
    }
    if(x[Symbol.iterator] !== undefined || x.length !== undefined) {
        return Array.from(x);
    }
    return [x];
}

function isString(x) {
    return Object.prototype.toString.call(x) === "[object String]"
}

function isNumber(x) {
    return Object.prototype.toString.call(x) === "[object Number]"
}

它使用了一些较新的浏览器功能,因此您可能需要对其进行多填充以获得最大支持。

示例:

> arr(null);
[]
> arr(undefined)
[]
> arr(3.14)
[ 3.14 ]
> arr(1/0)
[ Infinity ]
> gen = function*() { yield 1; yield 2; yield 3; }
[Function: gen]
> arr(gen())
[ 1, 2, 3 ]
> arr([4,5,6])
[ 4, 5, 6 ]
> arr("foo")
[ 'foo' ]

N.B.字符串将被转换为具有单个元素的数组,而不是字符数组。如果您希望使用其他方式,请删除isString复选框。

我在这里使用了Array.isArray,因为它是最健壮的,也是最简单的。

虽然有一些可靠的答案,但我更喜欢使用函子的函数方法。函子只是一种奇特的方式,可以说我们将把一个函数传递给一个值。(我看到的建议是将值传递给函数。)

创建TypeOf助手

const TypeOf = obj => Object.prototype.toString.call(obj).slice(8,-1);

这类似于typeof,但现在它为[]返回Array,为{}返回Object。我喜欢把它看作是一种严格的类型。如果你正在使用Gmail应用程序,性能是一个问题,那么你可以这样做。

const TypeOf = obj => (
  Array.isArray(obj)
   ? "array"
    : obj === null // catch null edge case.  typeof null is an object :)
   ? null
    : typeof obj
)

你可以停下来休息一下。然而,您可以使用合成使其更加强大。如果你创建了一个TypeBox Functor,你会得到很多好处,这也是一个将函数传递给值而不是将值传递给函数的好词。

创建TypeBox

const TypeBox = (predicate, defaultValue) => {
  const TypePredicate = value => ({
     value,
     map: cb => predicate(value)
                ? TypePredicate(cb(value))
                : TypePredicate(defaultValue)
  });
  return TypePredicate;
}

这里有很多事情,但它非常强大。TypeBox函数使用闭包并返回我们的Functor。闭包允许您访问Lexical_Scope。把它想象成一个背包,里面装着你以后想接触的东西。

创建ArrayBox

const ArrayBox = TypeOf(obj => TypeOf(obj) === 'Array' ? obj : [obj]);

ArrayBox正在将我们的谓词和defaultValue传递给TypeOf,并且在我们调用/执行ArrayBox时将可用(根据您的用例命名)。

现在有趣的部分

如果输入是数组,则返回它。

ArrayBox(["foo", "bar"]).value; // ['foo', 'bar']

如果输入不是数组,请将其返回一个

ArrayBox("foo").value // ["foo"]

这种方法的优点在于它可以扩展,易于测试,并且使用了合成。您可以以任何方式组合函数以获得所需的结果。

我们还有很多其他方法可以使用非此即彼或monads来实现这一点。

检查此项的简单函数:

function isArray(object)
{
    return object.constructor === Array;
}

也存在其他方法来检查,但我更喜欢以下方法作为我的最佳检查方法(因为您可以轻松检查其他对象的类型)。

> a = [1, 2]
[ 1, 2 ]
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>
> Object.prototype.toString.call([]).slice(8,-1) // best approach
'Array'

解释(节点REPL上的简单示例)»

> o = {'ok': 1}
{ ok: 1 }
> a = [1, 2]
[ 1, 2 ]
> typeof o
'object'
> typeof a
'object'
>
> Object.prototype.toString.call(o)
'[object Object]'
> Object.prototype.toString.call(a)
'[object Array]'
>

对象或阵列»

> Object.prototype.toString.call(o).slice(8,).replace(/\]$/, '')
'Object'
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>

空或未定义»

> Object.prototype.toString.call(undefined).slice(8,).replace(/\]$/, '')
'Undefined'
> Object.prototype.toString.call(null).slice(8,).replace(/\]$/, '')
'Null'
>

字符串»

> Object.prototype.toString.call('ok').slice(8,).replace(/\]$/, '')
'String'

编号»

> Object.prototype.toString.call(19).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.0).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.7).slice(8,).replace(/\]$/, '')
'Number'
>

我很感谢@mpen建议使用-1代替正则表达式,如下所示。

> Object.prototype.toString.call(12).slice(8,-1)
'Number'
>
> Object.prototype.toString.call(12.0).slice(8,-1)
'Number'
>
> Object.prototype.toString.call([]).slice(8,-1)
'Array'
> Object.prototype.toString.call({}).slice(8,-1)
'Object'
>
> Object.prototype.toString.call('').slice(8,-1)
'String'
>

因为我不喜欢任何Object.prototype调用,所以我寻找了另一种解决方案。特别是因为ChaosPandion的解决方案并不总是有效的,并且MidnightTortoise的isArray()解决方案不适用于来自DOM的数组(如getElementsByTagName)。最后,我找到了一个简单的跨浏览器解决方案,这可能也适用于Netscape 4

只有这四行(检查任何对象h):

function isArray(h){
    if((h.length!=undefined&&h[0]!=undefined)||(h.length===0&&h[0]===undefined)){
        return true;
    }
    else{ return false; }
}

我已经测试了这些数组(全部返回true):

1) array=d.getElementsByName('some_element'); //'some_element' can be a real or unreal element
2) array=[];
3) array=[10];
4) array=new Array();
5) array=new Array();
   array.push("whatever");

这适用于所有情况吗?或者我的解决方案不起作用?