If you haven’t noticed, the title should confuse you. What could possibly be wrong with such a basic problem as determining data types?

Boy, you can’t be naive. We’re dealing with a language, but JavaScript, anything you think you’ve taken for granted can turn into a pit in an instant.

But for the same reason, we can ask and discuss some interesting questions that are unique to JavaScript while learning and using the language. For example, we’re going to talk today about how an array is an array in JavaScript.

JavaScript, there are five ways to determine what type of a value, the typeof operator, the constructor method, the instanceof operator, the Object. The prototype. The toString method and Array. The isArray method.

1. Use typeof algorithm to judge

Typeof is a javascript natively provided operator to determine the data type, which returns a string representing the data typeof the parameter, for example:

const s = 'hello';
console.log(typeof(s))//String
Copy the code

Here is a table I found in the DOCUMENTATION for MDN that contains the output results for different parameters of typeOF operations:

Typeof returns object. There is no way to distinguish objects from arrays, objects, null, etc.

const a = null;
const b = {};
const c= [];
console.log(typeof(a)); //Object
console.log(typeof(b)); //Object
console.log(typeof(c)); //Object
Copy the code

Using typeOF as an array, object, or NULL, you can see that typeof returns object. Arrays can’t be identified using this method. Therefore, using Typeof to determine whether a positional type is an array in a JavaScript project is very unreliable.

2. Use instanceof

Since typeof cannot be used to determine whether an array is an array, is it possible to use the instance operator? To answer this question, we first need to understand what the Instanceof algorithm does.

The instanceof operator can be used to determine whether an object referred to by the constructor’s prototype property exists on the prototype chain of another object to be tested. When used, the syntax is as follows:

Object instanceof constructor (const constructor); object instanceof constructor If the Array constructor is found on the prototype chain, then the Object should be an Array. If only the Object constructor is found on the prototype chain, then the Object is not an Array.

const a = []; const b = {}; console.log(a instanceof Array); //true console.log(a instanceof Object); // True, the Object constructor console.log(b instanceof Array) can also be found on the Array prototype chain; //falseCopy the code

As you can see from the above lines, using the instanceof operator, you can distinguish an array from an object. You can determine that an array is an array.

(3)

The instantiated array has a constructor property that points to the method that generated the array.

const a = []; console.log(a.constructor); //function Array(){ [native code] }Copy the code

The above code shows that arrays are instantiated by a function called Array. If the judged object is of another data type, the result is as follows:

const o = {}; console.log(o.constructor); //function Object(){ [native code] } const r = /^[0-9]$/; console.log(r.constructor); //function RegExp() { [native code] } const n = null; console.log(n.constructor); / / an errorCopy the code

If you look at this, you might think that this is also a reasonable way to judge arrays. We can do this in the following way:

const a = []; console.log(a.constructor == Array); //trueCopy the code

Sorry to inform you, however, that the constructor property can be overwritten. If you accidentally change the constructor property, you will not be able to use this method to determine the identity of the array. Andy Lau: “who knows?” .

// Define an array const a = []; // change the constructor attribute from a.contrtuctor = Object; console.log(a.constructor == Array); //false (cry face) console.log(a.constructor == Object); //true (cry face) console.log(a instanceof Array); //true (instanceof eye)Copy the code

As you can see, it is no longer possible to use this method to determine that an array is an array after the constructor property has been modified, nor is it possible to use this method unless you can be sure that the constructor property will not be overwritten.

4. Use the toString method of Object

Another effective method is to use the Object. The prototype. The toString method to judge, each one inherited from the Object of the Object have the toString method.

If the toString method of an object has not been overridden, the toString method will return “object type”, where type represents the type of the object. Based on the value of type, we can determine whether the array object is an array.

You might wonder, why not just call the toString method of the array, or the string itself? Let’s give it a try and find out.

const a = ['Hello','Howard']; const b = {0:'Hello',1:'Howard'}; const c = 'Hello Howard'; a.toString(); //"Hello,Howard" b.toString(); //"[object Object]" c.toString(); //"Hello,Howard"Copy the code

As you can see from the above code, all data types except the object’s toString method return the character creation of the content. Only the object’s toString method returns the type of the object. Therefore, to determine the data type of data other than the object, we need to “borrow” the object’s toString method, so we need to use call or apply methods to change the execution context of the toString method.

const a = ['Hello','Howard']; const b = {0:'Hello',1:'Howard'}; const c = 'Hello Howard'; Object.prototype.toString.call(a); //"[object Array]" Object.prototype.toString.call(b); //"[object Object]" Object.prototype.toString.call(c); //"[object String]" const a = ['Hello','Howard']; const b = {0:'Hello',1:'Howard'}; const c = 'Hello Howard'; Object.prototype.toString.apply(a); //"[object Array]" Object.prototype.toString.apply(b); //"[object Object]" Object.prototype.toString.apply(c); //"[object String]"Copy the code

To summarize, we can check whether an array is an array by writing a method:

const isArray = (something)=>{ return Object.prototype.toString.call(something) === '[object Array]'; } cosnt a = []; const b = {}; isArray(a); //true isArray(b); //falseCopy the code

However, if you have to change the toString method on the Object prototype chain before creating this method, I really can’t help you…

/ / override the toString method Object. The prototype. The toString () = = > {alert (' have you eaten? '); } // Call String const a = [];Copy the code

Object.prototype.toString.call(a); // The alert is only visible in the browser, so I won’t explain it.

5. Use the isArray method of the Array object

Why put this method at the end? Because it’s the most reliable array method I’ve encountered so far, isArray returns true if the argument is an array and false if the argument is not an array.

const a = []; const b = {}; Array.isArray(a); //true Array.isArray(b); //falseCopy the code

I try to call this method before rewriting the Object. The prototype. The toString method:

Object.prototype.toString = ()=>{ console.log('Hello Howard'); } const a = []; Array.isArray(a); //trueCopy the code

Does not affect the outcome of the judgment. I tried modifying the constructor object again:

const a = []; const b = {}; a.constructor = b.constructor; Array.isArray(a); //trueCopy the code

OK, it still doesn’t affect the result of judgment.

Visible, it and the instance of operator judgment method, and the Object. The prototype. The toString method is not the same, a series of changes did not affect the judgment result.

You can safely use array. isArray to determine whether an object is an Array. Unless you accidentally overwrite the array.isarray method itself.

Important addition: Some readers remind me in the comments that array. isArray is a method added in THE ES2015 standard, and some older browsers may have compatibility problems. Therefore, in order to enhance robustness, it is recommended to judge the array. isArray method, enhance compatibility, and repackage the method as follows:

if (! Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }Copy the code