如何在 JavaScript 中初始化数组的长度?

IT技术 javascript arrays jslint
2021-01-27 04:27:59

我读过的关于 JavaScript 数组的大部分教程(包括w3schoolsdevguru)都建议您可以通过使用var test = new Array(4);语法将整数传递给 Array 构造函数来初始化具有特定长度的数组

在我的 js 文件中大量使用此语法后,我通过jsLint运行了其中一个文件,它吓坏了:

错误:第 1 行字符 22 出现问题:应为 ')' 而看到的是 '4'。
var test = new Array(4);
第 1 行字符 23 处的问题:应为 ';' 而是看到了')'。
var test = new Array(4);
第 1 行字符 23 出现问题:需要一个标识符,但看到的是“)”。

在阅读了jsLint 对其行为的解释后,看起来 jsLint 并不真正喜欢new Array()语法,而是[]在声明数组时更喜欢

所以我有几个问题:

首先,为什么?我是否会因为使用new Array()语法而冒任何风险是否存在我应该注意的浏览器不兼容问题?

其次,如果我切换到方括号语法,是否有任何方法可以声明一个数组并将其长度全部设置在一行上,或者我是否必须执行以下操作:

var test = [];
test.length = 4;
6个回答
  • Array(5) 为您提供一个长度为 5 但没有值的数组,因此您无法对其进行迭代。

  • Array.apply(null, Array(5)).map(function () {}) 为您提供一个长度为 5 且未定义为值的数组,现在可以对其进行迭代。

  • Array.apply(null, Array(5)).map(function (x, i) { return i; }) 为您提供一个长度为 5 且值为 0、1、2、3、4 的数组。

  • Array(5).forEach(alert)什么都不做,Array.apply(null, Array(5)).forEach(alert)给你 5 个警报

  • ES6给我们Array.from所以现在你也可以使用Array.from(Array(5)).forEach(alert)

  • 如果你想用某个值初始化,这些很好知道...
    Array.from('abcde')Array.from('x'.repeat(5))
    或者Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]

为什么 Array.apply() 给它 undefined 作为值?
2021-03-18 04:27:59
@wdanxna 当Array给定多个参数时,它会遍历arguments对象并将每个值显式应用于新数组。当您Array.apply使用数组或具有长度属性的对象调用时Array将使用长度显式设置新数组的每个值。这就是为什么Array(5)给出 5 个省略Array.apply(null, Array(5))的数组,而给出 5 个未定义的数组。有关更多信息,请参阅答案。
2021-03-19 04:27:59
Array(5) 和 new Array(5) 有区别吗?
2021-03-27 04:27:59
这就是我一直在寻找的。我想在逻辑序列上应用地图;这应该这样做。谢谢!
2021-04-05 04:27:59
Array.apply(null, Array(5)) 也可以写成Array.apply(null, {length: 5})确实没有太大区别,但后者明确表示意图是创建 的数组length 5,而不是包含的数组5
2021-04-07 04:27:59
  1. 为什么要初始化长度?理论上没有这个必要。它甚至会导致令人困惑的行为,因为所有使用length来确定数组是否为空的测试都会报告该数组不为空。
    一些 试验表明,设定大的阵列的初始长度可以如果该阵列被充满之后更有效,但性能增益(如果有的话)似乎不同于浏览器的浏览器。

  2. jsLint 不喜欢,new Array()因为构造函数不明确。

    new Array(4);
    

    创建一个长度为4的空数组但是

    new Array('4');
    

    创建一个包含值 的数组'4'

关于您的评论:在 JS 中,您不需要初始化数组的长度。它动态增长。您可以将长度存储在某个变量中,例如

var data = [];
var length = 5; // user defined length

for(var i = 0; i < length; i++) {
    data.push(createSomeObject());
}
@mlms 只需让 for 循环遍历用户定义的数字,而不必设置数组长度然后遍历它。这对你来说不是更有意义吗?
2021-03-29 04:27:59
“你为什么要……”在 SO 上被问了很多次。FWIW 我认为当有人发布问题时,假设他们有一个合法的用例并从那里开始是合理的。
2021-03-29 04:27:59
数组中的对象数量是用户定义的,所以我让用户选择一个数字,然后用这么多插槽初始化数组。然后我运行一个for循环,遍历数组的长度并填充它。我想在 JavaScript 中还有其他方法可以做到这一点,所以真正的答案是“我为什么要这样做?” 是“因为用其他语言编程时形成的旧习惯。” :)
2021-03-31 04:27:59
<blockquote>为什么要初始化长度?理论上没有这个必要。并且所有使用长度来确定数组是否为空的测试都将失败。</blockquote> 嗯,也许是性能设置数组的预先存在的元素比动态添加它更快。
2021-04-04 04:27:59
@codehead:回应这个引用:“设置一个数组的预先存在的元素比动态添加它更快。”:注意new Array(10)不会创建一个包含 10 个未定义元素的数组。它只是创建一个长度为 10 的空数组。有关令人讨厌的事实,请参阅此答案:stackoverflow.com/questions/18947892/...
2021-04-04 04:27:59

使用ES2015,.fill()您现在可以简单地执行以下操作:

// `n` is the size you want to initialize your array
// `0` is what the array will be filled with (can be any other value)
Array(n).fill(0)

哪个比 Array.apply(0, new Array(n)).map(i => value)

可以0.fill()不带参数的情况下删除并运行,这将用undefined. 但是,这将在 Typescript 中失败

是的,请在评论前尝试
2021-03-17 04:27:59
@AP.,零是多余的。Array(n).fill()
2021-03-22 04:27:59
@Pacerier 我不认为 0 是多余的。根据es6类型定义,这是函数签名:fill(value: T, start?: number, end?: number): this; 因此填充值似乎不是可选的。Typescript 编译将失败,因为函数调用是在上面写的。
2021-03-23 04:27:59
@GarretWilson 和 @Christian 它在规范中When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments
2021-04-05 04:27:59
@AralRoca 您可以随时使用MDN 页面上提供Polyfill,或考虑使用Modernizr
2021-04-08 04:27:59
[...Array(6)].map(x => 0);
// [0, 0, 0, 0, 0, 0]

或者

Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]

注意:你不能循环空槽,即 Array(4).forEach(() => …)


或者

typescript安全

Array(6).fill(null).map((_, i) => i);
// [0, 1, 2, 3, 4, 5]

或者

使用函数的经典方法(适用于任何浏览器)

function NewArray(size) {
    var x = [];
    for (var i = 0; i < size; ++i) {
        x[i] = i;
    }
    return x;
}

var a = NewArray(10);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

创建嵌套数组

创建一个当二维数组与fill直觉应该创建新实例。但实际发生的是相同的数组将被存储为引用。

var a = Array(3).fill([6]);
// [  [6], [6], [6]  ]

a[0].push(9);
// [  [6, 9], [6, 9], [6, 9]  ]

解决方案

var a = [...Array(3)].map(x => []);

a[0].push(4, 2);
// [  [4, 2], [], []  ]

所以一个 3x2 数组看起来像这样:

[...Array(3)].map(x => Array(2).fill(0));
// [  [0, 0], [0, 0], [0, 0]  ]

N维数组

function NArray(...dimensions) {
    var index = 0;
    function NArrayRec(dims) {
        var first = dims[0], next = dims.slice().splice(1); 
        if(dims.length > 1) 
            return Array(dims[0]).fill(null).map((x, i) => NArrayRec(next ));
        return Array(dims[0]).fill(null).map((x, i) => (index++));
    }
    return NArrayRec(dimensions);
}

var arr = NArray(3, 2, 4);
// [   [  [ 0,  1,  2,  3 ] , [  4,  5,  6,  7]  ],
//     [  [ 8,  9,  10, 11] , [ 12, 13, 14, 15]  ],
//     [  [ 16, 17, 18, 19] , [ 20, 21, 22, 23]  ]   ]

初始化棋盘

var Chessboard = [...Array(8)].map((x, j) => {
    return Array(8).fill(null).map((y, i) => {
        return `${String.fromCharCode(65 + i)}${8 - j}`;
    });
});

// [ [A8, B8, C8, D8, E8, F8, G8, H8],
//   [A7, B7, C7, D7, E7, F7, G7, H7],
//   [A6, B6, C6, D6, E6, F6, G6, H6],
//   [A5, B5, C5, D5, E5, F5, G5, H5],
//   [A4, B4, C4, D4, E4, F4, G4, H4],
//   [A3, B3, C3, D3, E3, F3, G3, H3],
//   [A2, B2, C2, D2, E2, F2, G2, H2],
//   [A1, B1, C1, D1, E1, F1, G1, H1] ]

数学填充值

使用数学时方便的小方法重载


function NewArray( size , method, linear )
{
    method = method || ( i => i ); 
    linear = linear || false;
    var x = [];
    for( var i = 0; i < size; ++i )
        x[ i ] = method( linear ? i / (size-1) : i );
    return x;
}

NewArray( 4 ); 
// [ 0, 1, 2, 3 ]

NewArray( 4, Math.sin ); 
// [ 0, 0.841, 0.909, 0.141 ]

NewArray( 4, Math.sin, true );
// [ 0, 0.327, 0.618, 0.841 ]

var pow2 = ( x ) => x * x;

NewArray( 4, pow2 ); 
// [ 0, 1, 4, 9 ]

NewArray( 4, pow2, true ); 
// [ 0, 0.111, 0.444, 1 ]
刚注意到你回答最短的那个,非常好
2021-03-14 04:27:59
a[0].push(9); // [ [6, 9], [6], [6] ] 应该是 a[0].push(9); // [ [6, 9], [6, 9], [6, 9] ] 因为每个嵌套数组都作为引用存储,所以改变一个数组会影响其余的数组。虽然我认为你可能只是打错了它:)
2021-03-24 04:27:59
[...Array(6)].map(x => 0);是一个很好的解决方案,对我很有帮助!稍加修改,它可以用来创建一个计算整数的数组(就像你的typescript安全示例):[...Array(6)].map((x, i) => i);导致[0, 1, 2, 3, 4, 5]
2021-03-29 04:27:59
我知道您想改进您的答案,但尽量不要为了得到点赞而复制其他人的答案。谢谢。
2021-04-05 04:27:59
有时我不在 map 函数中使用“元素/项目/第一个参数”,因为我只需要索引并且我正在寻找一种最佳实践来命名该参数。我不想把它命名为“x”或“未使用”等。所以,使用下划线实际上是一个很棒的主意!谢谢!map((_, i) => i)
2021-04-11 04:27:59

最短的:

let arr = [...Array(10)];
console.log(arr);

并不真地。在开发人员工具中尝试。 [...Array(5)].map((item, index) => ({ index })) 也试试这个:[...Array(5)]; console.log('hello');
2021-03-19 04:27:59
这是真的,但在这种情况下,我会说问题出在其他地方,分号和 linting 现在很重要。
2021-03-24 04:27:59
@AP 这个例子正是许多风格指南要求用分号结束每个语句的原因。const a = 'a'在这种情况下将是 Lint 错误。无论如何,它真的与这个答案无关。
2021-03-26 04:27:59
赞成,但有一个警告,你绝对不应该在 JS 中用 a 开始一行[而不使用 a,;因为它会试图取消引用上面的行。因此,在代码的任何部分中可预测地使用此行的安全方法是:;[...Array(1000)]//.whateverOpsNeeded()
2021-04-02 04:27:59
尝试在多行 js 文件中使用它。如果您的第一行是const a = 'a'和下一行[...Array(5)].//irrelevent. 你认为第一行会解决什么问题?这将const a = 'a'[...Array(5)]导致:Uncaught SyntaxError: Unexpected token ...
2021-04-03 04:27:59