JavaScript中是否可以创建定长数组?

57

在Javascript中,是否可以创建一个长度保持不变的数组?

例如,创建一个长度为2的数组A。随后,任何试图调用A.push()或A.pop(),或设置A [5]的值都将失败。A.length将始终为2。

这就是类型化数组(例如Float32Array)已经实现的方式。它们具有固定的大小。但我想知道在常规数组上获得相同行为的方法。

对于我的特定情况,我想创建一个固定长度的数组,其中每个条目都是一个对象。但我仍然想了解一般问题的答案。


3
不能使用本地数组,但可以创建一个类似数组的对象。 - Denys Séguret
4
你可以自己实现。只需将一个数组对象封装起来,但不公开pushpop或其他修改方法。如果希望保留内部封装的数组不可访问,可以使用闭包。 - salezica
2
为什么一定要使用数组?只需使用一个 object,然后 freeze 它,这样属性就无法被修改。请注意,如果您有一个对象的对象,则冻结仅适用于您冻结的对象,而不适用于任何嵌套对象。 - Andy
@uʍopǝpısdn - 是的 - 好的 - 我想我会做类似的事情。感谢您的建议。 - Daniel Howard
谢谢你的链接,@Andy。那篇文章中有一些非常有趣的想法。 - Daniel Howard
显示剩余2条评论
15个回答

0
你可以使用new Array(5)创建一个固定大小的空值数组,并保持它们的大小不变。
const fixedQueue = new Array(5)
fixedQueue.push = function (i) {
    this.shift();
    return Array.prototype.push.call(this, i)
}
fixedQueue.unshift = function (i) {
    this.pop()
    return Array.prototype.unshift.call(this, i)
}

-1

目前的答案是肯定的,你可以这样做。有几种方法可以实现,但一些网络浏览器有自己的“解释”。

  1. 使用FireFox Mozzila控制台测试的解决方案

var x = new Array(10).fill(0);
// Output: undefined
Object.freeze(x);
// Output: Array [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
x.push(11)
// Output: TypeError: can't define array index property past the end of an array with non-writable length
x.pop()
// Output: TypeError: property 9 is non-configurable and can't be deleted [Learn More]
x[0]=10
// Output: 10 // You don't throw an error but you don't modify the array
x
// Output: Array [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]   

需要注意的是,如果数组是对象,则需要进行深度冻结。深度冻结的代码在这里

  1. 包装数组的类(如果不想抛出异常,这是更好的选择)

  2. 使用ES2015代码应该可以解决以下问题,但实际上并没有:

var x = new Array(10).fill(0);
Object.freeze( x.length );
x.push(3);
console.log(x);

Check this page in the section Note


你的第三个选项是错误的。x.length 是一个数字,Object.freeze(x.length); 除了返回 x.length 之外什么也不会做。 - tim-we
@tim-we 我知道并且我已经写了那个,请阅读答案和评论。我说它应该有一天能够工作,但现在还不能。这是因为freeze应该是一个观察者,如果值的变化发出错误,则会发出错误。这是问题的最简单解决方案,但它不起作用。我提出了一个问题,并被接受。所以,总有一天它会工作的。 - titusfx
1
来源?您提供的MDN页面中写道:“在ES2015中,非对象参数将被视为冻结的普通对象,并简单地返回”。如果将原始值作为参数传递,则会复制它们。这意味着JS工作方式的根本变化。例如,以下代码会发生什么:“var n = x.length; /copy/ Object.freeze(n);” - tim-we
1
@time-wes 应该是一个 getter,而不是对变量的简单直接访问。这就是为什么。 - titusfx
@titusfx 你有相关的来源吗? - tim-we
显示剩余2条评论

-1

当使用 shift 和 push 时,在固定长度的数组中必须有前后长度控制,才能选择从数组开头或结尾删除项目,然后添加或拒绝新项目。这是我最快的解决方案。 如果只使用键来访问数组,可以轻松控制并期望固定大小的行为。对象和数组都可以使用。


-1

是的,此函数用于创建定长数组,使其不仅是单个数组,而且是动态的。您可以创建不同的有限数组,只需创建一个新变量并将其值设置为createLimtedArray(array_limit)的返回值即可。请注意,我的解决方案使用推送方法,因此在核心中创建的数组无需调用任何额外的功能即可进行推送。如果要创建多个不同长度的枚举数组,则非常好用。

// this call back check the length and return true or false if length > limit
const theCallback = (theArray, limit)=>{
  const check = theArray.length <= limit;
  return theArray.length;
}

const createLimtedArray = (arrayLength)=>{
  const limtedArray = [];
  addPushEventListener(limtedArray, theCallback, arrayLength);
  return limtedArray;
}

function addPushEventListener(theArray, theCallback, limit){
  // change the push method
  theArray.push = (e)=> { 
  // call the normal push method and give it the item
  // apply something callback on array before push
  //if (theArray.length <= limit){return false;}
  Array.prototype.push.call(theArray, e);
  const arrLength = theCallback(theArray, e, limit);
  const acceptPush = (arrLength <= limit);
  const s = limit == 1 ? '' : 's';
  if (!acceptPush){
    console.log("sorry array only accept " + limit + " item" + s);
    theArray.pop();
  }
  // apply push or 
  };
}
// first limited array
let x = createLimtedArray(1);
console.log("---------------Array X----------------");
x.push("New X Item 1");
x.push("New X Item 2");
console.log(x);
console.log("");
let y = createLimtedArray(3);
y.push("New Y Item 1");
y.push("New Y Item 2");
y.push("New Y Item 3");
y.push("New Y Item 4");
console.log(y);
console.log("--------------------------------------");
console.log("");


-1

我知道这是一个老问题,但现在有一个叫做fixed-array的节点模块可以做到这一点。


1
那个节点模块并没有真正帮助到你。它给你一个表示固定数组的对象,但你不能通过索引访问值(你必须将值作为数组的副本获取,但该副本不是固定长度的),也不能在特定位置写入值,只能推送到末尾。像之前的答案建议的那样,用一个包装数组的对象会更加灵活。 - Daniel Howard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接