11

I have two versions of a identical code block in php and javascript. Output of them is slightly different. There are two "undefined" elements in Javascript output. I know that the Javascript Array indexes are incremental which starts from 0 and don't allows us to skip any index number.

Is there anyway to solve this so the Javascript Array output looks like the Php Array output?

Php Code:

$n = array();
$n[0] = 'Apple';
$n[3] = 'Apple';
echo "<pre>";
print_r( $n );
echo "</pre>";

Output:

Array
(
    [0] => Apple
    [3] => Apple
)

Javascript Code:

var n = new Array();
n[0] = 'Apple';
n[3] = 'Apple';
n;

Output:

[
    "Apple", 
    undefined, 
    undefined, 
    "Apple"
]

Thanks!!

Aefits
  • 3,399
  • 6
  • 28
  • 46
  • Why dont you try a for loop and then an if inside which verifies if the current array isnt null..? – Peter Aug 20 '15 at 05:48
  • `console.table(n)` gives what you need (on Chrome) and `console.log(n)` gives the required output on other browsers too. They don't display the `undefined` elements. – TheChetan Feb 03 '18 at 18:11
  • yes you can use json objects instead of arrays. e.g. `var n = {0:"apple",3:"Apple"}` and you get them using `n[1]` – CME64 Feb 07 '18 at 08:31

8 Answers8

19

As you mentioned JavaScript Arrays have index limitations.

The closest way you can get the output you are looking for is by using a JavaScript Object.

If you then use JavaScript JSON stringify to convert the object into well formatted text you will get an almost identical output with little effort.

You could write extra JavaScript to have the output exactly mirror the PHP output. But I will leave that up to you.

var n = new Object();
n[0] = 'Apple';
n[3] = 'Apple';

var output = JSON.stringify(n, null, 2);

// Output to a pre tag like the PHP example you gave.
document.getElementById("output").innerHTML = output;

// Simple output to the console.
console.log(output);
<pre id="output"></pre>
fjoe
  • 1,150
  • 7
  • 15
  • Note that plain javascript objects do not have order like arrays do. – Marco Feb 07 '18 at 21:16
  • @d3L This is true but the Poster is trying to model a PHP array's output in JavaScript. As both a PHP array and a JavaScript Object do not have an inherent order it follows that a JavaScript object is the best data type to use not a JavaScript array. – fjoe Feb 08 '18 at 05:16
  • And yes I agree. I just wanted to mention that in case OP does iteration. – Marco Feb 08 '18 at 06:30
  • @d3L PHP arrays do have order and can be sorted but they take on the order they where declared in. [Here is an example in codepad](http://codepad.org/jpJH3doa). Even more interesting is how the browser does some sorting even though its not part of that JavaScript Object standard. [See jsfiddle](https://jsfiddle.net/cuwdgynL/2/). – fjoe Feb 08 '18 at 06:58
  • All the `JSON.stringify...` and everything after that is unnecessary. `var n = {}; n[0] = 'A'; n[3] = 'B';` will have the desired result. – Tony Chiboucas Feb 08 '18 at 16:41
  • 1
    @TonyChiboucas Technically yes the solution to the question is the use of a JavaScript Object but for completeness I have given an example that shows an easily verifiable result that mirrors the results the OP was looking for. – fjoe Feb 08 '18 at 19:17
7

I think in your case more good to use object instead of array, such as in JS associative arrays the same objects. F.e.

var n = {};
n[0] = 'Apple';
n[3] = 'Apple';
console.log(n);

it will output

Object {0: "Apple", 3: "Apple"}

EDITED You can get elements from object like in array:

n[0], n[3]
Taron Saribekyan
  • 1,360
  • 7
  • 13
  • 1
    In this case you are not able to loop object like array because object dose not have length property. so for looping through each property in object you have to go with for in loop. – Ejaz47 Feb 07 '18 at 05:41
7

PHP Arrays are Hash Tables, Javascript Arrays are indexed lists

Short Answer

No. There is no way to make Javascript arrays behave like Php arrays without violating ECMA standards (which would mean it's technically no longer javascript).

Yes. But only by replacing the built-in Array prototype behaviors.

See ECMA-262 Section 15.4 Array Objects

What is an array anyway?

Arrays are ordered data and nothing more. While arrays do have an index, the concept of an array "index" shouldn't be conflated with the concept of labeled data storage. Array indices are always sequential, because it points to a position in the array, similar to positions of people in a line.

You couldn't make a line of people with one person first, and one person fourth, and no one else in line. n[0] = 'first'; n[3] = 'fourth;

This is how arrays are defined in nearly every programming language, because it is how the data is stored in memory.

Use Objects Instead

This is the same answer many others have already given to this question. Ultimately a javascript Array is just a predefined type of object, built to behave as outlined above. Thus, the behavior you are trying to change, is actually a behavior that has been carefully engineered.

So, instead of using the special "Array" object, use string keys (as object named properties) and your whole problem is simplified.

Note: this is essentially what the other 'Use an object' answers here are doing, with one notable exception.

n['0'] = 'Apple';
n['3'] = 'Apple';

// OR

n = {
    '0': 'Apple',
    '3': 'Apple',
};

// numeric keys are possible, IFF the var is first explicitly defined as an object.
n = {};
n[0] = 'Apple';
n[3] = 'Apple';

Object isn't enough, it must be an Array? Roll your own "Array" container object.

The drawback here is that you'll need to manually define all the method calls you would like to pass to the array object itself.

var PhpArray = function(ary){
    if (ary instanceof Array) {
        this.ary = ary;
    } else {
        this.ary = new Array(ary);
    }
};

PhpArray.prototype.forEach = function(f){
    for(i in this.ary){
        if (this.ary[i] !== undefined && this.ary[i] !== null) {
            f(i, this.ary[i]);
        }
    }
};

PhpArray.prototype.toString = function(){
    var strResult '';
    this.forEach(function(k, val){
        switch(typeof val) {
            case 'boolean':
            case 'string':
            case 'number':
                strResult += k + ': ' + val;
                break;
            default:
                if (val.toString) {
                    strResult += k + ': ' + val.toString();
                } else {
                    strResult += k + ': ' + typeof val;
                }
        }
    });
};

// Usage:
var n = Array();
n[0] = 'Apple';
n[3] = 'Apple';
var x = new PhpArray(n);
console.log('' + x);

x.ary[5] = 'Pear';

Still not good enough? "Change the Array Behavior!?" you say?

Want to access x[3] = 'Apple'; from the example above?

Or perhaps you really want to override the built-in Array prototype?

Well buckle your seatbelt Dorothy, because javascript is going bye-bye. That's right, we're going somewhere over the ECMA where you can do whatever you want. Sure, other developers will hate you, and third party tools (jQuery) won't work anymore, but at least you'll have your javascript Arrays that aren't arrays.

Unfortunately, I'm not going to help you do that.

Tony Chiboucas
  • 5,505
  • 1
  • 29
  • 37
1

The reason that you are getting "undefined" values is that Javascript replaces any missing indexes/blanks in the list of array keys with the value of "undefined", i.e. index 1 and 2 in your case.

Rather than adding the element to your array by the key name, just push it onto the end of the array:

n.push("Apple");

Note! This will of course cause the indexes of the values in the Javascript to be different from your PHP script, as using push will always insert the value to the end of the array. That said, to make insert in exactly the same manner in both scripts, I would suggest that you use PHP's array_push method, which works the same way as Javascript's push method. Alternatively, you can use the same approach as you do now for the PHP script, but always insert at the end of the array, e.g:

$n[0] = 'Apple';
$n[1] = 'Apple';
nils1k
  • 467
  • 5
  • 20
1

It's worth noting that iterating over multidimensional variable in js is a little different than php.

PHP

$myArray = [0=>'here',1=>'we',2=>'go'];
for($i=0;$i<count($myArray);$i++){ echo $myArray[$i]; }
// or 
foreach($myArray as $item){ echo $item; }

javaScript There's ways to get the length of an object, but it can be tricky, so:

myObject = {0:'here',1:'we',2:'go'};
for(item in myObject){ console.log(myObject[item]) }
admcfajn
  • 2,013
  • 3
  • 24
  • 32
0

In your JS code do :

n = n.filter(function(n){ return n != undefined });
console.log(n);

This should eliminate the undefined elements. and outputs:

[
    "Apple", 
    "Apple"
  ]

Note that in php if you do:

echo $n[1] ; 

you will get:
Notice: Undefined offset: 1 in .....

USER249
  • 1,080
  • 7
  • 14
0

In Javascript Array it uses the index to find the value, so if it not find any value in that index it sets it as undefined or empty so to remove undefined we can use this function.

 Array.prototype.remove = function(deleteValue) {
      for (var i = 0; i < this.length; i++) {
        if (this[i] == deleteValue) {         
          this.splice(i, 1);
          i--;
        }
      }
      return this;
    };

    var a = [];
    a[0] = 'zero';
    a[3] = 'three';
    a.remove(undefined);
  • 1
    Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation would greatly improve its long-term value](//meta.stackexchange.com/q/114762/350567) by showing *why* this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you've made. – iBug Feb 08 '18 at 06:56
-1

As I can see, multiple answers are suggested. If you requirements just to show data only, not for production release. You can override toString method for demo purpose. Here below is the given snippet.

// Override toString
Array.prototype.toString = function () {
    return this.filter(x => x)
};

//How to use it
var n = new Array();
n[0] = 'Apple';
n[3] = 'Apple';
console.log(n.toString());

Why you should use toString in console.log.

Does console log invokes toString method of an object

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
xdeepakv
  • 7,835
  • 2
  • 22
  • 32