Creation of array and append value inside closure in javascript - javascript

I am using this code -
var gArray = (function (value) {
var array = [];
return function () {
array.push(value);
return array;
}
}());
gArray(1);
gArray(2);
gArray(3);
I am expecting to this code snippet [1, 2, 3]
but i am getting [undefined, undefined, undefined]

The gArray function doesn't have an argument, the immediately invoked function does, but you pass nothing when you call it:
var gArray = (function (value) { //<- Argument of IIFE
var array = [];
return function () { //<- No arguments for gArray
array.push(value);
return array;
}
}()); //<- No arguments passed to IIFE
What you need is to define an argument for the returned function, which is gArray:
var gArray = (function () {
var array = [];
return function (value) {
array.push(value);
return array;
}
}());

Your outer function is a self-invoked function. That means that it will be executed as soon as () is reached. In this particular case, it's returning:
function () {
array.push(value);
return array;
}
which is taking value as undefined. To solve this issue, you can rewrite your code as follows:
var gArray = (function () {
var array = [];
return function (value) {
array.push(value);
return array;
}
}());

Change var array = []; to this.array = [];.
It needs to have the right scope.

var myArray = [];
function addToArray(value){
myArray.push(value);
console.log(value + " was added to " + myArray);
}
addToArray(1);
addToArray(2);
addToArray(3);
If you give back myArray console will say [1, 2, 3]

This is the best way to do it:
const array = [];
const pushArray = function(value, array) {
array.push(value);
return array;
};
pushArray(1, array);
pushArray(2, array);
pushArray(3, array);

Related

Javascript return reference to array index with primitive value

I want to return a reference to to the content of an array at index x in order to be able to change the content of the array using the returned index afterwards.
Here is an example of what I mean:
let testArr = [1,2,3]
const someFunct = arr => {
...
return {reference to arr[0], aka 1}
}
someFunct(testArr) = 0;
//should log [0,2,3]
console.log(testArr);
someFunct(testArr) should behave like arr[0] in this case.
The content of the array could be anything.
i dont think the exact implementation you are trying to achieve is possible in JavaScript.
https://medium.com/#naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600
something similar:
const testArr = [1,2,3]
const changeArray = (array, index, newValue) => {
array[index] = newValue
return array
}
changeArray(testArr, 0, 0) // evaluates to [0,2,3]
I want to return a reference …
This is not possible, JavaScript doesn't have references as returnable values. The someFunct(testArr) = 0; syntax you are imagining is invalid.
Instead, take the new value as an argument:
function someFunct(arr, val) {
…
arr[0] = val;
}
someFunct(testArr, 0);
or return an object with a method that does the assigning:
function someFunct(arr) {
…
return {
set(v) {
arr[0] = v;
}
};
}
someFunct(testArr) = 0;
Try this:
function arrayWrapper(arr, index, newVal) {
let returnVal;
if(newVal) {
arr[index] = newVal;
returnVal = arr;
} else {
const obj = { ...arr };
returnVal = obj[index];
}
return returnVal;
};
console.log(arrayWrapper([1,2,3,4,5,6,7,8,9], 5)); /// to get value at index
console.log(arrayWrapper([1,2,3,4,5,6,7,8,9], 5, 'text')); // to set value on index
You can use the above method to get as well as set elements to your array.
The nature of operation depends on the third parameter.
Hope this helps :)

JavaScript changing object list to array. return undefined

function listToArray(list){
var newArray = [];
repeat();
function repeat(){
newArray.push(list.value);
if(list.rest == null){
return obj = newArray; // I don't know why It returns undefined here
}
else {
list = list.rest;
repeat();
}
}
}
// and this will return an array
function reTurn(){
var listVar = [5, 4, 3, 2, 1];
return obj = listVar;
}
This function does change my obj when I look for it in console, but returns undefined.
Anyone can help me? please
just return newArray - you can't return an assignment like that.
You're returning from the inner function, not the outer one. Add a return newArray to the bottom of listToArray. Change the return statement in repeat to just return;.
function listToArray(list){
var newArray = [];
repeat();
function repeat(){
newArray.push(list.value);
if (list.rest) {
list = list.rest;
repeat();
}
}
return newArray;
}
There's nothing really wrong with the recursive approach, but it's not necessary. You could just as easily write
function listToArray(list){
var newArray = [];
while (list) {
newArray.push(list.value);
list = list.rest;
}
return newArray;
}
However, even this code has the drawback that it is mixing the traversal of the list with the building of the array of values. It would be better to separate those:
function traverseList(list, fn) {
while (list) {
fn(list.value);
list = list.rest);
}
}
Now you can write listToArray as
function listToArray(list) {
var newArray = [];
traverseList(list, value => newArray.push(value));
return newArray;
}
I might also write this as a generator:
function* forList(list) {
while (list) {
yield list.value;
list = list.rest;
}
}
Now I don't even need a separate function to create the array of values, because I can just write
[...forList(list)]

Function trims values after being passed in another function

I would like have renderData() display the values from max. When I console.log(max) in calculateData() it displays all three maximum values from three JSON objects. However, when I return max in renderData() it only shows the first value. Why is this, and what can I do to make it display all three values instead of just one? Note: data is the json list of objects being passed. Thank you!
function calculateData(data) {
for (i in data) {
var arr = [];
var max;
var obj = data[i].tones;
obj.map(function(item) {
var data = item.score;
arr.push(data);
})
max = arr.reduce(function(a, b) {
return Math.max(a, b);
})
//Returns an array containing dominant [emotion_tone, language_tone, social_tone]
return renderData(max);
}
}
function renderData(max) {
console.log(max);
};
Maybe this is what you are intending? It will iterate through the entire data object calculating a max for each iteration, collect them in an array, and then finally call the renderData func with that array.
function calculateData(data) {
var maxes = [];
for (i in data) {
var arr = [];
var max;
var obj = data[i].tones;
obj.map(function(item) {
var data = item.score;
arr.push(data);
})
maxes.push(arr.reduce(function(a, b) {
return Math.max(a, b);
}));
}
return renderData(maxes);
}
function renderData(max) {
console.log(max);
};
I created a second array, finalArray and pushed each max into it:
function calculateData(data) {
var finalArr = [];
for (i in data) {
var arr = [];
var max;
data[i].tones.map(function(item) {
arr.push(item.score);
})
var max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
finalArr.push(max);
//Returns an array containing dominant [emotion_tone, language_tone, social_tone]
// return renderData(max);
}
renderData(finalArr);
}
function renderData(finalArr) {
console.log(finalArr);
};
Thanks for your help guys!
Your error arises because the return statement inside the loop aborts the whole function, and therefore also the loop. But this whole function can be simplified/shortened quite a bit:
And as mentioned in the comments, don't define functions inside a loop (unless it is inevitable), define the before the loop. I did this in by defining the functions getScore and max in my code.
//ES6
function calculateData(data) {
var getScore = item => item.score,
max = (a,b) => Math.max(a,b),
maxima = Object.values(data)
.map(value => value.tones.map(getScore).reduce(max));
return renderData(maxima);
}
//Or maybe you're more comfortable without Arrow functions
function calculateData(data) {
function getScore(item){ return item.score }
function max(a,b){ return Math.max(a,b) }
var maxima = Object.values(data).map(function(value){
return value.tones.map(getScore).reduce(max)
});
return renderData(maxima);
}
The only difference to your code is that Object.values() returns only own values of the object, whereas for..in iterates over all values of the object, own and inherited.

Javascript: How to get key of function.apply()

I am trying to cache 'func.apply(this, func)' value so that it can be looked up later rather than running the function again. The problem is that I don't know how or what to use as the key.
Is there a way to assign an key of a function that can be looked up later?
Code example:
var m = function(func) {
var cached = {};
return function() {
var key = ''; // how do I get or create the key of func.apply(this, func)?
if (cached[key]) {
return cached[key];
}
cached[key] = func.apply(this, arguments);
return cached[key];
};
};
The m() function should return a function that, when called, will check if it has already computed the result for the given argument and return that value instead if possible.
What are you looking for is called Memoization
See: Implementing Memoization in JavaScript
Here are an example:
var myFunction = (function() {
'use strict';
var functionMemoized = function() {
// set the argumensts list as a json key
var cacheKey = JSON.stringify(Array.prototype.slice.call(arguments));
var result;
// checks whether the property was cached previously
// also: if (!(cacheKey in functionMemoized.cache))
if (!functionMemoized.cache.hasOwnProperty(cacheKey)) {
// your expensive computation goes here
// to reference the paramaters passed, use arguments[n]
// eg.: result = arguments[0] * arguments[1];
functionMemoized.cache[cacheKey] = result;
}
return functionMemoized.cache[cacheKey];
};
functionMemoized.cache = {};
return functionMemoized;
}());
Why do you need an object with an index. Just store the result/key.
var m = function(func) {
var result=null;
return function() {
if (result===null) {
result = func.apply(this, arguments);
}
return result;
}
};
But I am not sure that is what you want. If the function returns different values based on arguments, than you want to use a key based off the arguments.
var m = function(func) {
var results = {};
return function() {
var key = [].slice.call(arguments).join("-");
if (results[key]===undefined) {
results[key] = func.apply(this, arguments);
}
return results[key];
}
};
var multiply = function (a,b) {
return a * b;
}
var mult = m(multiply);
console.log(mult(2,5)); //runs calculation
console.log(mult(2,5)); //uses cache
If you send the value of the function as a string, you can use that as the index with one minor modification
var m = function(func, scope) {
return function() {
var cached = {};
var index = func; // how do I get or create the index of func.apply(this, func)?
scope = scope || this;
if (!cached[index]) {
func = scope[func]; //Get the reference to the function through the name
cached[index] = func.apply(this, func);
}
return cached[index];
};
};
This does depend on if the index exists in the this object reference. Otherwise you should use a different scope.

clear and undo clear the array

If I do have the following code then empty the arry:
var a1 = [1,2,3];
a1 = [];
//returns []
But I'm trying to make a function to clear and undo clear the array, it's not working as expected:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
}
function undoClearArray(a){
a = storeArray;
}
clearArray(foo);
foo; //still returns ['f','o','o']
//but expected result is: []
Here's the problem:
You assign an array to a variable foo.
Then you pass this object to your function which stores it in another variable a. Now you have one object that two variable are pointing at. In the function you then reassign a to a different object an empty array []. Now a points at the empty object and foo still points at the original object. You didn't change foo by reassigning a.
Here's a concise way to store you're array:
var storeArray = [];
function clearArray(a){
while (a.length>0){
storeArray.push(a.shift()) //now a is empty and storeArray has a copy
}
}
I tried something different. Maybe it's dirty, but the storage itself is on the object.
the fiddle
//define the object to hold the old data
Object.defineProperty(Array.prototype, "storage", {
enumerable: false,
configureable: true,
get: function () {
return bValue;
},
set: function (newValue) {
bValue = newValue;
}
});
//define the prototype function clear to clear the data
Object.defineProperty(Array.prototype, "clear", {
enumerable: false,
writable: false,
value: function () {
this.storage = this.slice(0); //copy the data to the storage
for (var p in this) {
if (this.hasOwnProperty(p)) {
delete this[p]; //delete the data
}
}
return this; //return the object if you want assign the return value
}
});
//define the prototype function restore to reload the data
Object.defineProperty(Array.prototype, "restore", {
enumerable: false,
writable: false,
value: function () {
var a = this.storage.slice(0); //copy the storage to a local var
for (var p in this.storage) {
if (this.storage.hasOwnProperty(p)) {
this[p] = a[p]; //assign the pointer to the new variable
delete this.storage[p]; //delete the storage
}
}
return this;
}
});
var a = ['f','o','o'];
console.log(a); //--> displays ['f','o','o']
a.clear();
console.log(a); //--> displays []
a.restore();
console.log(a); //--> displays ['f','o','o']
You can use splice() method to delete all elements of an array likes below
function clearArray(a){
storeArray = a;
a.splice(0,a.length);
}
var a = [1,2,3,4];
var tempArr ;
clearArray = function() {
tempArr = a.slice(0);
a.length = 0;
}
undoArray = function() {
a = tempArr.slice(0);
}
Here is a small jsfiddle: http://jsfiddle.net/66s2N/
Here's working way of what you want to achieve:
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a.slice(0);
for (var i=0; i<a.length; i++)
delete a[i];
a.length = 0;
}
function undoClearArray(a){
for (var i=0; i<storeArray.length; i++)
a.push(storeArray[i]);
}
console.log(foo);
clearArray(foo);
console.log(foo); //now foo is []
undoClearArray(foo);
console.log(foo); // now foo is ['f','o','o']
http://jsfiddle.net/44EF5/1/
When you do:
var a1 = [1,2,3];
a1 = [];
it's as if you've written:
var a1 = [1,2,3];
var a1 = [];
You're overwriting variables.
Now, why your approach doesn't work - in JS there's no passing by reference. MarkM response explains what's happening within the function.
Now, why does the above work - while you've got two variables pointing towards the same array, nothing prevents you from modifying that array. As such storeArray = a.slice(0) will create a copy of the array. Then by using delete we're removing all values of the array, and then as length isn't enumerable (so using for (var i in a) wouldn't help) we reassign the length of the array. This has removed the values of original array, while creating a new array assigned to storeArray.
function clearArray(a){
storeArray = a.slice(0);
return a.length = 0;
}
or set foo.length = 0;
Just update your both function with below ones
function clearArray(a){
storeArray = a.slice(0);
a.length = 0;
}
function undoClearArray(a){
a = storeArray;
return a;
}
in undoClearAray() we are returning the variable which have new reference(in your clearArray(), Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays). so use it as foo=undoClearArray(foo); for old values.
try
var foo = ['f','o','o'];
var storeArray;
function clearArray(a){
storeArray = a;
a = [];
return a;
}
function undoClearArray(a){
a = storeArray;
}
foo = clearArray(foo);
foo; //returns []
You can use wrappers to do this quite nicely. First create a wrapper function with the additional methods defined, then create your array using that function instead of []. Here is an example (see JSFiddle):
var extendedArray = function() {
var arr = [];
arr.push.apply(arr, arguments);
arr.clearArray = function() {
this.oldValue = this.slice(0);
this.length = 0;
}
arr.undoArray = function() {
this.length = 0;
for (var i = 0; i < this.oldValue.length; i++) {
this.push(this.oldValue[i]);
}
}
return arr;
};
var a = extendedArray('f', 'o', 'o');
alert(a);
a.clearArray();
alert(a);
a.undoArray();
alert(a);

Categories

Resources