Reference to slice of an array

2019-04-12 02:01发布

问题:

How to get the reference to a slice of an array?

var A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
A.mySlice = function(l, h){return this.slice(l,h)};

var B = A.mySlice(1,5); // ["b", "c", "d", "e"]

It works for direct slices derived from A. But, how to get it for all slices derived? (in this case for B)

B.mySlice = function(l, h){return this.slice(l,h)};

A[3] = 33;
A.mySlice(1,5) // ["b", "c", 33, "e"] => ok
B.mySlice(0,3) // ["b", "c", "d"] => I would want ["b", "c", 33]

回答1:

I don't think you can do this with native JS arrays (well, not in a straightforward manner anyway).

I think the cleanest approach would be going back and using custom objects to represent the slices. Perhaps something along these lines:

function ArraySlice(arr, lo, hi){
    this.arr = arr;
    this.lo = lo;
    this.hi = hi;
    this.length = hi - lo;
};
ArraySlice.prototype._contains = function(ix){
    return this.lo + ix < this.hi;
};
ArraySlice.prototype.get = function(ix){
    if (this._contains(ix)){
        return this.arr[this.lo + ix];
    }else{
        return; //undefined
    }
};
ArraySlice.prototype.set = function(ix, value){
    if (this._contains(ix)){
        return (this.arr[this.lo + ix] = value);
    }else{
        return; //undefined
    }
};

var a = [0,1,2,3,4,5];
var b = new ArraySlice(a, 1, 3);

a[2] = 17;
console.log( b.get(1) );

Of course, this loses the convenient [] syntax and the objects aren't arrays anymore but subclassing Array is annoying and error prone and I don't believe there is a cross-browser way to do operator overloading.



回答2:

slice() copies elements to a new array.

So, in your example, A and B are two completely different arrays. So, changing elements in one does not affect another.



回答3:

Here is the only possible solution I see:

  • extend Array class and store all array data in a singleton class instance
  • create a unique identifier (UID) when you first create a new array
  • use that identifier when you are trying to get data from singleton
  • use that same identifier when you're making a slice

This may however break lots of your code.



回答4:

I'm pretty sure this isn't possible in Javascript. This line var B = A.mySlice(1,5); sets B to an array object containting a slice of A's numbers. It has no reference to A. It's just an array object.



回答5:

It's not quite as clean, since you'd be dealing with function objects, but you could wrap the calls to chain back up the original array using closures:

var A = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
A.mySlice = function (l, h) { return function() { return this.slice(l, h); }; };

var B = A.mySlice(1, 5); // B() will resolve to ["b", "c", "d", "e"]
B.mySlice = function (l, h) { return function() { return this().slice(1, h) }; };

A[3] = 33;
A.mySlice(1, 5)() // ["b", "c", 33, "e"]
B.mySlice(0, 3)() // ["b", "c", 33]