I'm trying to use the arr.includes(item). The function should return True if the item is an element of the array. But it doesn't seem to be able to do so with a multidimensional array. Take a look at this screenshot (running node in the console):
I got a similar result on my Google Chrome.
Is it because it's an EC6 function, and not yet completely functional?
No information on such a problem on the Mozille page.
No, you can't use it on deep structures, because it performs an === test that checks that the operands are the same object, and not two (different) objects that happen to have the same contents.
On the MDN page you linked to there's a polyfill where you can see that === test within the sameValueZero() nested function.
For the above reasons, this would actually return true:
let a = [0, 1];
let b = [1, 2];
let c = [a, b];
c.includes(b);
> true
because the object passed to .includes really is the same object that's contained in c.
Related
MDN provides a way to flat an array recursively:
function flatDeep(arr, d = 1) {
return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
: arr.slice();
}
Why we need arr.slice() to get a copy? I think just arr is OK, is there any problem with just using arr?
It's intended to exactly emulate the behavior of Array.prototype.flat, which returns a new array even if there's nothing to be flattened:
const arr = [0, 1, 2];
console.log(arr === arr.flat());
The .slice isn't necessary to produce a flattened array, it's just there to create a new array reference just in case there's no recursion to do.
The requirement of the creation of a new array is described in the specification here, and in FlattenIntoArray. Even if there aren't any elements to flatten, a new array is created by assigning all properties and values of the old array to the new array. ("Repeat, while sourceIndex < sourceLen: (assign property origArr[sourceIndex] to new array)")
Technically there is no problem if you don't modify the returned value.
However the behaviour is confusing if the returned value is modified, either by an unknowing user or by accident.
A function that sometimes returns a clone and sometimes returns a reference makes it harder to debug,
and is most likely considered an antipattern.
Since there is no standard for indicating whether a returned array is mutable in JavaScript,
MDN most likely considered it is better to be safe and consistent
I wanted to know how javascript arrays work internally, I mean when for example you create a new array.
array = [1,2,3];
It's internally creating a new array: array = new Array();
and then calling Array.push() or similar?
Thanks.
The best resource to find out how javascript internals work is ECMAScript specification itself.
In order to understand what happens internally when you do array = [1, 2, 3] you would need to read section 7.3.16 CreateArrayFromList (elements). Roughly what happens is that first Array object gets created, then each element gets set to this object with CreateDataProperty (7.3.4 CreateDataProperty section) (DefineOwnProperty) internal method.
Then you want to learn what exactly happens when you push element to array. You check 22.1.3.17 Array.prototype.push ( ...items ) section for this. There you will find out that it uses quite different algorithm, namely it sets specific property of an object (7.3.3 Set (O, P, V, Throw) section).
So the answer is no, creating array like a = [1, 2, 3] does not uses same mechanics to insert items as push does. The first one roughly creates new property on (newly created) array object, the push sets property to existing object.
and then calling Array.push() or similar?
No. As you can see in the below example that when array is initialized push (overridden) method is not invoked.
Array.prototype.push = function(){ console.log("adding") };
var array = [1,2,3];
//console.log(array);
But, it is invoked when console statement is executed (after un-commenting the same).
var array = [1,2,3];
It doesn't call push but it's a simpler way to initialize an array when you know the elements in advance.
If you want to add another element you can do it in multiple ways like:
1) array.push(22); // adds integer 22 to the array
or
2) array[4] = 22; // adds integer 22 to the array at index 4
You can even do this:
array[20] = 22; // this will resize the array and keep all the uninitialized elements returns undefined. So array[10] is undefined, for ex.
If you want to know all the details about arrays explained in a simple way I recommend you the book: Secrets of the JavaScript Ninja. It has an entire chapter about arrays.
https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/1617292850/ref=sr_1_1?ie=UTF8&qid=1519484868&sr=8-1&keywords=javascript+ninja
var primes=[2,3,5,7]
primes.sync = function(){this[0]=23;}
primes // => [2, 3, 5, 7]
primes.sync()
primes // => [23, 3, 5, 7]
This seems to work perfectly in Chrome.
Are there any reasons to not use this syntax/"feature"? Also, can I count on primes to be behave as a normal array (e.g. when passing it to a function that expects an array)?
This is why I want to use it:
Say I have a peopleList in my program. Functions all over the app will use it like an array. Then, suddenly, I do a POST to the server. I then want the array to query the server directly, and update itself. This would allow for some very elegant code in my angular.js app.
The only trouble you'll likely have will be if you (incorrectly) try to use for-in to iterate the Array. As long as you use a for statement or one of the Array iterator methods to constrain the enumeration to numeric indices, there shouldn't be any trouble.
The Array will continue to behave like a typical Array.
What you would want to do is to add a function to Array.prototype, rather than adding it to an array instance. See below.
Array.prototype.sync = function(){this[0]=23;};
This way, all array instances, including those that have been initialized before adding the function, will automatically be able to use the function at once.
var a = [];
a.sync(); // TypeError: Object [object Array] has no method 'sync'
Array.prototype.sync = function(){this[0]=23;};
a.sync();
a // [23]
var b = [1,2,3];
b.sync();
b // [23, 2, 3]
However, only add those functions that are useful/meaningful/reusable to Array.prototype because it is going to be available for all array instances ever created and will be created.
If your function is going to be used by only few instances. You are better of adding them to each instance like you did above.
Any programming language which provides arrays (lists, vectors, tuples etc.) must decide whether they have reference or value semantics, with the usual/obvious choice being reference semantics for mutable arrays and value semantics for immutable ones.
JavaScript which provides mutable arrays appears to have chosen reference semantics e.g. given
var a = [1, 2, 3]
var b = [1, 2, 3]
then a != b, as expected because though they have the same contents, they are different arrays.
However when you use them as keys in an object, the picture changes; if you set obj[a] to a value, then obj[b] gets the same value. Furthermore, this remains true if you change the contents of the arrays; at least when I tested it in Rhino, it behaves as though the interpreter were recursively comparing the full contents of the supplied and stored key arrays on every lookup, complete with a check for the infinite loop that would occur if one of the arrays were made to point to itself.
Is this the intended/specified behavior in all implementations?
Does it also apply to objects used as keys?
Is there any way to get the other behavior, i.e. to look up values using arrays as keys with reference semantics?
When arrays are used as property names they are cast to a string:
[1,2,3].toString() == '1,2,3'
Once turned into a string value, arrays with the same contents would map to the same property.
To answer your last question, you can't use objects to reference property names (keys) whereby only the same object maps to the same property (1:1 mapping).
obj[a] and obj[b] will run the toString function on the arrays and produce the same result for both. It doesn't try to use the arrays as keys.
var a = [1,2,3];
var x = {};
x[a] = "test";
var i;
for(i in x)
{
alert(i); //"1,2,3"
}
jsFiddle example
My question is the same as Are Javascript arrays sparse? with one difference...
Are JavaScript arrays sparse, as implemented in Node.js (and/or V8)? I had assumed the were, but then I did the following test:
var testArray = [];
testArray[10000] = 'test';
console.log(testArray);
Returned is 10,000 blank elements, with 'test' at the end. Is this because of the way the debugging output works, or does Node.js actually allocate memory for the undefined array elements when adding new elements?
What you are seeing is not an actual array, just a representation. The console checks for the presence of a length and a splice property and prints the numeric properties of the object, which is why jQuery collections appear to be arrays when logged.
function RandomThingThatIsDefinitelyNotAnArray() {
this.splice = function() {};
this.length = 10;
this[5] = 5;
}
console.log(new RandomThingThatIsDefinitelyNotAnArray());
// shows [undefined, undefined, undefined, undefined, undefined, 5]
jsfFiddle for a live demo.
Node's util.inspect function specifically checks for sparse arrays to print them like that. In fact, it has a test that specifically checks for it. I know this because my full rewrite of node's inspector ultimately didn't make it into core, and lead to my UltraREPL.