Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/434.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
可以在javascript中创建固定长度的数组吗?_Javascript_Arrays - Fatal编程技术网

可以在javascript中创建固定长度的数组吗?

可以在javascript中创建固定长度的数组吗?,javascript,arrays,Javascript,Arrays,在Javascript中,是否可以创建一个长度保证不变的数组 例如,创建长度为2的数组A。随后,任何调用A.push()或A.pop()或设置A[5]值的尝试都将失败A。长度始终为2 这就是类型化数组(例如Float32Array)的工作方式。它们有固定的尺寸。但是我想要一种方法在正则数组上获得相同的行为 对于我的具体情况,我想创建一个固定长度的数组,其中每个条目都是一个对象。但我仍然想知道一般问题的答案。更新: 接受的答案显示了如何使用当时不可用的Object.seal解决此问题 原始答案:

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

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

这就是类型化数组(例如
Float32Array
)的工作方式。它们有固定的尺寸。但是我想要一种方法在正则数组上获得相同的行为


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

更新:

接受的答案显示了如何使用当时不可用的
Object.seal
解决此问题

原始答案:

因此,原来问题的答案似乎只是“不”。无法创建具有固定长度的本机javascript数组

但是,您可以创建一个类似于固定长度数组的对象。根据评论中的建议,我提出了两种可能的实现方案,各有利弊

我还没有弄清楚我将在我的项目中使用这两个选项中的哪一个。我也不是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');     

    });


});
//版本1
var FixedLengthArrayV1=函数(大小){
//创建真实数组以存储值,通过闭包从外部隐藏
var arr=新阵列(大小);
//对于每个数组项,创建一个getter和setter方法

对于(var i=0;i来说,当前的答案是肯定的,你可以。有几种方法可以做到这一点,但有些web浏览器有自己的“解释”

  • 使用FireFox Mozzila控制台测试的解决方案
  • var x=新数组(10)。填充(0);
    //输出:未定义
    冻结(x);
    //输出:数组[0,0,0,0,0,0,0,0,0,0]
    x、 推(11)
    //输出:TypeError:无法定义超过长度不可写的数组结尾的数组索引属性
    x、 流行音乐()
    //输出:TypeError:属性9不可配置,无法删除[了解更多信息]
    x[0]=10
    //输出:10//您不会抛出错误,但不会修改数组
    x
    
    //输出:数组[0,0,0,0,0,0,0,0,0,0]
    我知道这是一个老问题,但现在有一个节点模块,它就是这样做的,叫做更新:

    (作为ES2015的一部分)将做到这一点:

    // create array with 42 empty slots
    let a = new Array(42);
    
    if(Object.seal) {
      // fill array with some value because
      // empty slots can not be changed after calling Object.seal
      a.fill(undefined);
    
      Object.seal(a);
      // now a is a fixed-size array with mutable entries
    }
    
    原始答案:

    差不多。正如所建议的,您可以冻结对象:

    let 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
    
    但是,您无法更改冻结对象的值。 如果您有一个对象数组,这可能不是问题,因为您仍然可以 更改对象的值

    对于数字数组,当然有

    Object.freeze
    是的一部分。您当然可以对其进行功能测试:


    if(Object.freeze){Object.freeze(obj);}

    实际上,要在大多数现代浏览器(包括IE 11)上用js创建一个完全优化的真正的c类固定数组,您可以使用:TypedArray或ArrayBuffer like so:

    var int16 = new Int16Array(1); // or Float32Array(2)
    int16[0] = 42;
    console.log(int16[0]); // 42
    int16[1] = 44;
    console.log(int16[1]); // undefined
    

    我编写了一个固定数组,它是一个库,为您提供固定长度数组和固定长度密集数组(数组的元素总是向左折叠或向右折叠)

    它支持许多标准阵列操作,如拼接和切片。但将来可以添加更多操作


    push
    的概念没有意义,相反,有
    caret*
    方法可用于插入元素并将已经存在的元素推出到空插槽中。

    您可以这样简单地使用

    let myArray = [];
    function setItem (array, item, length) {
      array.unshift(item) > length ?  array.pop() : null
    }
    // Use Like this
    setItem(myArray, 'item', 5);
    

    基本上,它将填充数组中的项目,直到长度变为5,如果长度将变为5。它将弹出las项目数组。因此,它将始终保持长度为5。

    我们可以使用闭包解决此类问题。我们只是固定了数组大小,并从函数返回函数

    函数setArraySize(大小){
    返回函数(arr、val){
    如果(arr.length==大小){
    返回arr;
    } 
    arr.push(val);
    返回arr;
    }
    }
    设arr=[];
    设sizerr=setArraySize(5);//固定数组大小的固定值。
    sizeArr(arr,1);
    sizeArr(arr,2);
    sizeArr(arr,3);
    sizeArr(arr,4);
    sizeArr(arr,5);
    sizeArr(arr,6);
    
    console.log('arr value',arr);
    您可以实现一个具有容量的类。假设您希望在推入数组时长度保持在5。如果您运行代码段,您将看到6没有推入数组,因为容量已经满足。祝您好运

    类capArray{
    建造商(容量){
    这个。容量=容量;
    this.arr=[];
    }
    }
    capArray.prototype.push=函数(val){
    if(此阵列长度<此容量){
    这个。arr.push(val);
    }
    }
    var newArray=新的capArray(5);
    newArray.push(1)
    newArray.push(2)
    newArray.push(3)
    newArray.push(4)
    newArray.push(5)
    newArray.push(6)
    console.log(newArray)
    console.log(newArray.arr)
  • 使用
    新数组
    构造函数
  • 但是,创建的数组填充了
    未定义的
    。因此使其不可写。您可以用
    null
    0
    值代替

    新数组(100).fill(null).map(()=>…);
    
  • 使用
    Array.from
    方法
  • Array.from({length:n},(u,i)=>i)
    
    使用本机数组是不行的。但是你可以创建一个类似数组的对象。你可以自己实现它。只需包装一个数组对象,但不公开任何
    推送
    弹出
    或其他修改方法。如果你想保留内部