Dan*_*ard 20 javascript arrays
在Javascript中,是否有可能创建一个长度保证保持不变的数组?
例如,创建长度为2的数组A.随后,任何调用A.push()或A.pop()或设置A [5]的值的尝试都将失败.A.length总是2.
这是类型化数组(例如Float32Array)已经工作的方式.它们有固定的尺寸.但我想要一种在常规数组上获得相同行为的方法.
对于我的具体情况,我想创建一个固定长度的数组,其中每个条目都是一个对象.但我仍然想知道一般问题的答案.
tim*_*-we 13
更新:
Object.seal(它是ES2015的一部分)就是这样做的:
var a = new Array(42);
if(Object.seal) {
Object.seal(a);
// now a is a fixed-size array with mutable entries
}
Run Code Online (Sandbox Code Playgroud)
原答案:
几乎.正如titusfx所建议的,您可以冻结对象:
var a = new Array(2);
// set values, e.g.
a[0] = { b: 0; }
a[1] = 0;
Object.freeze(a);
a.push(); // error
a.pop(); // error
a[1] = 42; // will be ignored
a[0].b = 42; // still works
Run Code Online (Sandbox Code Playgroud)
但是,您无法更改冻结对象的值.如果您有一个对象数组,这可能不是问题,因为您仍然可以更改对象的值.
对于数字数组,当然有类型数组.
Object.freeze是ES2015的一部分,但大多数浏览器似乎都支持它,包括IE9.你当然可以对它进行功能测试:
if(Object.freeze) { Object.freeze(obj); }
你可以像这样简单地使用。
let myArray = [];
function setItem (array, item, length) {
array.unshift(item) > length ? array.pop() : null
}
// Use Like this
setItem(myArray, 'item', 5);
Run Code Online (Sandbox Code Playgroud)
基本上,如果长度将大于 5,它将填充数组中的项目,直到长度达到 5。它会弹出 las 项目数组。所以它将保持长度始终为 5。
小智 6
实际上,要在大多数现代浏览器(包括 IE 11)上的 js 中创建完全优化的真正 c 类固定数组,您可以使用:TypedArray 或 ArrayBuffer,如下所示:
var int16 = new Int16Array(1); // or Float32Array(2)
int16[0] = 42;
console.log(int16[0]); // 42
int16[1] = 44;
console.log(int16[1]); // undefined
Run Code Online (Sandbox Code Playgroud)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
更新:
接受的答案显示了如何这个问题可以现在使用可以解决Object.seal这是不可用的时间.
原答案:
因此,似乎原始问题的答案只是"不".无法创建具有固定长度的本机javascript数组.
但是,您可以创建一个行为类似于固定长度数组的对象.根据评论中的建议,我提出了两种可能的实现方式,包括优点和缺点.
我还没弄清楚我将在我的项目中使用哪2个.我对这两者都不是100%满意.如果您对改进它们有任何想法,请告诉我(我希望尽可能快速有效地制作这些物品,因为我需要很多它们).
以下两种实现的代码,以及说明使用情况的QUnit测试.
// Version 1
var FixedLengthArrayV1 = function(size) {
// create real array to store values, hidden from outside by closure
var arr = new Array(size);
// for each array entry, create a getter and setter method
for (var i=0; i<size; i++) {FixedLengthArrayV1.injectArrayGetterSetter(this,arr,i);}
// define the length property - can't be changed
Object.defineProperty(this,'length',{enumerable:false,configurable:false,value:size,writable:false});
// Could seal it at this point to stop any other properties being added... but I think there's no need - 'length' won't change, so loops won't change
// Object.seal(this);
};
// Helper function for defining getter and setter for the array elements
FixedLengthArrayV1.injectArrayGetterSetter = function(obj,arr,i) {
Object.defineProperty(obj,i,{enumerable:true,configurable:false,get:function(){return arr[i];},set:function(val){arr[i]=val;}});
};
// Pros: Can use square bracket syntax for accessing array members, just like a regular array, Can loop just like a regular array
// Cons: Each entry in each FixedLengthArrayV1 has it's own unique getter and setter function - so I'm worried this isn't very scalable - 100 arrays of length 100 means 20,000 accessor functions in memory
// Version 2
var FixedLengthArrayV2 = function(size) {
// create real array to store values, hidden from outside by closure
var arr = new Array(size);
this.get = function(i) {return arr[i];}
this.set = function(i,val) {
i = parseInt(i,10);
if (i>=0 && i<size) {arr[i]=val;}
return this;
}
// Convenient function for looping over the values
this.each = function(callback) {
for (var i=0; i<this.length; i++) {callback(arr[i],i);}
};
// define the length property - can't be changed
Object.defineProperty(this,'length',{enumerable:false,configurable:false,value:size,writable:false});
};
// Pros: each array has a single get and set function to handle getting and setting at any array index - so much fewer functions in memory than V1
// Cons: Can't use square bracket syntax. Need to type out get(i) and set(i,val) every time you access any array member - much clumsier syntax, Can't do a normal array loop (need to rely on each() helper function)
// QUnit tests illustrating usage
jQuery(function($){
test("FixedLengthArray Version 1",function(){
// create a FixedLengthArrayV2 and set some values
var a = new FixedLengthArrayV1(2);
a[0] = 'first';
a[1] = 'second';
// Helper function to loop through values and put them into a single string
var arrayContents = function(arr) {
var out = '';
// Can loop through values just like a regular array
for (var i=0; i<arr.length; i++) {out += (i==0?'':',')+arr[i];}
return out;
};
equal(a.length,2);
equal(a[0],'first');
equal(a[1],'second');
equal(a[2],null);
equal(arrayContents(a),'first,second');
// Can set a property called '2' but it doesn't affect length, and won't be looped over
a[2] = 'third';
equal(a.length,2);
equal(a[2],'third');
equal(arrayContents(a),'first,second');
// Can't delete an array entry
delete a[1];
equal(a.length,2);
equal(arrayContents(a),'first,second');
// Can't change the length value
a.length = 1;
equal(a.length,2);
equal(arrayContents(a),'first,second');
// No native array methods like push are exposed which could let the array change size
var errorMessage;
try {a.push('third');} catch (e) {errorMessage = e.message;}
equal(errorMessage,"Object [object Object] has no method 'push'");
equal(a.length,2);
equal(arrayContents(a),'first,second');
});
test("FixedLengthArray Version 2",function(){
// create a FixedLengthArrayV1 and set some values
var a = new FixedLengthArrayV2(2);
a.set(0,'first');
a.set(1,'second');
// Helper function to loop through values and put them into a single string
var arrayContents = function(arr) {
var out = '';
// Can't use a normal array loop, need to use 'each' function instead
arr.each(function(val,i){out += (i==0?'':',')+val;});
return out;
};
equal(a.length,2);
equal(a.get(0),'first');
equal(a.get(1),'second');
equal(a.get(2),null);
equal(arrayContents(a),'first,second');
// Can't set array value at index 2
a.set(2,'third');
equal(a.length,2);
equal(a.get(2),null);
equal(arrayContents(a),'first,second');
// Can't change the length value
a.length = 1;
equal(a.length,2);
equal(arrayContents(a),'first,second');
// No native array methods like push are exposed which could let the array change size
var errorMessage;
try {a.push('third');} catch (e) {errorMessage = e.message;}
equal(errorMessage,"Object [object Object] has no method 'push'");
equal(a.length,2);
equal(arrayContents(a),'first,second');
});
});
Run Code Online (Sandbox Code Playgroud)
new Array构造函数但是,创建的数组充满了undefined. 从而使其不可迭代。null您可以用或0值来填充它。
new Array(100).fill(null).map(() => ...);
Run Code Online (Sandbox Code Playgroud)
Array.from方法Array.from({ length: n }, (_,i) => i)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
32520 次 |
| 最近记录: |