PHP's is_array in JavaScript

Here’s what our current JavaScript equivalent to PHP's is_array looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
module.exports = function is_array (mixedVar) { // eslint-disable-line camelcase
// discuss at: http://locutus.io/php/is_array/
// original by: Kevin van Zonneveld (http://kvz.io)
// improved by: Legaev Andrey
// improved by: Onno Marsman (https://twitter.com/onnomarsman)
// improved by: Brett Zamir (http://brett-zamir.me)
// improved by: Nathan Sepulveda
// improved by: Brett Zamir (http://brett-zamir.me)
// bugfixed by: Cord
// bugfixed by: Manish
// bugfixed by: Brett Zamir (http://brett-zamir.me)
// note 1: In Locutus, javascript objects are like php associative arrays,
// note 1: thus JavaScript objects will also
// note 1: return true in this function (except for objects which inherit properties,
// note 1: being thus used as objects),
// note 1: unless you do ini_set('locutus.objectsAsArrays', 0),
// note 1: in which case only genuine JavaScript arrays
// note 1: will return true
// example 1: is_array(['Kevin', 'van', 'Zonneveld'])
// returns 1: true
// example 2: is_array('Kevin van Zonneveld')
// returns 2: false
// example 3: is_array({0: 'Kevin', 1: 'van', 2: 'Zonneveld'})
// returns 3: true
// example 4: ini_set('locutus.objectsAsArrays', 0)
// example 4: is_array({0: 'Kevin', 1: 'van', 2: 'Zonneveld'})
// returns 4: false
// example 5: is_array(function tmp_a (){ this.name = 'Kevin' })
// returns 5: false

var _getFuncName = function (fn) {
var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn)
if (!name) {
return '(Anonymous)'
}
return name[1]
}
var _isArray = function (mixedVar) {
// return Object.prototype.toString.call(mixedVar) === '[object Array]';
// The above works, but let's do the even more stringent approach:
// (since Object.prototype.toString could be overridden)
// Null, Not an object, no length property so couldn't be an Array (or String)
if (!mixedVar || typeof mixedVar !== 'object' || typeof mixedVar.length !== 'number') {
return false
}
var len = mixedVar.length
mixedVar[mixedVar.length] = 'bogus'
// The only way I can think of to get around this (or where there would be trouble)
// would be to have an object defined
// with a custom "length" getter which changed behavior on each call
// (or a setter to mess up the following below) or a custom
// setter for numeric properties, but even that would need to listen for
// specific indexes; but there should be no false negatives
// and such a false positive would need to rely on later JavaScript
// innovations like __defineSetter__
if (len !== mixedVar.length) {
// We know it's an array since length auto-changed with the addition of a
// numeric property at its length end, so safely get rid of our bogus element
mixedVar.length -= 1
return true
}
// Get rid of the property we added onto a non-array object; only possible
// side-effect is if the user adds back the property later, it will iterate
// this property in the older order placement in IE (an order which should not
// be depended on anyways)
delete mixedVar[mixedVar.length]
return false
}

if (!mixedVar || typeof mixedVar !== 'object') {
return false
}

var isArray = _isArray(mixedVar)

if (isArray) {
return true
}

var iniVal = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.objectsAsArrays') : undefined) || 'on'
if (iniVal === 'on') {
var asString = Object.prototype.toString.call(mixedVar)
var asFunc = _getFuncName(mixedVar.constructor)

if (asString === '[object Object]' && asFunc === 'Object') {
// Most likely a literal and intended as assoc. array
return true
}
}

return false
}
[ View on GitHub | Edit on GitHub | Source on GitHub ]

How to use

You you can install via npm install locutus and require it via require('locutus/php/var/is_array'). You could also require the var module in full so that you could access var.is_array instead.

If you intend to target the browser, you can then use a module bundler such as Browserify, webpack or rollup.js.

ES5/ES6

This function targets ES5, but as of Locutus 2.0.2 we also support ES6 functions. Locutus transpiles to ES5 before publishing to npm.

A community effort

Not unlike Wikipedia, Locutus is an ongoing community effort. Our philosophy follows The McDonald’s Theory. This means that we don't consider it to be a bad thing that many of our functions are first iterations, which may still have their fair share of issues. We hope that these flaws will inspire others to come up with better ideas.

This way of working also means that we don't offer any production guarantees, and recommend to use Locutus inspiration and learning purposes only.

Notes

  • In Locutus, javascript objects are like php associative arrays, thus JavaScript objects will also return true in this function (except for objects which inherit properties, being thus used as objects), unless you do ini_set(‘locutus.objectsAsArrays’, 0), in which case only genuine JavaScript arrays will return true

Examples

Please note that these examples are distilled from test cases that automatically verify our functions still work correctly. This could explain some quirky ones.

#codeexpected result
1is_array(['Kevin', 'van', 'Zonneveld'])true
2is_array('Kevin van Zonneveld')false
3is_array({0: 'Kevin', 1: 'van', 2: 'Zonneveld'})true
4ini_set('locutus.objectsAsArrays', 0) is_array({0: 'Kevin', 1: 'van', 2: 'Zonneveld'})false
5is_array(function tmp_a (){ this.name = 'Kevin' })false

« More PHP var functions