问题
I was playing around with JavaScript's TypedArrays when I noticed something a bit strange. I figured the implementation of the TypedArray.prototype.set method would simply copy values incrementally. Thus, I tried tricking the system to see this behavior:
var ar = new Uint8Array([1,2,3,4,5,6,7,8]); ar.set(ar.subarray(0,6),2);
I perceived that, if it started copying from ar
at 0, but overwrote values at 2, the subarray would be manipulated, and thus start looping once it reached index 2. Therefore, I would naturally expect an output of Uint8Array(8) [1,2,1,2,1,2,1,2]
, but, when inspecting ar
:
> ar Uint8Array(8) [1,2,1,2,3,4,5,6]
So, I figured perhaps it copied backwards?
var ar = new Uint8Array([1,2,3,4,5,6,7,8]); ar.set(ar.subarray(2),0); > ar Uint8Array(8) [3,4,5,6,7,8,7,8]
Nope. Rather unsettled by this, I then decided to use a Proxy to inspect internal behavior:
ar = new Uint8Array([1,2,3,4,5,6,7,8]); pxy = new Proxy(ar.subarray(0,6),{ get: (o,p)=>{console.log("get",o,p,o[p]); return o[p]} }); > ar.set(pxy,2); get Uint32Array(6) [1, 2, 3, 4, 5, 6] length 6 get Uint32Array(6) [1, 2, 3, 4, 5, 6] 0 1 get Uint32Array(6) [1, 2, 1, 4, 5, 6] 1 2 get Uint32Array(6) [1, 2, 1, 2, 5, 6] 2 1 get Uint32Array(6) [1, 2, 1, 2, 1, 6] 3 2 get Uint32Array(6) [1, 2, 1, 2, 1, 2] 4 1 get Uint32Array(6) [1, 2, 1, 2, 1, 2] 5 2 > ar Uint8Array(8) [1,2,1,2,1,2,1,2]
And, alas, as soon as I attempt to observe it, it sneaks away and acts as I first anticipated!
I've run this test in Chrome and Firefox, and both give the same results. I also tested it in MS Edge, and it also seems to give the same results (though at times it would randomly crash the JS runtime - perhaps it was related to the proxy).
Is this a bug or is this specified behavior? When (and/or why) should I expect this behavior? Or should I just altogether evade setting a TypedArray to its own subarray?
回答1:
It is specified behaviour. You can count on this.
When you set
a typed array to its own subarray (i.e. when both typed arrays are views on the same buffer), the source area is explicitly cloned before being written into the destination. This is so that the [1,2,1,2,1,2,1,2]
result is prevented - it is usually unwanted and unexpected.
Using a proxy to inspect the internal behaviour failed you here because using a proxy changed the behaviour. What I said above applies only when you pass another typed array to the set
method - but a Proxy
(even with a typed array target) does not count as a typed array. It falls back to normal copying like from any other array-like object, which does work as you initially described.
来源:https://stackoverflow.com/questions/51308432/javascript-strange-behavior-with-typedarray-prototype-set