Doing Array.apply(null,[1]) gets me this [empty] but Array(null,[1,2]) gets me [1,2]
the array with 'empty' has a length of one but index zero is undefined.
Array.apply(null,[1]).length
1
Array.apply(null,[1])[0]
undefined
Array.apply(null,[1])
[empty]
console.log(Array.apply([1]));
console.log(Array.apply([1]).length);
There is nothing like empty variable in Javascript, they are empty slots. You are calling Array([1,2]) instead Array.apply([1,2]).
Both Array.apply([1]) and Array.apply([1,2]) will give you same result which will be [].
But when you call Array.apply(this,[1]) it will result in [empty] because internally it is equal to Array(1). And when you call Array.apply(this,[1,2]) it is equal to Array(1,2) which will be [1,2]. When only one number passed to Array constructor it returns an array of empty slots with its length property set to that number.
MDN Docs
The reason you are getting two different results is that in the first case of doing:
Array.apply(null,[4])
You are simply invoking the JavaScript Array constructor with a list of one argument. This single argument to the constructor is used to create an array of size n where n is the number you have in the list. It creates this list without anything in it.
For me in a node REPL, this is the result of the above:
> Array.apply(null, [4])
[ <4 empty items> ]
In the second case where you did:
Array.apply(null, [1, 2])
This is another constructor overload used to specify the contents of the array. So in this case, you are telling the array constructor to create an array containing the elements 1, 2.
> Array.apply(null, [1, 2])
[ 1, 2 ]
See the MDN documentation for details.
Related
I'm trying to understand why Javascript prints an empty array when it should have at least one value inside it. Please, check this code:
detail = [];
detail.cat1=[];
detail.cat2=[];
detail.cat3=[];
detail.cat4=[];
var newEntry = {"cod":"01","dt":"2021-10-02 09:07:21.205-07:00"};
detail.cat2.push(newEntry);
console.log(detail);
console.log(detail.length);
console.log(detail.cat2);
The results are:
> Array []
> 0
> Array [Object { cod: "01", dt: "2021-10-02 09:07:21.205-07:00" }]
How could it print [] since I have one object inside? And how can the length be zero? I was using any Javascript online editor, and the result is the same.
Since an array is really an object, we can add methods/properties directly to an individual array.
Then if you want to see the keys in an object for instance, Object.keys won't see it, but Reflect.ownKeys() will.
The Reflect version of defineProperty will return success or fail, while Object's returns the object passed.
Remember Reflect.preventExtensions() will (like it says) stop you or others from extending them.
As far as question about length is there, ".length" gives length of values not properties so it still gives 0
Array is an indexed collection of values, means you can put element at particular index and get element from particular index.
In the below example, you can see that if there are already elements in an array then you can get its length using length property.
Remember: The length of an array is (highest integer index at which the element is present in array + 1)
const arr = [1, 2, 3, 4];
console.log(arr); // prints whole array
console.log(arr.length); // prints length of an array
console.log(arr[2]); // Element at index 2
If you set element at particular index let say arr[8] = "something" then its length will be 9
const arr = [];
arr[8] = "something";
console.log(arr.length) // 9
It is true that array's are objects, so you can set/get values to/from array. But if you set property that is not a numbered index then it will not increase its length but It will set the property to that array object as:
const arr = [];
arr["introduction"] = "I'm an array";
arr.property = "This is a property"
console.log(arr.length);
console.log(arr.introduction);
console.log(arr.property);
When displaying an array, the default Array.prototype.toString method is usually called. This actually calls Array.prototype.join with no arguments, so produces a comma separated string of the elements of the array.
The join method only returns properties that have a positive integer name (an array index, indicating an array element), other properties are ignored by join.
Similarly, only elements of the array affect the length property, ordinarly properties (i.e. those that don't have an array index for their name) don't affect length.
I have an algorithm :
let someArray = [1, 2, 3, 4, 5]
let mapped = someArray.map(number => {
let index = someArray.indexOf(5)
if (index !== -1) {
someArray.splice(index, 1)
}
console.log(typeof number)
return number
})
console.log(mapped)
console.log(mapped.length)
console.log(Object.keys(mapped).length)
So what I expected to have was mapped=[1,2,3,4] and mapped.length=4
But instead I have mapped=[1,2,3,4,empty] and mapped.length=5.
So what I thought is : in the beginning, map is going for 5 iterations so it does it no matter what. That's why I added console.log(typeof number).
But it's executed only 4 times.
I know to have my expected result, filter is way better. I'm just wondering, what is happening here ?
See MDN documentation:
map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values, including undefined. It is not called for missing elements of the array (that is, indexes that have never been set, which have been deleted or which have never been assigned a value).
If existing elements of the array are changed, their value as passed to callback will be the value at the time map visits them. Elements that are deleted after the call to map begins and before being visited are not visited.
You're mutating the array as you're iterating over it, which means that once index [4] is reached, that element (whose value used to be 5) doesn't exist anymore, which means the function does not get called on that iteration, resulting in <empty>. The resulting array is created with 5 elements, but the callback is never called on the last element.
Use filter instead.
I understand you can pass an array to Function.prototype.apply but recently I've come across this code (it was written as a good way to create an array with undefined values as opposed to empty slots or holes);
var a = Array.apply( null, { length: 3 } );
I can't understand how this code works starting with the second argument. Is there another syntax that could be used to make it more understandable what's going on? What's going on when we pass an actual object to apply as opposed to an array? Can we somehow translate this object to an array to get this result? I've tried many things to do this, but without success.
Oh, that is just horrible.
So, when you call Array as a function, it doesn't really care what this is so you can tell it that this is null.
The second argument for apply is an array-like object which gives the list of arguments.
If you had [0, 0, 0] then that would be like this object:
{
0: 0,
1: 0,
2: 0,
length: 3
}
… because arrays get a length property which equals the value of their highest index. A real array would get other properties from the prototype, but we (and apply, and Array) don't care about them.
The arguments you pass to Array become its initial values.
Now, it seems that (internally) Array checks the length of its arguments and then sets its internal values using something like:
for (var i = 0; i < arguments.length; i++) {
internal_array_values.push(arguments[0])
}
And if you have an object which consists solely of { length: 3 } it is going to get undefined as the value of each of those three arguments giving you [undefined, undefined, undefined].
http://www.2ality.com/2012/07/apply-tricks.html
With apply and Array (which can be used as either a function or a constructor), you can turn holes into undefined elements:
Array.apply(null, ["a",,"b"])
// [ 'a', undefined, 'b' ]
This question already has answers here:
Undefined values in Array(len) initializer
(5 answers)
Closed 7 years ago.
I would expect the following code to return [1,1,1,1...]
(new Array(10)).map(function() { return 1;})
but it returns [, , , , , ...].
Moreover,
(new Array(10)).length == 10 and (new Array(10))[0] == undefined are true.
And for z = function(){return 0;}; the expression z(undefined) === 0 is also true.
Yet I have noticed that [,,,,,,,,,,].map(function() { return 1; }) also returns [,,,,....].
Can anyone explain why?
So. I would expect the following code to return [1,1,1,1...].
(new Array(10)).map(function() { return 1;})
But it returns [, , , , , ...].
Right, because new Array(10) creates an array with no elements with a length of 10, and map only iterates over elements that actually exist. (And yes, this is surprising. :-) )
Moreover, (new Array(10)).length == 10 and (new Array(10))[0] == undefined are true.
Again correct, because (again) new Array(10) doesn't put any elements in the array, so accessing [0] gives you undefined.
JavaScript's standard arrays aren't really arrays at all, and they can have a length that's a positive number without having any entries in them. They're a form of "sparse" array.
Let's take a simpler example:
var a = new Array(10);
a[2] = 1;
That array contains one element, the element at index 2. There is no element at index 0, no element at index 1, and no elements at indexes 3 and above. It just has gaps there. You can tell by asking it:
console.log(0 in a); // "false"
console.log(1 in a); // "false"
console.log(2 in a); // "true"
Standard arrays in JavaScript are just objects with special behavior assigned to length, special behavior assigned to a class of property names (loosely, numeric ones), and that are backed by Array.prototype.
This is all in contrast to the newer "typed" arrays, Int32Array and such, which are true arrays in the traditional sense.
This will work:
Array.apply(null, Array(10)).map(…
Live demo: http://jsfiddle.net/xXG5p/
You have to make the array dense first. new Array(n) creates a sparse array. Sparse arrays do have a length but they have no elements. Hence, a .map() call will not iterate at all.
Using my code above, you will create a dense array that does contain elements (whose values are initially set to null).
Here is what the Mozilla Developer Network says about Array.prototype.map:
callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
When you call new Array(10), the Array you create believes it is 10-element long but none of its indexes have ever been assigned to. Here's an example of what happens if you use a literal array for which you have not set values for some indices:
[1, , 3].map(function () {return "a"})
The value you get is:
[ 'a', , 'a' ]
Because at index 1, no value was assigned.
What exactly is the difference between:
Array(3)
// and
Array.apply(null, Array(3) )
The first returns [undefined x 3] while the second returns [undefined, undefined, undefined]. The second is chainable through Array.prototype.functions such as .map, but the first isn't. Why?
There is a difference, a quite significant one.
The Array constructor either accepts one single number, giving the lenght of the array, and an array with "empty" indices is created, or more correctly the length is set but the array doesn't really contain anything
Array(3); // creates [], with a length of 3
When calling the array constructor with a number as the only argument, you create an array that is empty, and that can't be iterated with the usual Array methods.
Or... the Array constructor accepts several arguments, whereas an array is created where each argument is a value in the array
Array(1,2,3); // creates an array [1,2,3] etc.
When you call this
Array.apply(null, Array(3) )
It get's a little more interesting.
apply accepts the this value as the first argument, and as it's not useful here, it's set to null
The interesting part is the second argument, where an empty array is being passed in.
As apply accepts an array it would be like calling
Array(undefined, undefined, undefined);
and that creates an array with three indices that's not empty, but have the value actually set to undefined, which is why it can be iterated over.
TL;DR
The main difference is that Array(3) creates an array with three indices that are empty. In fact, they don't really exist, the array just have a length of 3.
Passing in such an array with empty indices to the Array constructor using apply is the same as doing Array(undefined, undefined, undefined);, which creates an array with three undefined indices, and undefined is in fact a value, so it's not empty like in the first example.
Array methods like map() can only iterate over actual values, not empty indices.
The .map() API does not iterate over completely uninitialized array elements. When you make a new array with the new Array(n) constructor, you get an array with the .length you asked for but with non-existent elements that will be skipped by methods like .map().
The expression Array.apply(null, Array(9)) explicitly populates the newly-created array instance with undefined, but that's good enough. The trick is whether or not the in operator will report that the array contains an element at the given index. That is:
var a = new Array(9);
alert(2 in a); // alerts "false"
That's because there really is no element at position 2 in the array. But:
var a = Array.apply(null, Array(9));
alert(2 in a); // alerts "true"
The outer call to the Array constructor will have explicitly populated the elements.
This is an artifact of how apply works. When you do:
new Array(9)
an empty array is created with a length of 9. map does not visit non–existent members, so does nothing at all. However, apply turns the array into a list using CreateListFromArrayLike so it turns the formerly empty array into a parameter list like:
[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
that is passed to Array to create an array with 9 members, all with a value of undefined. So now map will visit them all.
BTW, ECMAScript 2015 has Array.prototype.fill for this (also see MDN) so you can do:
Array(9).fill(0);
Because the first array would not have ordered properties arr[0] === undefined and the second does. Array functions like forEach and map will iterate from 0 to the array's length - 1 and the lack of order to the properties of the first is an issue. The second version produces an array with the correct ordering, i.e.
arr = Array.apply(null, Array(3));
arr[0] === undefined //true
arr[1] === undefined //true
//etc.
The first version as you noticed doesn't. Also, adding new to the first version would not make it work.
In the first case you have one operation
Array(3)
Its creates an array with three empty slots. Not an array with the three undefined values but exactly - empty.
At the second case
Array.apply(null, Array(3) )
we can spread it to the three operations:
first: Array(3) - you get an array with 3 empty slots;
second: Array(3) spreads by Function.prototype.apply() function to 3 parameters that it passes to Array() function. At this stage 3 empty slots in given array transformes by apply() to 3 undefined values (it looks like if apply() sees an empty slot it automaticaly turns it to undefined in any sparsed array).
third: we get an Array(undefined, undefined, undefined). And that will do to us an array with 3 undefined (not empty) values.
Because now you have 3 undefined but not empty slots, you can use them with map() function.
Note that not only Function.prototype.apply() have such behavior of decomposing arrays by such way. You can also do this in ECMAScript 6 by "..." - spread operator.
Array(...new Array(3));
This will also returns an array with 3 undefined and respectively can be mapped slots.
Here i giving more detailed explanation.
https://stackoverflow.com/a/56814230/11715665