I've found something interesting and I don't know why it's happening.
If I try in google chrome developer tools, the following two staments
(Array([1,2,3])).filter(function (item, index, array) {
return item === 1;
}); ==> []
and
([1,2,3]).filter(function (item, index, array) {
return item === 1;
}); ==> [1]
The results are an empty array for the first statement and array with a single value (1) for the second
Inspecting the parameters for the callback function, i found that in the first statement the arguments are (array, index, value) and for the second statemente are(value, index, array).
Inspecting with typeof and constructor of both objects the result are the expected, and the same "object", and Array.
Why is this happening?
Thanks
Because that's not how you define an array with Array().
Should be without the square brackets, otherwise it's an array of a single element, which is also an array ([1,2,3]).
Array(1,2,3)
That inner array never equals to 1 (basically you check [1,2,3] == 1), so the result is an empty array.
If you define an array by using Array([1,2,3]) this code, then the following array will be created,
[[1,2,3]]
Since you are pushing an array into another one. And if you really want the Array function to create an array by reading an array then you have to write something like this,
Array.apply([], [1,2,3])
But the above one is completely pointless. Again I am telling it is completely pointless since we are having an array that we require in our hand. But just for a knowledge you can know about it.
Array([1,2,3]) create array of arrays [[1, 2, 3]] so .map()function will iterate one time only.
If you want to create array with Array constructor use next syntax:
Array(1,2,3)
the shorter is the better :
[1,2,3].filter(item => item === 1);
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
I am new to javascript. I am doing a task which trying to get the first item removed from an array in javascript.
Method One
function getFirst(arr, item) {
arr.push(item);
var removed = arr.shift();
return removed;
}
Method Two
function getFirst2(arr, item) {
arr = arr.push(item);
var removed = arr.shift();
return removed;
}
I comes out with these two solution but only method one accepted and method two is the wrong one which return Uncaught TypeError: arr.shift is not a function().
What is the extacly meaning of Uncaught TypeError and state that arr.shift is not a function but it works on Method one?
Any help will be appreciate! Thanks!
Your function getFirst2() is not working because of arr = arr.push(item).
Here arr actually becomes a number, as the push method on an array returns the new length property of the object upon which the method was called.
Thus calling method push on a number throws a TypeError.
Your first Method is alright. But i'd like to note that you do not always have to create a local fucntion-scope variables. Your return statement can return computed values. So instead of
function getFirst(arr, item) {
arr.push(item);
var removed = arr.shift();
return removed;
}
I would go for
function getFirst(arr, item) {
arr.push(item);
return arr.shift();
}
You can apply the shift function on an array. In method 2, arr is not an array anymore because I think that the push method returns the length of the array. This is why you are getting a typeError.
Try printing arr before applying the shift method to see what it is.
Javascript has many inbuilt functions that are attached to different data types. The Array type has the functions push(), unshift(), shift() etc that are attached to every array but not to other non-array types.
When you use these Array functions on any type that is not an array you get the Uncaught type error, because the Javascript interpreter cannot read the function off that type.
Your second function on this line: arr = arr.push(item); , changes the value of arr to a number because the return value of the function arr.push(item); is a number(Int). Hence trying to call .shift() on arr is no longer allowed because arr is no longer an array.
i have a function in javascript where i need to retrieve the last element of the list. the list can be an array, string, list in numbers (not array). I tried converting the list into a String and then an array and retrieving it by index, but that's not working.
Here is the code I tried:
function last(list){
var array = new String(list);
array = array.split("");
return array[array.length-1];
}
I don't understand what the problem is because test suite says Expected: 5 instead got: 5
I am using code wars and did not write the tests. Is it expecting a Number and getting a String '5' ? I don't understand types in loosely typed languages very well yet.
from the comments, I think you mean you want to either return the last element in an array, the last character in a string, or the last argument passed if multiple arguments were passed. This would do it:
function last() {
if (arguments.length > 1) { // first we handle the case of multiple arguments
return Array.prototype.pop.call(arguments);
}
value = arguments[0]
if (typeof value === 'string') { // next, let's handle strings
return value.split('').pop();
}
if (Object.prototype.toString.call( [] ) === '[object Array]') {// Arrays are of type object in js, so we need to do a weird check
return value.pop();
}
}
arguments is a pseudo-array that contains all arguments passed into the function, so for last(1,2,3,4,5), arguments would be roughly [1,2,3,4,5]. It's not exactly that though, because arguments has all args in order and a length property, but it's prototype isn't Array, so it isn't truly [1,2,3,4,5] and lacks all of array's functions. This is why we need to call pop in the context of arguments (in javascript, Function.prototype.call calls the function passing the first arguments as the value of this, and all the rest of the arguments into the arguments pseudo-array, so for example last.call([], 1, 2, 3) would call last in the context of a new array and with arguments roughly equal to [1,2,3]).
the rest of the code is pretty straightforward, except for the check to see if value is an array, which is further explained here.
Finally, pop is an array method that removes the last element from an array and returns it.
I have an associative array with two object inside. Running this through $(myassoc).each(), the callback runs only once. Also the callback parameters (index and object) returns 0 and the entire associative array, respectively.
One would expect jQuery.each() to run for each element in the array, returning the correct keys as index and the correct element as the object.
Why isn't that happening, and can jQuery do what I'm after?
I think you're looking for jQuery.each() instead of .each()
try this:
$.each(myassoc, function(index, value){
//your code
});
try this:
$.each(assocarray,function(i, value){
console.log('index: ' + i + ',value: ' + value);
});
Badly.
Don't $(associative_array).each(function () {...}) -- that's nonsense
Don't $.each(associative_array, function() {...}); -- that has an obscure bug(1)
To see the bug, try this in a javascript console:
> $.each({foo:1, length:-1, bar:2}, console.log)
foo 1
length -1
bar 2
> $.each({foo:1, length:0, bar:2}, console.log)
The first example outputs three lines of key-value pairs, as it should. The second outputs nothing!
The moral of the story, don't use jQuery.each() on objects. (Objects in JavaScript are essentially the same thing as associative arrays.) Things may work fine forever, but you run the risk that someday an object happens to have a member named length and its value happens to be exactly 0 and then you have a bug out of nowhere that can be very difficult to explain. (I'll let you guess, by the ponderous heft of this answer, whether that ever happened to me.)
As mentioned in the bug report:
If you need to iterate over all keys of objects having the length property, jQuery.each is not the correct solution.
I suggest going further, that jQuery.each should not be relied upon for associative arrays, ever.
(1) This "bug" may never be fixed, since $.each() historically uses Duck Typing on arrays: "Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index."
Here's what I use[thanks Dominik] to loop through property names and values of objects, or put another way, the keys and values of an associative array:
function looper(object, callback) {
for (var key in object) {
if (object.hasOwnProperty(key)) {
if (false === callback.call(object[key], key, object[key])) {
break;
}
}
}
return object;
}
looper() is then a drop-in replacement for $.each()
> looper({foo:1, length:0, bar:2}, console.log)
foo 1
length 0
bar 2
Just like $.each():
Inside the callback, this is each value
Inside the callback, returning false (not just falsy) terminates the loop
looper() returns the object originally passed to it
looper() works on arrays as well as objects.
Use:
var a = [];
looper({foo:1, length:0, bar:2}, function(k, v) {
a.push(k+"="+v);
});
console.assert("foo=1,length=0,bar=2" === a.join());
Try that with $.each() and you'll get an empty result. Because it interprets this particular object as an array-like object of zero length.
The problem is that the $.each() function internally retrieves and uses the length property of the passed collection. But in an associative array that has no integer indices the length always seems to be 0. For $.each() now there seems to be nothing to walk through.
The $.each() function internally retrieves and uses the length
property of the passed collection.
The solutions is simply to use an object instead.
var obj = {
"flammable": "inflammable",
"duh": "no duh"
};
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});