如何使用自定义方法取消/移动单个值和多个值?

时间:2015-11-11 04:21:31

标签: javascript arrays prototype

我有原型来重新创建数组方法的工作方式,pop / push / shift /等,我想扩展功能以执行以下操作:

  1. 按下/弹出/移位/取消移动多个值 array.push(0); array.push(1); array.push(2); expect(array.pop()).to.be(2); expect(array.pop()).to.be(1); expect(array.pop()).to.be(0);

  2. Push / Pop / unshift / etc单个值 array.push(0); array.push(1); expect([0,1]); array.pop(1); expect([0]);

  3. 我的假设是我需要一个全局数组变量来存储元素。那是对的吗?

    这是我的代码:

    var mainArray = [];  // array no longer destroyed after fn() runs
    function YourArray(value) {
      this.arr = mainArray;  // looks to global for elements | function?
      this.index = 0;
      var l = mainArray.length;
    
      if(this.arr === 'undefined')
        mainArray += value;        //  add value if array is empty
      else
        for(var i = 0; i < l ; i++)             // check array length
            mainArray += mainArray[i] = value;  // create array index & val
    
      return this.arr;
    }
    
    YourArray.prototype.push = function( value ) {
      this.arr[ this.index++ ] = value;
      return this;
    };
    
    YourArray.prototype.pop = function( value ) {
      this.arr[ this.index-- ] = value;
      return this;
    };
    
    var arr = new YourArray();
    arr.push(2);
    console.log(mainArray); 
    

2 个答案:

答案 0 :(得分:1)

  

我的假设是我需要一个全局数组变量来存储   要素。那是对的吗?

没有。那不对。

您希望每个数组对象都有自己独立的数据集。否则,你怎么能在你的程序中有多个数组?

function YourArray(value) {
  this.arr = [];  // This is the data belonging to this instance. 
  this.index = 0;
  if(typeof(value) != 'undefined')) {
    this.arr = [value];
    this.index = 1;
  }
}

////////////////////////////////////
// Add prototype methods here
///////////////////////////////////

var array1 = new YourArray();
var array2 = new YourArray();
array1.push(2);
array1.push(4);
array2.push(3);
array2.push(9);
// Demonstrate that the values of one array
// are unaffected by the values of a different array
expect(array1.pop()).to.be(4);
expect(array2.pop()).to.be(9);

答案 1 :(得分:1)

对于这个派对来说有点晚了,承认但它却唠叨我。在一个全局数组中,没有简单的方法(对于一些较大的“简单”值)方法吗?

标准数组函数的工作方式如下面的粗略(!)草图:

function AnotherArray() {
  this.arr = [];
  // points to end of array
  this.index = 0;
  if(arguments.length > 0) {
    for(var i=0;i<arguments.length;i++){
      // adapt if you want deep copies of objects
      // and/or take a given array's elements as 
      // individual elements
      this.arr[i] = arguments[i];
      this.index++;
    }
  }
}
AnotherArray.prototype.push = function() {
  // checks and balances ommitted
  for(var i=0;i<arguments.length;i++){
    this.arr[ this.index++ ] = arguments[i];
  }
  return this;
};
AnotherArray.prototype.pop = function() {
  this.index--;
  return this;
};
AnotherArray.prototype.unshift = function() {
  // checks and balances ommitted
  var tmp = [];
  var alen = arguments.length;

  for(var i=0;i<this.index;i++){
    tmp[i] = this.arr[i];
  }
  for(var i=0;i<alen;i++){
    this.arr[i] = arguments[i];
    this.index++;
  }
  for(var i=0;i<tmp.length + alen;i++){
    this.arr[i + alen] = tmp[i];
  }
  return this;
};
AnotherArray.prototype.shift = function() {
  var tmp = [];
  for(var i=1;i<this.index;i++){
    tmp[i - 1] = this.arr[i];
  }
  this.arr = tmp;
  this.index--;
  return this;
};
AnotherArray.prototype.isAnotherArray = function() {
  return true;
}
AnotherArray.prototype.clear = function() {
  this.arr = [];
  this.index = 0;
}
AnotherArray.prototype.fill = function(value,length) {
  var len = 0;
  if(arguments.length > 1)
    len = length;
  for(var i=0;i<this.index + len;i++){
    this.arr[i] = value;
  }
  if(len != 0)
    this.index += len;
  return this;
}
// to simplify this example
AnotherArray.prototype.toString = function() {
  var delimiter = arguments.length > 0 ? arguments[0] : ",";
  var output = "";
  for(var i=0;i<this.index;i++){
    output += this.arr[i];
    if(i < this.index - 1)
     output += delimiter;
  }
  return output;
}
var yaa = new AnotherArray(1,2,3);
yaa.toString(); // 1,2,3
yaa.push(4,5,6).toString(); // 1,2,3,4,5,6
yaa.pop().toString(); // 1,2,3,4,5
yaa.unshift(-1,0).toString(); // -1,0,1,2,3,4,5
yaa.shift().toString(); // 0,1,2,3,4,5
var yaa2 = new AnotherArray();
yaa2.fill(1,10).toString(); // 1,1,1,1,1,1,1,1,1,1

非常简单和前进,只花了大约20分钟写(是的,我是一个慢打字员)。我会将this.arr中的原生JavaScript数组与双链表进行交换,如果内容可以是任意JavaScript对象,这会使shiftunshift内存更少,但很明显更复杂,也更慢。

但是主要问题是全局数组。如果我们想要使用同一阵列的几个单独的块,我们需要有关于各个部分的开始和结束的信息。例如:

var globalArray = [];
var globalIndex = [[0,0]];
function YetAnotherArry(){
  // starts at the end of the last one
  this.start = globalIndex[globalIndex.length-1][1];
  this.index = this.start;
  // position of the information in the global index
  this.pos = globalIndex.length;
  globalIndex[globalIndex.length] = [this.start,this.index];
}

到目前为止,这么好。我们可以毫无问题地处理第一个数组。我们甚至可以制作第二个,但是当第一个想要扩展它的阵列时,我们遇到了麻烦:没有空间。第二个数组的开头是第一个数组的结尾,没有任何间隙。

一个简单的解决方案是使用数组数组

globalArray = [
                ["first subarray"],
                ["second subarray"],
                ...
              ];

我们可以重复使用我们已经在那种情况下编写的内容

var globalArray = [];
function YetAnotherArray(){
  // open a new array
  globalArray[globalArray.length] = [];
  // point to that array
  this.arr = globalArray[globalArray.length - 1];
  this.index = 0;
}
YetAnotherArray.prototype.push = function() {
  for(var i=0;i<arguments.length;i++){
    this.arr[ this.index++ ] = arguments[i];
  }
  return this;
};
// and so on

但是对于每个新的YetAnotherArray,您将另一个数组添加到全局数组池中,并且您放弃的每个数组仍然存在并使用内存。您需要管理数组并删除不再需要的每个YetAnotherArray,并且必须完全删除它以允许GC执行其操作。

这将只留下全局数组中的空白。您可以保持原样,但如果您想使用和删除数千个,那么最后会留下一个非常稀疏的全局数组。或者你可以清理。问题:

var globalArray = [];
function YetAnotherArray(){
  // add a new subarray to the end of the global array
  globalArray[globalArray.length] = [];
  this.arr = globalArray[globalArray.length - 1];
  this.index = 0;
  this.pos = globalArray.length - 1;
}
YetAnotherArray.prototype.push = function() {
  for(var i=0;i<arguments.length;i++){
    this.arr[ this.index++ ] = arguments[i];
  }
  return this;
};
YetAnotherArray.prototype.toString = function() {
  var delimiter = arguments.length > 0 ? arguments[0] : ",";
  var output = "";
  for(var i=0;i<this.index;i++){
    output += this.arr[i];
    if(i < this.index - 1)
     output += delimiter;
  }
  return output;
}
// we need a method to delete an instance
YetAnotherArray.prototype.clear = function() {
  globalArray[this.pos] = null;
  this.arr = null;
  this.index = null;
};
YetAnotherArray.delete = function(arr){
    arr.clear();
    delete(arr);
};
// probably won't work, just a hint in case of asynch. use
var mutex = false;
YetAnotherArray.gc = function() {
  var glen, indexof, next_index, sub_len;

  indexof = function(arr,start){
    for(var i = start;i<arr.length;i++){
      if (arr[i] == null || arr[i] == undefined)
        return i;
    }
    return -1;
  };

  mutex = true;
  glen = globalArray.length;
  sublen = 0;
  for(var i = 0;i<glen;i++){
    if(globalArray[i] == null || globalArray[i] == undefined){
      next_index = indexof(globalArray,i);
      if(next_index == -1){
        break;
      }
      else {
        globalArray[i] = globalArray[next_index + 1];
        globalArray[next_index + 1] = null;
        sublen++;
      }
    }
  }
  globalArray.length -= sublen - 1;
  mutex = false;
};

var yaa_1 = new YetAnotherArray();
var yaa_2 = new YetAnotherArray();
var yaa_3 = new YetAnotherArray();
var yaa_4 = new YetAnotherArray();

yaa_1.push(1,2,3,4,5,6,7,8,9).toString(); // 1,2,3,4,5,6,7,8,9
yaa_2.push(11,12,13,14,15,16).toString(); // 11,12,13,14,15,16
yaa_3.push(21,22,23,24,25,26,27,28,29).toString();// 21,22,23,24,25,26,27,28,29
yaa_4.push(311,312,313,314,315,316).toString(); // 311,312,313,314,315,316


globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
11,12,13,14,15,16
21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/
YetAnotherArray.delete(yaa_2);
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9

21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/
YetAnotherArray.gc();
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/

但是,正如您可能已经猜到的那样:它不起作用。

YetAnotherArray.delete(yaa_3); // yaa_3 was 21,22,23,24,25,26,27,28,29
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
21,22,23,24,25,26,27,28,29

*/

我们需要另一个阵列来保持所有位置。实际实现作为读者练习但是如果你想实现类似JavaScript的数组,那就是你真正的任意内容,真的,真的 应该使用双重链接名单。或者是b树。可能是b + -tree?

哦,顺便说一句:是的,你可以用一个{key:value}对象很容易地做到这一点,但这会把所有的乐趣都挤掉,不是吗? ; - )