简体   繁体   English

如何检查变量是否为 javascript 中的类型化数组?

[英]How to check if a variable is a typed array in javascript?

I'm working on a game and we make extensive use of typed arrays (Float32Arrays) for our math types.我正在开发一款游戏,我们广泛使用类型化的 arrays (Float32Arrays) 作为我们的数学类型。 We save and load the gamestate from JSON. An example of JSON stringify output is for such an array (in Chrome) is:我们从 JSON 保存和加载游戏状态。JSON stringify output 的一个例子是这样的数组(在 Chrome 中)是:

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

This wastes space and causes them to be loaded as objects which is inconvenient.这会浪费空间并导致它们作为不方便的对象加载。 Ideally we could use the stringify 'replacer' function to test if a variable is a typed array, and then convert it to a bog standard array in that case.理想情况下,我们可以使用 stringify 'replacer' function 来测试变量是否为类型化数组,然后在这种情况下将其转换为沼泽标准数组。 Unfortunately I'm not sure how to reliably test whether a variable is a typed array or not.不幸的是,我不确定如何可靠地测试变量是否是类型化数组。

Any help?有什么帮助吗?

ArrayBuffer.isView should help you out. 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

If you're happy with it being a Float32Array or a subclass of Float32Array and they'll be from the same realm (loosely, window) as the code you're checking, see Anton's answer using instanceof .如果你用它一个快乐的Float32Array子类Float32Array ,他们会是同一领域(松散,窗)的代码,你要检查,请参阅使用安东的回答instanceof

If you need to know that it's specifically a Float32Array and not a subclass (and its from the same realm), you could use yourObject.constructor === Float32Array :如果你需要知道它是一个专门Float32Array ,而不是一个子类(来自同一领域的),你可以使用yourObject.constructor === Float32Array

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

Live example:现场示例:

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

But note that will fail if the object originates in a different realm (like another frame), because different environments have different Float32Array constructors (even though they do the same thing).但请注意,如果对象来自不同的领域(如另一个框架),这将失败,因为不同的环境具有不同的Float32Array构造函数(即使它们做相同的事情)。

If you need to support cases where constructor won't work, you can use the Object.prototype.toString.call(yourObject) trick.如果您需要支持constructor不起作用的情况,您可以使用Object.prototype.toString.call(yourObject)技巧。 That returns a useful string for all of the JavaScript built-in types ( [object Array] , [object Date] , etc.) Per specification , Object.prototype.toString when applied to a typed array must return the string in the format "[object TypedArrayNameHere]" .这将返回所有 JavaScript 内置类型( [object Array][object Date]等)的有用字符串。 根据规范Object.prototype.toString在应用于类型化数组时必须返回格式为"[object TypedArrayNameHere]"的字符串"[object TypedArrayNameHere]"

So:所以:

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

Live example:现场示例:

 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()) + "\\""); }

Note that it's possible to create objects that lie about their type, making Object.prototype.toString return the same thing it would return for (say) Float32Array :请注意,可以创建与其类型有关的对象,使Object.prototype.toString返回与(例如) Float32Array返回的相同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));

You also can use yourObject instanceof Float32Array construction.您也可以使用yourObject instanceof Float32Array构造。 It returns true if your object is an instance of Float32Array and false in other case.如果您的对象是Float32Array的实例,则返回true ,其他情况下返回false

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

I'm surprised no one got this one below.我很惊讶没有人在下面找到这个。 This should work in most cases to figure out if you have a typed array:在大多数情况下,这应该可以确定您是否有类型化数组:

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);

Of course this is "duck typing", and a instanceof Float32Array or similar is the best way to know for sure for specific types.当然,这是“鸭子类型”,并且a instanceof Float32Array或类似a instanceof Float32Array是确定特定类型的最佳方式。

If you'd like a more general test that catches any of the ArrayBufferView and DataView types you can use:如果您想要一个更通用的测试来捕获任何 ArrayBufferView 和 DataView 类型,您可以使用:

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

I've found a better way, if you want to test every possible TypedArray, according to MDN , you can get the TypedArray constructor.我找到了一个更好的方法,如果你想测试每一个可能的 TypedArray,根据MDN ,你可以得到TypedArray构造函数。 Using this constructor you can test if something is of its type:使用这个构造函数,你可以测试某些东西是否属于它的类型:

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

You can save this into a function like this:您可以将其保存到这样的函数中:

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

All typed arrays are inherit from ArrayBuffer.所有类型化数组都继承自 ArrayBuffer。 This type contains a byteLength property, so simple check if this property is available.此类型包含一个 byteLength 属性,因此只需检查此属性是否可用。

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

Simple way to actually find all constructors that return a TypedArray:实际查找所有返回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");
  }
}

Output in current Chrome:当前 Chrome 中的 Output:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM