confused on the combination of Array.isArray() and every() - javascript

I am trying to check every element within the target object is an array object by using the every()function, the code as follows:
let targetObj = [[1,2],[3],4];
let result = targetObj.every((val,index,arr)=>{
return Array.isArray(val);
});
the resultis false because 4 is not an array object, but i found if i replace the callback function with Array.isArray which is still work:
let result = targetObj.every(Array.isArray);
So my questions are:
1.In this way, since the callback function is not taking any parameters.Why the result still return false?
2.How the Array.isArraycallback function can automatically check every element from targetObjwithout gave any parameters?

Array.isArray has one param.
.every( ... ) gives 3 params.
A callback in .every (without calling it directly) is going to give params.
If the callback has more than 3 params, the next params are gonna be undefined.
Since you're not calling the callback, .every is calling it for you and it's gonna fill its params.

Related

Getting undefined instead of a correct result

I am trying to use forEach method on my array but I am getting undefined instead of a correct result. Could anyone help me and tell me what is wrong with my code?
[0,1,2,3].forEach((x,i) => (x*i)%3);
The return value of forEach() is undefined, use Array.prototype.map() instead:
var r = [0,1,2,3].map((x,i) => (x*i)%3);
console.log(r);
You're using forEach, which doesn't return anything, so the result of calling it is undefined. (forEach also completely ignores the return value of the callback it calls.)
If you want a return value, you probably want map (or possibly reduce), not forEach. For example:
console.log([0,1,2,3].map((x,i) => (x*i)%3));
You're returning nothing inside the forEach, write a console.log for that
This is from https://developer.mozilla.org/
forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain.
If you are trying to transform the array, use map() instead

Using destructuring assignment and the rest syntax for default variables

The following is an attempt to set the default value for an argument, based on the first argument:
function tree(values, ...[[curr] = values]) {
console.log(curr);
}
tree(['foo']); // foo
tree(['foo'], ['bar']); // bar
It appears to work (actually it isn't quite what I want, but I want to understand this first).
What is going on here?
The spread syntax is spreading an anonymous array with the contents of curr…
No. Nothing is being spreaded into an array literal.
The spread syntax is capturing the rest of the arguments into an anonymous array instance which is being destructured…
Yes.
…into the first value of either: the supplied array if present, or values.
Not sure I understand. The captured array is destructured to the target [[curr] = values], which takes out the first element or - if not present - the values default, and assigns that to the target [curr].
And as #FelixKling commented, you really should not do that, but use
function tree(values, [curr] = values) {
console.log(curr);
}
This happens because default parameters can reference previous parameters. In your example you are destructuring values to curr, that's why the console is printing the first element of the array. You could suppress the spread operator and the result would be the same:
function tree(values, [curr] = values) {
console.log(curr);
}
tree(['foo']); // foo
tree(['foo'], ['bar']); // bar
What is happening to the second call tree(['foo'], ['bar']) is that the second argument (['bar']) is overriding [curr] default value.
Please let me know if I wasn't clear enough.
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters (look for the section titled "Default parameters are available to later default parameters")

How does this unique() function work

As I was looking at a unique() function I found
which takes an array as argument and returns a new array which contains the unique elements of this array (which means no duplicated items). However I cannot understand the logic of this function. Can somebody explain it to me?
Here is the function:
function unique ( array ) {
return array.filter(function(a){
return !this[a] ? this[a] = true : false;
}, {});
}
I can't really understand the whole code especially the !this[a] ? this[a] = true : false; and the new object ({}) that is passed as the second argument to filter.
Let's start with the filter:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
The a is the random number of the array to which you apply the filter. The whole essence is in the following statement:
return !this[a] ? this[a] = true : false;
If the this[a] is true, a has been already processed once and it has been added to this as one of its properties. Otherwise, this[a] is false. So taking its negation result in true and the current a should be returned. Furthermore this[a] would be set to true and then we proceed to the next a.
The following snippet will help you grasp what filter does:
var numbers = [1,2,3,4,5];
var filteredNumbers = numbers.filter(function(number){
console.log(number);
return number > 2;
});
console.log(filteredNumbers);
And the following snippet will show you in action what happens in unique function:
function unique ( array ) {
return array.filter(function(a){
console.log(this);
return !this[a] ? this[a] = true : false;
}, {});
}
var array = [1,2,3,1,2,3,4,5,5,6];
console.log(unique(array));
I understand the basic logic of filter but what i dont is the {}
passed as a 2nd argument and how each value is added to a new array
with !this[a]
The second argument is an optional value that you can pass to the filter method and it can be used as the this, when your callback would be executed (check the link I mentioned at the beginning about filter). You pass there an empty object. When you use the keyword this inside your callback, your refer this object. This is why the first time that code gets in this method returns {}. Check the first line of the output of the second snippet.
I will explain the second part of your question based on the second snippet. The first time you get in you have an empty object (I refer to this) and the first number processed is 1. So this1 would be undefined. So !this[1] would be true. Hence the first part after the ? is executed which is an assignment
this[1] = true.
Now this acquired its first key, 1, with value true. Furthermore, 1 would be returned from filter. The same happens with 2 and 3. When we arrive at 1 the
!this[1]
is false, since this[1] is true. So false is returned and the 1 now would not be added to the array that would be returned after all elements of array have been processed.
Basically, .filter would call the callBack function by supplying the individual values of the iterating array. If the callBack returns a value that resolves to true then that value will be collected, else that particular value will be ignored.
Here the second argument of filter has been used. That second argument will be used as a context(this) while calling the callBack internally. So here in your code, the passed object will be added with the array's value as property for each iteration. And in the consecutive iterations, the code will check the current value is available as a property in the initially passed object. If available then that ternary operator would return false, otherwise true.
Hence the unique values will be returned from the filter function.
Array.filter will only grab elements of the array when the function passed return truthy.
For each element of the array it is doing
return !this[a] // if value is not yet on this
? this[a] = true // add value to this and return true (grab element)
: false; // value was already cached, so return false (don't grab)
So it will only return 1 of each
Other answers have explained basically how this works. But a couple of points:
First, instead of return !this[a] ? this[a] = true : false;, it would be more concise to write
!this[a] && (this[a] = true)
Second, this code has the flaw that it only works on elements which can serve as keys into an object--basically strings or numbers. That is why using Set is better:
Array.from(new Set(array))
The above will work on any primitive or object.
Third, this approach does not work properly with strings and numbers. If the number 1 is present, it will filter out the string "1".
const uniq = a => a.filter(x => !this[x] && (this[x] = true), {});
console.log(uniq([1, '1']));
The reason is that object keys are string-valued.
Finally, IMHO this code is a bit too tricky for its own good. Most developers, even experienced ones, would stop and scratch their heads for a minute before figuring it out. Less experienced developers would have to consult the documentation for the thisArg parameter to Array#filter before being able to understand it. The ternary operator with the assignment inside is also a bit cryptic. I'd go ahead and write it out as
if (this[x]) return false;
this[x] = true;
return true;

Javascript: Adding a property to an array of objects

I have an array of objects as follows:
var myarray=[{"name":"John","address":"home"},{"name":"Peter","address":"home"}]
and I would like to run a function to add a property to the array as follows:
[{"name":"John","address":"home","collection":"friend"},
{"name":"Peter","address":"home","collection":"friend"}]
I have tried doing this:
myarray=myarray.map(function (err, myarray){
myarray.collection="friend";
return myarray;
}
console.log(myarray)
But the console continues to return this:
[{0},{1}]
Can anyone help me? Thank you
Your code is not adding the property to the contents of the array. The values of the array are given as the first parameter to the callback function (the second parameter is an index, and not the array itself—that's the third parameter). Simply assign the new property to the first parameter of the callback function, rather than the second one.
Edit - As #zerkms points out, however, if you're looking to update the current array rather than generate a new array, map is probably not best solution here. forEach provides a method for iterating over the current array, and modifying each of its values (which is what you're doing). This would looks omething like this:
myarray.forEach(function(value) {
value.collection = "friend";
});
As you'll notice in the documentation for .map, the callback function returns the new value that will appear in the new array that is generated by map; if you're changing the current array in place (i.e. by modifying the properties of its contents), there's no need to return anything.
myarray.map(function(value) {
value.collection = "friend";
});
Also note that both map and forEach are methods, so you need to close the method invocation with ).
Wrong use of map().
The first argument of map() is the current element of the array, the second argument is it's index.
For example:
['a','b','c'].map(function(element, index){console.log(element, index)});
Will result in
a 1
b 2
c 3
So inside your function myarray was your index, and you were trying to add the property to the index.
Now you have to options. Either you use the map() as it's ment to be used and assign it's return value to myarray:
myarray = myarray.map(function(element) {
element.collection = "friend";
return element;
});
or you can, because objects are not getting copied but referenced when passed as an argument, not care about the return values and modify the elements directly:
myarray.map(function(element) {
element.collection = "friend";
}); // returns [undefined, undefined ...]
This, however, isn't the way one should use map()
Better: Use forEach()
myarray.forEach(function(element) {
element.collection = "friend";
});
Hope it helped.
Greets!
All you have to do is changing the reference object within map function
myarray.map(function (value){
value.collection = "friend";
});
console.log(myarray);

Backbone example app and javascript apply

Hi can someone explain why in backbone example app (http://backbonejs.org/examples/todos/index.html) in remaining() function, is called using apply (this.without.apply(this, this.done());) and not this.without(this.done())
// Filter down the list of all todo items that are finished.
done: function() {
return this.where({done: true});
},
// Filter down the list to only todo items that are still not finished.
remaining: function() {
return this.without.apply(this, this.done());
},
Thank You !
#Update
Debugger output
this.without(this.done())
[child, child, child, child]
this.without.apply(this, this.done());
[child, child, child]
Variable list of arguments
The key is in the way without is written:
function () {
var args = slice.call(arguments);
args.unshift(this.models);
return _[method].apply(_, args);
}
It's anticipating a variable list of arguments, and one way to do that is to use apply:
...
return this.without.apply(this, ['pass', 'these', 'arguments']);
There's more about apply in the MDN documentation.
You asked what is the difference between these two calls:
this.without( this.done() )
vs.
this.without.apply( this, this.done() );
To clarify, let's remove the nested this.done() call. Now the first one is:
var value = this.done();
this.without( value );
That code obviously calls this.without() and passes it a single argument, whatever value was returned by this.done(). If value happens to be an array, the entire array is passed as a single argument.
The second version becomes:
var array = this.done();
this.without.apply( this, array );
That calls this.without() with a variable number of arguments, one argument for each element of array. (And I called it array instead of value this time, because for this code to make sense it has to be an array.)
.apply() also sets this in the called function, so passing this as the first argument just passes this along to that function in the same manner as a regular this.without() method call.
apply also lets you specify the "this" object for the function.
That matters sometimes, like when it is being called in a closure, where "this" might be different than you intended.

Categories

Resources