alternative to for loop [duplicate] - javascript

This question already has answers here:
How can I convert the "arguments" object to an array in JavaScript?
(21 answers)
Closed 7 years ago.
How do I use .forEach instead of a for loop?
'use strict';
var score = (function(){
function updateScore() {
for(var i = 0; i < arguments.length; i++) {
this.score += arguments[i];
}// I want to use .forEach here instead of for loop.
return this.score;
}
return {
update: updateScore
}
})();
var soccer = {
name: 'Soccer',
score: 0
}
score.update.apply(soccer, [1,2,3])
console.log(soccer.score)
this will log 6.
I tried this
function updateScore() {
arguments.forEach((args, i) => {
this.score += args[i];
};
return this.score;
};
Error log: arguments.forEach is not a function

In modern (ES2015) JavaScript you can use Array.from():
Array.from(arguments).forEach((arg) => {
this.score += arg;
});
You don't need to use array indexing, as the .forEach() function passes each array element to the callback function as the first argument. (It does pass the index as the second argument, but in this case you wouldn't need to use that.)
It's important to note that if the arguments object is passed out of a function (as it would be here), the overall function may be considered ineligible for optimization. That's because the arguments object has some weird properties that make it very hard for the optimizer to know what's going on and whether it's safe to make assumptions about how local variables change. If that's a concern, then the only option is to copy the arguments into a simple array with a for loop.

Related

Expected a 'for-of' loop instead of a 'for' loop while doing modifications [duplicate]

This question already has answers here:
JavaScript by reference vs. by value [duplicate]
(4 answers)
Closed 3 years ago.
I'm having problems with TSlint and understanding why the for(i=0; ...) loop is not longer permitted.
Let's assume I have a simple code like:
this.filters['1','2','3'....];
for (let i = 0; i < this.filters.length; i++) {
if (this.filters[i] === '2') {
this.filters = new_value;
}
}
which TSlint is asking me to convert it to for-of. However, using for-of is not going to work as I need to modify the value and the for-of does not allow to modify. I could use something like
for (const [i, el] of this.filters.entries()) {
but then I get a compilation warning
TypeScript and Iterator: Type 'IterableIterator<T>' is not an array type
and I do have to change the compilation options. Also, I could iterate over the keys() which I see a bit stupid having the for(const i=0...)
Can someone explain me why TSlint is still complaining about this and why is not allowing to use the for(const i=0; ....)
Furthermore, I just saw that if do this code in a for-of
this.filters['1','2','3'....];
for (let f of this.filters) {
if (f === '2') {
f = new_value;
}
}
I would end up with the same array as it is not modified after the loop, but however, if I have a similar approach but with objects
let filters = [{id:'1'},{id:'2'},{id:'3'}];
console.log(filters)
for (let f of filters) {
if (f.id === '2') {
f.id = 'toto';
}
}
console.log(filters)
Surprise, my array of objects is modified after the loop! Can someone explain me why ?
Thank you
I searched for the error and I saw it in github as an issue that was closed but I can't find the solution
https://github.com/palantir/tslint/pull/1813
With strings you get following:
String is assigned to f. Then new value is reassigned to f: f === '2'. But string from array is not touched.
With objects:
Reference to object is assigned to f. Then object is being modified: f.id = 'toto'. Since array contains only reference to an object - we get modified object in array.
Basically the answer ends up with difference between reference type and value type variables.
In your case if for (const [i, el] of this.filters.entries()) { does not work because of ts settings, you could try:
arr.forEach((entry, index) => arr[index] = ...);
or something more ugly:
for(entry of arr) {
arr[arr.indexOf(entry)] = ...;
}

Why can't I use filter to the arguments of a function? [duplicate]

This question already has answers here:
Why can't I call an array method on a function's arguments?
(8 answers)
How can I convert the "arguments" object to an array in JavaScript?
(21 answers)
Closed 4 years ago.
I am trying to check if the arguments passed to duckCount have the property 'quack' and return the number of arguments that do have it.
To do so I was trying to use the filter on the arguments array but for some reason I can't. Anyone knows why?
var notDuck = Object.create({ quack: true })
var duck = { quack: true }
duckCount(duck, notDuck) // 1
function duckCount() {
// SOLUTION GOES HERE
console.log(arguments)
return arguments.filter((argument) => argument.hasOwnProperty('quack')).length
}
arguments is an object but not an array where as filter is an array function. Use the rest parameter to convert the argument object to array and then apply array function
var notDuck = Object.create({
quack: true
})
var duck = {
quack: true
}
// 1
function duckCount() {
// SOLUTION GOES HERE
console.log(arguments)
return [...arguments].filter((argument) => argument.hasOwnProperty('quack')).length
}
console.log(duckCount(duck, notDuck))
You can also use Array.from to a new instance from array like object
var notDuck = Object.create({
quack: true
})
var duck = {
quack: true
}
// 1
function duckCount() {
return Array.from(arguments).filter((argument) => argument.hasOwnProperty('quack')).length
}
console.log(duckCount(duck, notDuck))
brk's solution is the best way if you can guarantee that your code will only ever run on browsers which support ES6 (which these days mainly means "not IE") - but sometimes you do have to support older browsers. (This probably doesn't apply to the OP, due to the use of arrow functions, but this might be useful for others.) In case you need to, there is a useful trick which is barely any more bother than using array destructuring or Array.from:
return Array.prototype.filter.apply(arguments, function(argument) {/* your function goes here */});

Explain API function signature syntax [duplicate]

This question already has answers here:
How to interpret function parameters in software and language documentation?
(4 answers)
Closed 2 years ago.
Reading documentation for a few years I've often been confused by the syntax commonly used in explaining function signatures. for instance:
From the Mozilla Array.map Docs:
var new_array = arr.map(callback[, thisArg])
The docs list three arguments for the callback: currentValue, index, and array, but the signature just has this weird callback[, thisArg] syntax. Whats the deal with that comma? why are there array brackets next to 'callback'? Is there any documentation out there on this syntax? is there a name for this syntax? any help would be appreciated.
Thanks!
The function Array.prototype.map expects a function as the first argument:
var new_array = arr.map(callback[, thisArg])
The square brackets indicate that the secondparameter is optional. You can call Array.prototype.map with or without a second argument. Both functions calls are valid:
var array = [1, 2, 3, 4];
var myFunc = function (number) {
return number * 5;
};
var myFuncUsingThis = function (number) {
console.log(this);
return number;
};
var myThisArg = {
foo: 'bar'
};
console.log(array.map(myFunc));
console.log(array.map(myFuncUsingThis, myThisArg));
The last is the same as
console.log(array.map(myFuncUsingThis.bind(myThisArg)));
So, if the function that you provide to Array.prototype.map uses the this object, you can specify the this object of the function when it is called by Array.prototype.map by using the second (optional) argument.
currentValue, index and array are something completely different. You do not have to provide them when you call Array.prototype.map. Instead, Array.prototype.map provides them for you: it calls the function that you gave it with those three arguments (but you don't have to use all three arguments).
The first argument to your function is the value of the element in the array that is currently processed, the second argument is the index of that element, and the third argument is the array itself.
You can write a function that takes use of the index parameter:
var array = Array(20).fill(0); // an array containing 20 zeros
var evenNumbers = array.map(function (number, index) {
// number is zero, index is the index of the element we should transform
return index * 2;
});
console.log(evenNumbers);
Maybe it helps if you take a look at a (naïve) implementation of Array.prototype.map:
Array.prototype.map = function (callback, thisArg) {
// "this" is the array on which we work
var arr = []; // the new array that we build
var result;
for (var i = 0; i < this.length; i += 1; i++) {
result = callback.call(thisArg, this[i], i, this);
arr[i] = result;
}
return arr;
};
The parameters inside the brackets mean they are optional.

Why is my return value undefined (JavaScript) [duplicate]

This question already has answers here:
Jquery each - Stop loop and return object
(6 answers)
Closed 9 years ago.
I have an array called questionSets full of objects. The createSet function should create new or create a copy of an existing questionSets object. The function getQuestionsFromSet is used if createSet is used to make a copy. For some reason when I call getQuestionsFromSet() from inside createSet() I always get a returned value of 'undefined'. I can't figure out why because when I do a console.log() of the value to be returned by getQuestionsFromSet() I see exactly what I want.
I have these two functions.
function createSet(name, copiedName) {
var questions = [];
if (copiedName) {
questions = getQuestionsFromSet(copiedName);
}
console.log(questions); // undefined. WHY??
questionSets.push({
label: name,
value: questions
});
}; // end createSet()
function getQuestionsFromSet(setName) {
$.each(questionSets, function (index, obj) {
if (obj.label == setName) {
console.log(obj.value); // array with some objects as values, which is what I expect.
return obj.value;
}
});
}; // end getQuestionsFromSet()
Because getQuestionsFromSet() does not return anything and so is implicitly undefined.
What you need is probably something like:
function getQuestionsFromSet(setName) {
var matched = []; // the array to store matched questions..
$.each(questionSets, function (index, obj) {
if (obj.label == setName) {
console.log(obj.value); // array with some objects as values, which is what I expect.
matched.push(obj.value); // push the matched ones
}
});
return matched; // **return** it
}
return obj.value; is nested within the inner $.each(function{}), and getQuestionsFromSet is indeed not returning anything.

How String.concat() implements in javascript?

In function .concat(), I can pass an arbitrary number of arguments to it.
I understand function overloading in C++, but I don't know how implement a function with unknown number of arguments in JavaScript.
How do I implement an arbitrary number of arguments to a function?
In javascript, you would use the built in parameter called "arguments" which is an array of all the arguments passed to the function. You can obtain it's length with arguments.length and each value from the array arguments[0], arguments[1], etc... Every function has this built in variable that you can use.
For example, a function to concatenate all strings passed to it.
function concatAll() {
var str;
for (var i = 0 ; i < arguments.length; i++) {
str += arguments[i];
}
return(str);
}
var f = concatAll("abc", "def", "ghi"); // "abcdefghi"
You can do this using the arguments object. See the examples and documentation here: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments
Like this -
function f()
{
var i;
for(i=0; i<arguments.length; i++)
{
alert( (i+1) + "th argument: " + arguments[i]);
}
}
All the functions in javascript has a built-in parameter called arguments which is an array containing all the function arguments passed to the function. Just iterate over this array and you will be able to access all the arguments of a function.
As an example, once I've written a function which is used to enable/disable certain button if some specific fields were not empty. I wrote this function this way -
function toggleButton() // I used jquery inside this function
{
var i;
var last = arguments.length-1;
for(i=0; i<last; i++)
{
if( $.trim($(arguments[i]).val()) === "" )
return false;
}
$(arguments[last]).toggle();
return true;
}
and called this function like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfButtonToToggle");
or like this -
toggleButton("#idOfFirstField", "#idOfSecondField", "#idOfThirdField", "#idOfButtonToToggle");
so in both the cases, I was passing variable number of field ids to the function and it checked that if these fields were empty. If all of them contained some value, then it toggled the visibility of the button.
Like this - use the arguments object all functions have available :
function someFunction() {
for (var i=0,n=arguments.length;i<n;i++) {
// do something with arguments[i];
}
}
You can use the arguments array to access parameters that are not formally declared inside the function:
function printArguments() {
for (i = 0; i < printArguments.arguments.length; i++)
document.writeln(printArguments.arguments[i] + '<br />');
}
printArguments(1, 2, 3, 'etc');
Source: http://www.irt.org/articles/js008/
Any javascript function can have an arbitrary number of arguments. If function execution depends on the number or specific qualities of it's arguments, you'll have to check the arguments object, which can be iterated like an 'Arraylike' object, as others have shown.
In some cases it may be handy to convert the arguments to a real array, using something like
var args = Array.prototoype.slice(arguments).
Here's a blog entry from John Resigs page on method overloading that may interest you.

Categories

Resources