复制ArrayBuffer对象最直接的方法是什么?

时间:2012-04-11 06:13:55

标签: javascript typed-arrays

我正在使用ArrayBuffer个对象,我想复制它们。虽然使用实际指针和memcpy这很容易,但我无法在Javascript中找到任何直接的方法。

现在,这就是我复制ArrayBuffers的方式:

function copy(buffer)
{
    var bytes = new Uint8Array(buffer);
    var output = new ArrayBuffer(buffer.byteLength);
    var outputBytes = new Uint8Array(output);
    for (var i = 0; i < bytes.length; i++)
        outputBytes[i] = bytes[i];
    return output;
}

有更漂亮的方式吗?

7 个答案:

答案 0 :(得分:37)

我更喜欢以下方法

function copy(src)  {
    var dst = new ArrayBuffer(src.byteLength);
    new Uint8Array(dst).set(new Uint8Array(src));
    return dst;
}

答案 1 :(得分:27)

ArrayBuffer应支持slice(http://www.khronos.org/registry/typedarray/specs/latest/),以便您可以尝试,

buffer.slice(0);

适用于Chrome 18但不支持Firefox 10或11.对于Firefox,您需要手动复制它。您可以在Firefox中对slice()进行修补,因为Chrome slice()将胜过手动副本。这看起来像是,

if (!ArrayBuffer.prototype.slice)
    ArrayBuffer.prototype.slice = function (start, end) {
        var that = new Uint8Array(this);
        if (end == undefined) end = that.length;
        var result = new ArrayBuffer(end - start);
        var resultArray = new Uint8Array(result);
        for (var i = 0; i < resultArray.length; i++)
           resultArray[i] = that[i + start];
        return result;
    }

然后你可以打电话,

buffer.slice(0);

在Chrome和Firefox中复制数组。

答案 2 :(得分:22)

看来只需传入源数据视图即可执行复制:

var a = new Uint8Array([2,3,4,5]);
var b = new Uint8Array(a);
a[0] = 6;
console.log(a); // [6, 3, 4, 5]
console.log(b); // [2, 3, 4, 5]

在FF 33和Chrome 36中测试。

答案 3 :(得分:2)

嗯......如果它是你要切片的Uint8Array(逻辑上应该是这样),这可能有用。

 if (!Uint8Array.prototype.slice && 'subarray' in Uint8Array.prototype)
     Uint8Array.prototype.slice = Uint8Array.prototype.subarray;

答案 4 :(得分:2)

更快,更复杂的chuckj答案版本。应该在大型阵列上使用约8倍的复制操作。基本上我们尽可能多地复制8字节块,然后复制剩余的0-7字节。这在当前版本的IE中特别有用,因为它没有为ArrayBuffer实现切片方法。

if (!ArrayBuffer.prototype.slice)
    ArrayBuffer.prototype.slice = function (start, end) {
    if (end == undefined) end = that.length;
    var length = end - start;
    var lengthDouble = Math.floor(length / Float64Array.BYTES_PER_ELEMENT); 
    // ArrayBuffer that will be returned
    var result = new ArrayBuffer(length);

    var that = new Float64Array(this, start, lengthDouble)
    var resultArray = new Float64Array(result, 0, lengthDouble);

    for (var i = 0; i < resultArray.length; i++)
       resultArray[i] = that[i];

    // copying over the remaining bytes
    that = new Uint8Array(this, start + lengthDouble * Float64Array.BYTES_PER_ELEMENT)
    resultArray = new Uint8Array(result, lengthDouble * Float64Array.BYTES_PER_ELEMENT);

    for (var i = 0; i < resultArray.length; i++)
       resultArray[i] = that[i];

    return result;
}

答案 5 :(得分:0)

在某些情况下(例如webaudio音频缓冲区),您只能引用2个数组。
因此,如果您将array1作为float32Array,将array2作为float32Array,
您必须逐个元素地进行复制。

为此,您可以使用其他方法。

            var ib=z.inputBuffer.getChannelData(0);
            var ob=z.outputBuffer.getChannelData(0);

这个

            ib.forEach((chd,i)=>ob[i]=chd);

或者这个更好,也许更快

            ob.set(ib);

那是因为Array.set使用多个数据(甚至来自另一个数组)填充了一个现有的数组

答案 6 :(得分:0)

上面的一些操作只做“浅”拷贝。使用worker和可转移数组时,需要做深拷贝。

function copyTypedArray(original, deep){
    var copy;
    var kon = original.constructor;
    if(deep){
        var len = original.length;
        copy = new kon(len);
        for (var k=len; --k;) {
            copy[k] = original[k];
        }
    } else {
        var sBuf = original.buffer;
        copy = new kon(sBuf);
        copy.set(original);
    }
    return copy;
}

提示(对于困惑的人):类型化数组包含一个 ArrayBuffer,可以通过“buffer”属性获得。

var arr = new Float32Array(8);
arr.buffer <-- this is an ArrayBuffer