Related
I'm trying to use Closure in JS in order to declare a function named **expandArray()** which contain an Array named **myArray**and Returns an anonymous function that directly modifies myArray by increase the values by 1 than the returned function then returns the value of **myArray**. My Problem here one the last part where the returned function return a function not Array value ?!
This is my code
function expandArray() {
const myArray = [1, 1, 1];
return function () {
myArray.forEach( function (num, index, myArray) {
myArray[index] = num + 1;
});
return myArray;
};
}
console.log(expandArray());
As its closure, you have invoked it only once like expandArray() , which return the function itself, which is below
ƒ () {
myArray.map( function (num, index, myArray) {
myArray[index] = num + 1;
});
return myArray;
}
you need to invoke it again to get your result back as below
expandArray()() //[2, 2, 2]
Ref: How do JavaScript closures work?
You've written a function that returns a function when you run it:
function expandArray() {
const myArray = [...];
// return this when we run expandArray():
return function() {
...
}
}
So if you run expandArray(), it is going to return your anonymous function. Exactly as you wrote it to do.
If you then want to get an actual reference to that internal myArray, you'll now need to actually run that returned function, so:
var getMyArray = expandArray();
var result = getMyArray();
console.log(result);
Just fyi, you are doing something very similar to the memoization pattern.
To address your problem: as everyone else has already said, you return a function from expandArray. What you want is to return the closed array (after incrementing every element).
To do this, you can use something called immediately-invoked function expression in combination with arrow functions to simplify your code:
const expandArray = (() => {
const myArray = [1, 1, 1];
return () => {
myArray.forEach((num, index) => {
myArray[index] = num + 1;
});
return myArray;
};
})();
console.log(expandArray());
console.log(expandArray());
console.log(expandArray());
There are a couple of things incorrect with your code.
you can't change the values of variables declared within const. In the case of Objects and Arrays, you aren't allowed to assign a new reference with a new Array or Object. We change the declarative operator to let instead of const.
myArray.map doesn't mutate myArray, it returns a new array based on the input from myArray and your passed in function that adds 1 to each value. We can fix this by assigning myArray.map to the already declared myArray. That is to say, we're overwriting the old Array with a new one. This is why const in the above bullet point won't work.
Your map function parameters are unnecessary The parameters for it that are most often used are the first two available, which is the item in the array and the index of that item. Since we're iterating over each number using map the function can simply return the item (declared as num in your code) plus 1. This will return a new array with your changed values. So we don't need the index at all..
When you return a function from a function you need to invoke both to get the second return value. When using a closure you need to keep a reference to the initial returned function. This is confusing but if you think of it as levels - in your expandArray function you have two levels. The function itself and the function you're returning. when you call expandArray() you're invoking the first level, and making the second level available to be invoked, this is why expandArray() returns the second function and expandArray()() will return the value from the second function. We save the returned function in a variable called add_to_array by setting it equal to expandArray(), and then we consistently invoke add_to_array to return the new Array with the changed values.
This is the most confusing part of closures, but what is happening is that the add_to_array variable is like a wedge in the function. It stops myArray from being deleted by the Browser because it requires the function to exist in the event that it needs to be invoked again. It's kind of like a bookmark in a book. For the story to make sense whenever you open it, you don't just tear out the pages before the bookmark. You keep the story intact because in five years when you come back to it you may need to read the previous pages at the bookmark to remember where you were. A closure works the same way. It can't remove the variables from the initial expandArray function call because add_to_array is a placeholder in the middle of it. The reference point keeps the book open.
(for more info on closures you can check out this article here Destroying Buildings - A Guide to JavaScript Closures)
function expandArray() {
let myArray = [1, 1, 1];
return function () {
myArray = myArray.map( function (num) {
return num + 1;
});
return myArray;
};
}
let add_to_array = expandArray();
console.log( add_to_array(),add_to_array(),add_to_array() );
In your original code, you're only getting the return value of expandArray(), which is the function you're trying to use as a closure. In order to get the closure's return value, try this out:
function expandArray() {
const myArray = [1, 1, 1];
return function () {
myArray.forEach( function (num, index, myArray) {
myArray[index] = num + 1;
});
return myArray;
};
}
console.log(expandArray()());
The second set of parentheses after the call to expandArray() will invoke the closure and return the values you're seeking.
Old post, but I still like to contribute. I came up with this solution, as I think you want add something to the array instead of incrementing the numbers.
function expandArray() {
let myArray = [1, 1, 1];
return function() {
myArray.push(1)
return myArray
}
}
const array = expandArray();
const result = array();
console.log(result)
3years after this question was posted this lines of code works fine for me
function expandArray() {
let myArray = [1, 1, 1];
return function() {
myArray.push(1);
return myArray;
};
}
let newArray = expandArray();
console.log(newArray());
Note this is my first contribution on stack overflow.
I have a function that takes in an array of objects and a string, which represents a property. The function should return an array containing that property from each object.
Here is my sample code:
function pluck(array, property) {
var newArr = [];
array.map(function(paints){
return newArr.push(paints[property]);
});
return newArr;
}
This returns a new array and it works. But when the function is taking in an array of objects as one of the arguments...what gets passed to the anonymous iterator function in the map method? The value of the key?
How would it iterate over an array of objects using the map method?
The comments on your question explain what is happening in your code.
When you call map on an array, the mapping function is provided with 3 arguments, which are used always, sometimes and rarely in that order.
const result = items.map(function(element, index, items) {
// do the mapping
});
The function is called for each element of the original array items in turn, and the result of the function placed in the same index position of the result array.
The function arguments are:
element - this is the current element from the array
index - the current index
items - the original array on which map was called
Your pluck function could be written as:
function pluck(arr, prop) {
return arr.map(item => item[prop]);
}
Hello I am new this is my first question. I am completing the JavaScript Primer for Bloc, and am stuck on a simple checkpoint.
I am trying to Create a function named arrayLengthPlusOne. This function should: take one argument, an array return a number that is one greater than the number of elements in the array.. For example: arrayLengthPlusOne([0,0,1,0,2,1]); // returns 7
code i tried:
var arrayLengthPlusOne = function () { return arrayLengthPlusOne.length + 1; };
I am getting an error message telling me it isnt' passing tests. Maybe i'm not grasping the array/function relationship. I understand that an array is an Object not a Data Type. How do i make my function take one argument, that IS an array ?
Only you need to add an argument in your function declaration.
var arrayLengthPlusOne = function(data) { // data is an argument in the function. It's an array.
return data.length + 1;
};
// Calling the function.
var arrayData = [0, 1, 3, 4]; // Declare an array variable with four elements.
alert(arrayLengthPlusOne(arrayData)); // Show an alert with the result. Returns 4 + 1 elements.
The problem is your variabel name "arrayLengthPlusOne" in the function.
You should do something like:
var arrayLengthPlusOne = function (yourArray) { return yourArray.length + 1; }
and the call the function
myArray = [1 ,2 ,3 ,4 ]
arrayLengthPlusOne(myArray)
you need to pass the array as a parameter
var arrayLengthPlusOne = function(array) {
return array.length + 1;
}
Inside the function you can check whether the parameter passed is an array or not. If the parameter is an array it returns the length added by 1. If it's not an array, it returns undefined. However you can change the return type based on your requirement
var arrayLengthPlusOne = function (array1) {
if (array1 instanceof Array) {
return array1.length + 1;
}
};
You are missing to pass the arguments to the function.
Try this one:
alert(arrayLengthPlusOne([1,2,3,4,5,6]));
var arrayLengthPlusOne = function (myArray) {
return myArray.length + 1;
};
I am having problems understanding the concept of Array.map. I did go to Mozilla and Tutorials Point, but they provided very limited info regarding this.
This is how I am using Array.map. It is a little complex (a bit of d3.js involved; just ignore it)
var mapCell = function (row) {
return columns.map(function(column) {
return { column : column, value : getColumnCell(row, column) }
})
}
//getColumnCell is a function defined in my code
//columns is array defined at the top of my code
I do not understand exactly what this code is doing. I know its returning a new array and stuff but this part is a little tricky!
If you want to go through my code: http://jsfiddle.net/ddfsb/2/
I am using console to actually understand what's happening inside the code. Looking at the answers provided, I have clearly understood the concept of array.map. Now the only part remaining is parameters rows and columns, but there is a difference between row and rows, and column and columns in the fiddle provided
var rows//completely ok
var columns//completely ok
funcion(row)//here,source of row is unknown.getColumncell function utilizes this parameter further making it more critical
function(column)//source of column is unknown..getColumncell function utilizes this parameter further making it more critical
Let's rewrite it a bit, and start working from inside out.
var mapCell = function (row) {
return columns.map(
function(column) {
return {
column : column,
value : getColumnCell(row, column)
}
}
)
}
The function(column) part is essentially a function that takes a column as a parameter, and returns a new object with two properties:
column, that is the original value of the parameter, and
value, that is the result of calling the getColumnCell function on the row (external variable) and column (parameter)
The columns.map() part calls the Array.map function, that takes an array and a function, and runs the function for every last item of it, and returns the results. i.e. if the input is the array [1, 2, 3, 4, 5] and the function is something like isEven, the result will be the array [false, true, false, true, false]. In your case, the input are the columns, and the output is a list of objects, each of which has a column and a value properties.
Lastly, the var mapCell = function (row) part declares that the variable mapCell will contain a function of one variable called row - and this is the same row that is used in the inner function.
In a single sentence, this line of code, declares a function that when run, will take a row and return values for all columns for that row.
map loops through your original array and calls the method for each value in the array. It collects the results of your function to create a new array with the results. You are "mapping" the array of values into a new array of mapped values. Your code is equivalent to:
var mapCell = function (row) {
var result = [];
for (var i = 0; i < columns.length; ++i) {
var mappedValue = {
column: columns[i],
value : getColumnCell(row, columns[i])
};
result.push(mappedValue);
}
return result;
};
Understanding the map function is only part of the solution here, there is also the function mapCell. It takes one parameter row and it returns something like:
[ {
"column": "parties",
"value": [cell value]
}, {
"column": "star-speak",
"value": [cell value]
} ]
Where the cell value depends on the row and the column (parties, stars-speak etc.)
A map function applies a transformation to a value, and returns that transformed value.
A simple example:
function square(x) { return x * x; }
[ 2, 3, 4 ].map(square); // gives: [ 4, 9, 16 ]
Similarly:
[ "parties", "starspeak" ].map(function (column) {
return {
column: column,
value: findTheValue(column)
}
});
Now since that map is nested with a function that gets a row parameter. You can use it in the map function, to get:
function (row) {
return [ "parties", "starspeak" ].map(function (column) {
return {
column: column,
value: findTheValue(row, column)
}
});
}
And this gets pretty close to your code.
Map function goes through each element of an array in ascending order and invokes function f on all of them.
It returns new array which is being computed after function is invoked on it.
Syntax:
array.map(f)
Example:
<!doctype html>
<html>
<head>
<script>
var arr = [4,5,6];
document.write(arr.map(function(x){return x*2;}));
</script>
</head>
</html>
Answer: 8,10,12
Summary
Array.map is a function which is located on Array.prototype.map. The function does the following:
Creates a new array with the same amount of entries/elements.
Executes a callback function, this function receives and current array element as an argument and returns the entry for the new array.
Returns the newly created array.
Example:
Basic usage:
const array = [1, 2, 3, 4];
// receive each element of array then multiply it times two
// map returns a new array
const map = array.map(x => x * 2);
console.log(map);
The callback function also exposes an index and the original array:
const array = [1, 2, 3, 4];
// the callback function can also receive the index and the
// original array on which map was called upon
const map = array.map((x, index, array) => {
console.log(index);
console.log(array);
return x + index;
});
console.log(map);
Probably most people coming here (like me) just want a basic array.map usage example:
myArray = [1,2,3]
mappedArray = [];
mappedArray = myArray.map(function(currentValue){
return currentValue *= 2;
})
//myArray is still [1,2,3]
//mappedArray is now [2,4,6]
This is it at it's most basic. For additional parameers, check out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
IF you have an array of elements and you have to perform the same operation on the
each element of the array that time you can use the javascript map function for array
it helps to iterate throw the array then we can perform the operation of each element and
return it.
let NumberArray = [1,2,3,4,5,6,7,8];
let UpdatedArray = NumberArray.map( (Num , index )=>{
return Num*10;
})
console.log(UpdatedArray);
//UpdatedArray ==> [10, 20, 30, 40, 50, 60, 70, 80]
Javascript map() Syntax
arrayObj.map(callback[,context]);
arrayObj is a original array on which map() is invoked.
The map() takes 2 named arguments, First is a callback function and the second is a context object. callback function gets triggered on every element of an array.
In addition, callback function takes 3 arguments:
function callback(currentElement,index,array){
}
currentElement – This is a current elements of array which is passed to callback function
index – Index of the current element
array – complete array on which map() is applied
Out of these 3 elements, currentElement parameter is mandatory while the rest 2 parameters are optional.
However, map() does not change the original array, it creates a new array element which is generated by callback function.
You can read more on JavaScript map function
Array map() method returns a new array.
It does not change the original array.
let array = arr.map((c, i, arr) => { //return element to new array });
here,
array is the new array that is returned.
arr is the original array on which the map method is called.
c is the current value that is being processed.
i is the index of current value.
For example:-
const originalArr = [4, 3, 2]; let newArr = originalArr.map((val) => val + val);
result:-
newArr: [8, 6, 4]
originalArr: [4, 3, 2]
in simple words you can perform operations on array using map
Examples
1.Array
let arr = ["sam","tom"]
console.log("Before map :",arr)
arr.map((d,i)=>{
arr[i] = d+"yy"
})
console.log("After map :",arr)
Examples
2.Array Of Objects
// console.log(Date.now());
let arr = [
{name:"sam",roll_no:10},
{name:"tom",roll_no:12}
]
console.log("Before map :",arr)
arr.map(d=>{
if(d.name == "sam")
{
d.name = "sammy",
d.roll_no=100
}
})
console.log("After map :",arr)
I would like to filter an array of items by using the map() function. Here is a code snippet:
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
The problem is that filtered out items still uses space in the array and I would like to completely wipe them out.
Any idea?
EDIT: Thanks, I forgot about filter(), what I wanted is actually a filter() then a map().
EDIT2: Thanks for pointing that map() and filter() are not implemented in all browsers, although my specific code was not intended to run in a browser.
You should use the filter method rather than map unless you want to mutate the items in the array, in addition to filtering.
eg.
var filteredItems = items.filter(function(item)
{
return ...some condition...;
});
[Edit: Of course you could always do sourceArray.filter(...).map(...) to both filter and mutate]
Inspired by writing this answer, I ended up later expanding and writing a blog post going over this in careful detail. I recommend checking that out if you want to develop a deeper understanding of how to think about this problem--I try to explain it piece by piece, and also give a JSperf comparison at the end, going over speed considerations.
That said, **The tl;dr is this:
To accomplish what you're asking for (filtering and mapping within one function call), you would use Array.reduce()**.
However, the more readable and (less importantly) usually significantly faster2 approach is to just use filter and map chained together:
[1,2,3].filter(num => num > 2).map(num => num * 2)
What follows is a description of how Array.reduce() works, and how it can be used to accomplish filter and map in one iteration. Again, if this is too condensed, I highly recommend seeing the blog post linked above, which is a much more friendly intro with clear examples and progression.
You give reduce an argument that is a (usually anonymous) function.
That anonymous function takes two parameters--one (like the anonymous functions passed in to map/filter/forEach) is the iteratee to be operated on. There is another argument for the anonymous function passed to reduce, however, that those functions do not accept, and that is the value that will be passed along between function calls, often referred to as the memo.
Note that while Array.filter() takes only one argument (a function), Array.reduce() also takes an important (though optional) second argument: an initial value for 'memo' that will be passed into that anonymous function as its first argument, and subsequently can be mutated and passed along between function calls. (If it is not supplied, then 'memo' in the first anonymous function call will by default be the first iteratee, and the 'iteratee' argument will actually be the second value in the array)
In our case, we'll pass in an empty array to start, and then choose whether to inject our iteratee into our array or not based on our function--this is the filtering process.
Finally, we'll return our 'array in progress' on each anonymous function call, and reduce will take that return value and pass it as an argument (called memo) to its next function call.
This allows filter and map to happen in one iteration, cutting down our number of required iterations in half--just doing twice as much work each iteration, though, so nothing is really saved other than function calls, which are not so expensive in javascript.
For a more complete explanation, refer to MDN docs (or to my post referenced at the beginning of this answer).
Basic example of a Reduce call:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
more succinct version:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Notice that the first iteratee was not greater than one, and so was filtered. Also note the initialMemo, named just to make its existence clear and draw attention to it. Once again, it is passed in as 'memo' to the first anonymous function call, and then the returned value of the anonymous function is passed in as the 'memo' argument to the next function.
Another example of the classic use case for memo would be returning the smallest or largest number in an array. Example:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.
An example of how to write your own reduce function (this often helps understanding functions like these, I find):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
// or, more technically complete, give access to base array
// and index to the reducer as well:
// memo = reduceFunc(memo, this[i], i, this);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
The real implementation allows access to things like the index, for example, but I hope this helps you get an uncomplicated feel for the gist of it.
That's not what map does. You really want Array.filter. Or if you really want to remove the elements from the original list, you're going to need to do it imperatively with a for loop.
Array Filter method
var arr = [1, 2, 3]
// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })
// ES2015 syntax
arr = arr.filter(item => item != 3)
console.log( arr )
You must note however that the Array.filter is not supported in all browser so, you must to prototyped:
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
{
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
And doing so, you can prototype any method you may need.
TLDR: Use map (returning undefined when needed) and then filter.
First, I believe that a map + filter function is useful since you don't want to repeat a computation in both. Swift originally called this function flatMap but then renamed it to compactMap.
For example, if we don't have a compactMap function, we might end up with computation defined twice:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.filter(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
return isIncluded;
})
.map(x => {
let computation = x / 2 + 1;
return `${x} is included because ${computation} is even`
})
// Output: [2 is included because 2 is even, 6 is included because 4 is even]
Thus compactMap would be useful to reduce duplicate code.
A really simple way to do something similar to compactMap is to:
Map on real values or undefined.
Filter out all the undefined values.
This of course relies on you never needing to return undefined values as part of your original map function.
Example:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.map(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
if (isIncluded) {
return `${x} is included because ${computation} is even`
} else {
return undefined
}
})
.filter(x => typeof x !== "undefined")
I just wrote array intersection that correctly handles also duplicates
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
// array intersection that correctly handles also duplicates
const intersection = (a1, a2) => {
const cnt = new Map();
a2.map(el => cnt[el] = el in cnt ? cnt[el] + 1 : 1);
return a1.filter(el => el in cnt && 0 < cnt[el]--);
};
const l = console.log;
l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ]
l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ]
First you can use map and with chaining you can use filter
state.map(item => {
if(item.id === action.item.id){
return {
id : action.item.id,
name : item.name,
price: item.price,
quantity : item.quantity-1
}
}else{
return item;
}
}).filter(item => {
if(item.quantity <= 0){
return false;
}else{
return true;
}
});
following statement cleans object using map function.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);