【问题标题】:How to check if a variable is a typed array in javascript?如何检查变量是否是javascript中的类型化数组?
【发布时间】:2013-02-21 12:16:31
【问题描述】:

我正在开发一款游戏,我们在数学类型中广泛使用类型化数组 (Float32Arrays)。我们从 JSON 保存和加载游戏状态。 JSON stringify 输出的一个示例是这样一个数组(在 Chrome 中)是:

"{"0":0,"1":0,"2":0,"length":3,"byteLength":12,"byteOffset":0,"buffer":{"byteLength":12}}"

这会浪费空间并导致它们作为不方便的对象加载。理想情况下,我们可以使用 stringify 'replacer' 函数来测试变量是否是类型化数组,然后在这种情况下将其转换为 bog 标准数组。不幸的是,我不确定如何可靠地测试变量是否是类型化数组。

有什么帮助吗?

【问题讨论】:

    标签: javascript json stringify typedarray


    【解决方案1】:

    ArrayBuffer.isView 应该可以帮到你。

    var data = [0,1,2]
    var dataBuffer = new ArrayBuffer( data )
    var dataBufferView = new Float32Array( data )
    
    ArrayBuffer.isView(data) //false
    ArrayBuffer.isView(dataBuffer) //false
    ArrayBuffer.isView(dataBufferView) //true
    dataBuffer instanceof ArrayBuffer //true
    

    【讨论】:

    • 不,DataView 实例也返回 true。不过,如果您知道它无论如何都不会是 DataView,那么这很有用。
    • 所以,你可以使用ArrayBuffer.isView(dataBufferView) && !(dataBufferView instanceof DataView)。整洁!
    【解决方案2】:

    如果您对它是Float32Array 感到满意Float32Array 的子类,它们将来自同一个realm(松散地说, window) 作为您正在检查的代码,see Anton's answer using instanceof

    如果您需要知道它具体Float32Array 而不是子类(并且它来自同一领域),您可以使用yourObject.constructor === Float32Array

    if (yourObject.constructor === Float32Array) {
         // It's a Float32Array
    }
    

    活生生的例子:

    if (typeof Float32Array === "undefined") {
      console.log("This browser doesn't support Float32Array");
    } else {
      var array = new Float32Array(10);
      console.log(array.constructor === Float32Array); // true
    }

    但请注意,如果对象源自不同的领域(如另一个框架),则会失败,因为不同的环境具有不同的 Float32Array 构造函数(即使它们执行相同的操作)。

    如果您需要支持constructor 不起作用的情况,您可以使用Object.prototype.toString.call(yourObject) 技巧。这将为所有 JavaScript 内置类型([object Array][object Date] 等)返回一个有用的字符串。当应用于类型化数组时,Per specificationObject.prototype.toString 必须返回格式为 "[object TypedArrayNameHere]" 的字符串。

    所以:

    if (Object.prototype.toString.call(yourObject) === "[object Float32Array]") {
         // It's a Float32Array
    }
    

    活生生的例子:

    if (typeof Float32Array === "undefined") {
      console.log("This browser doesn't support Float32Array");
    } else {
      console.log("Object.prototype.toString.call(new Float32Array()) returns: \"" +
        Object.prototype.toString.call(new Float32Array()) + "\"");
    }

    请注意,可以创建与其类型有关的对象,使 Object.prototype.toString 返回与(例如)Float32Array 返回相同的内容:

    const real = new Float32Array();
    const fake = {
      get [Symbol.toStringTag]() {
        return "Float32Array";
      }
    };
    const realString = Object.prototype.toString.call(real);
    const fakeString = Object.prototype.toString.call(fake);
    console.log(realString);
    console.log(fakeString);
    console.log(realString === realString);
    
    // You can also create a class that returns objects that lie:
    class Foo {
      get [Symbol.toStringTag]() {
        return "Float32Array";
      }
    }
    const fake2 = new Foo();
    console.log(Object.prototype.toString.call(fake2));

    【讨论】:

    • 这是否意味着检查对象是否是任何类型的数组的唯一方法是检查所有数组类型?
    • @Startec:那将是最稳健的方式。请注意,您不必单独执行它们,您可以在 Object.prototype.toString 的结果上使用正则表达式。但请注意,也可以创建使Object.prototype.toString 撒谎的对象——我在答案的末尾添加了一个示例。
    • 新的 Float32Array(); // ES2017 中的新功能
    • @JimTang - 它们比这更老,它们在 ES2015 的 JavaScript 中被标准化(在此之前有一个特定于浏览器的规范)。
    【解决方案3】:

    您也可以使用yourObject instanceof Float32Array 构造。 如果您的对象是Float32Array 的实例,则返回true,否则返回false

    if (yourObject instanceof Float32Array) {
        // your code here
    }
    

    【讨论】:

      【解决方案4】:

      我找到了一个更好的方法,如果你想测试每一个可能的 TypedArray,根据MDN,你可以得到 TypedArray 构造函数。使用此构造函数,您可以测试某物是否属于其类型:

      var x = new Uint32Array();
      var TypedArray = Object.getPrototypeOf(Uint8Array);
      console.log(x instanceof TypedArray);

      您可以将其保存到这样的函数中:

      const isTypedArray = (function() {
        const TypedArray = Object.getPrototypeOf(Uint8Array);
        return (obj) => obj instanceof TypedArray;
      })();
      

      【讨论】:

        【解决方案5】:

        我很惊讶没有人在下面得到这个。在大多数情况下,这应该可以确定您是否有类型化数组:

        function isTypedArray(a) { return !!(a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT); }
        
        var a = [];
        console.log(isTypedArray(a)); // (false);
        var a = new Float32Array(3);
        console.log(isTypedArray(a)); // (true);
        var dataView = new DataView(a.buffer);
        console.log(isTypedArray(dataView)); // (false);
        console.log(isTypedArray(Float32Array)); // (false);
        

        当然,这是“鸭子打字”,a instanceof Float32Array 或类似名称是确定特定类型的最佳方法。

        【讨论】:

          【解决方案6】:

          如果您想要一个更通用的测试来捕获您可以使用的任何 ArrayBufferView 和 DataView 类型:

          if (Object.prototype.toString.call(yourObject.buffer) === "[object ArrayBuffer]") {
               // It's either an ArrayBufferView or a DataView
          }
          

          【讨论】:

            【解决方案7】:

            所有类型化的数组都继承自 ArrayBuffer。此类型包含一个 byteLength 属性,因此简单检查此属性是否可用。

            function isTypedArray(obj)
            {
                return !!obj && obj.byteLength !== undefined;
            }
            

            【讨论】:

            • 类型化数组不继承自 ArrayBuffer。 TypedArray 的 'buffer' 属性继承自 ArrayBuffer。
            • isTypedArray({byteLength: 10}) ==> true
            【解决方案8】:

            实际查找所有返回 TypedArray 的构造函数的简单方法:

            isTypedArray = _ => _?.prototype?.__proto__?.constructor?.name == "TypedArray";
            for (const key of Object.getOwnPropertyNames(window)) {
              const obj = window[key];
              if (isTypedArray(obj)) {
                console.log(key, "is a TypedArray");
              }
            }
            

            当前 Chrome 中的输出:

            Uint8Array is a TypedArray
            Int8Array is a TypedArray
            Uint16Array is a TypedArray
            Int16Array is a TypedArray
            Uint32Array is a TypedArray
            Int32Array is a TypedArray
            Float32Array is a TypedArray
            Float64Array is a TypedArray
            Uint8ClampedArray is a TypedArray
            BigUint64Array is a TypedArray
            BigInt64Array is a TypedArray
            

            【讨论】:

              猜你喜欢
              • 2022-11-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多