I need to take the first and last element in a given array and return an object with the first element as the key and the last as the value.
Here's my code:
function transformFirstAndLast(array) {
array=[];
var object={};
object[key]=value;// make object
var key=array[0];
var value=array[array.length-1];
return object;} // return object
for whatever reason, it's returning undefined inside the object. I swear it was working this morning...
I've always tried:
function transformFirstAndLast(array) {
array=[];
var object = {};
object[array[0]] = array[array.length-1];}
but that's returning undefined without so much as an object being built.
This is straightforward using computed property names:
function transformFirstAndLast(array) {
return {[array[0]]: array[array.length - 1]};
}
Or if you prefer:
const transformFirstAndLast = ([head, ...tail]) => ({[head]: tail.pop()});
You're redeclaring array at the beggining of your function.
Besides, in my opinion, using "array" and "object" as variable names is a bad idea. Just a typo could get you messing up with Array and Object. And that might have side effects.
Here's a functional fiddle for your use case using array.shift() and array.pop() methods.
var myArray=['one','two','three','four'];
function buildObject(arr) {
var myObject={},
key=arr.shift(),
val=arr.pop();
myObject[key]=val;
return myObject;
}
console.log(buildObject(myArray));
Related
I was working with an array in JavaScript and was wondering why changes I made to an array were correctly saving to localStorage, but weren't being reflected in the array past the function call. The code was the following:
function removeFromList(array, arrayName, key) {
array = array.filter(function(element) { return element.key !== key; });
localStorage.setItem(arrayName, JSON.stringify(array));
}
I did some googling and, through some old posts, discovered that the array was being passed by value to the function, that is, the array variable, which pointed to an array object, was being passed by value, and changing that copy did not affect the original variable that was pointing to my array object.
I came up with the following code as a workaround:
function removeFromList(array, arrayName, key) {
arrayTemp = array.filter(function(element) { return element.key !== key; });
for(var i = 0; i < array.length; i++) {
if (!arrayTemp.some(item => item.key === array[i].key)) {
array.splice(i, 1);
}
}
localStorage.setItem(arrayName, JSON.stringify(array));
}
This solved my problem, and the new contents of the array was displayed in both localStorage and the array object that was pointed to by the original variable. However, I've been wondering if there is some new way introduced into JavaScript recently or an older method I did not find that would do a better job of achieving the desired result.
I did some googling and, through some old posts, discovered that the array was being passed by value to the function, that is, the array variable, which pointed to an array object, was being passed by value, and changing that copy did not affect the original variable that was pointing to my array object.
Exactly right.
Is there a way to change the original reference to an object in a function call
No, JavaScript is still a purely pass-by-value language. While I suppose it's possible for that to change at some point, it hasn't as of this writing (and it seems really unlikely to me it ever will). If you do example(x) when x contains 42 (or an array reference), there still isn't any way for example to reach out and change the value of x (to 43, or to refer to a different array). If x refers to a mutable object (like an array), example can modify that object, but it can't make x refer to a whole new object.
Your workaround works by modifying the existing array. FWIW, in general it would be preferred to return the new array instead, so the caller has the option of either keeping the original or using the new one. E.g.:
function removeFromList(array, arrayName, key) {
array = array.filter(function(element) { return element.key !== key; });
localStorage.setItem(arrayName, JSON.stringify(array));
return array;
}
And then when using it:
variableContainingArray = removeFromList(variableContainingArray, "nameInLocalStorage", 42);
But if you want to update in place, you don't need a temporary array:
function removeFromList(array, arrayName, key) {
// Looping backward we don't have to worry about the indexes when we remove an entry
for (let i = array.length - 1; i >= 0; --i) {
if (array[i].key === key) {
array.splice(i, 1);
}
}
localStorage.setItem(arrayName, JSON.stringify(array));
}
Instead of using a for-loop to remove the values from the argument array you can also empty it out using splice and add the filtered values:
function removeFromList(array, arrayName, key) {
var filtered = array.filter(function(element) { return element.key !== key; });
array.splice(0, array.length, ...filtered);
localStorage.setItem(arrayName, JSON.stringify(array));
}
I suggest changing var to const and function(element) { return element.key !== key; } to element => element.key !== key if those features are available within your runtime environment.
I have an Array of objects A
And I have 2 different drawing functions which change A completely in their own ways.
I would like to keep A unchanged. Is there best practices how to do it? My current solution is somehow feels unnatural:
var A;//Should stay the same always
drawGraphX(A){
//Modifying A here to draw but I would like the original A to stay the same
B=JSON.parse(JSON.stringify(A));
//So I do it with B
}
drawGraphY(A){
//Modifying A here to draw
B=JSON.parse(JSON.stringify(A));
//So I do it with B
}
I suspect the real answer here is that you shouldn't be changing the data inside your function at all!
Lets imagine that A is an array of x/y points to be used for a chart
var A = [{x:1,y:1},{x:2,y:2},{x:3,y:3}];
And your function just wants the x - are you doing this:
function drawGraphX(A){
for(var i=0;i<A.length;i++)
A[i] = A[i].x;
// now draw the graph
}
In the above example, yes,, you will be changing the source of A as you've just passed a reference in to the function and updated the elements of that referenced array. This is bad practice, what you should be doing is this:
function drawGraphX(A){
var data = A.map(function(e){
return e.x;
});
// data is an array of just the x values
}
Try putting drawGraphX(A.slice()) slice returns copy of array if shallow copy is fine for you and it is just about array itself, however remember that you are in fact not cloning objects so
var A = [{test:'foo', test2:'bar'}, {test:'foo1', test2:'bar1'}];
var B = A.slice();
A[0].test = 'foobar';
console.log(B[0].test);
will return you "foobar"
so it is fine if you mutate array itself but not elements (note that the same comment goes to Array.from(A) solution.
What I would do is use the Array.from() method, to pass a new array into your function. So, when you call drawGraphX(A), instead call drawGraphX(Array.from(A)). This will create a new Array of the same data you had in 'A'. Easy Peasy.
var b = Array.from(A);
drawGraphX(b);
or
drawGraphX(Array.from(A));
Edit: As netRat and Jonasw pointed out. This will make a new array, but it keeps references to the individual objects. Meaning that while mutating the Array will not change the source array, changing any of the objects shared by the two arrays will change the source material. I.E.:
var a = [1,2];
var b = Array.from(a);
b[0] = b[0]++;
console.log(a); // will result [2,2];
while
b.push[3];
console.log(a); // will result [1,2]
console.log(b); // will result [1,2,3];
Proof of concept: https://jsfiddle.net/5hLjajc0/1/
The more elegant solution would be sth like a switch, that if an objs is undefined, take a parents one:
function switch(obj,prot){
return function(keys,val){
keys= keys.split(".");
var el=obj;
var par;
for(key of keys){
par=el
el=el[key];
}
if(el==undefined){
var el=prot;
var par;
for(key of keys){
par=el
el=el[key];
}
}
if(value){
par[keys[keys.length]]=value;
}
return el;
};}
Use like this:
prot=[0,1,3];//unchangeable
obj=[,5,];
callfunc(switch(obj,prot));
function callfunc(el){
//read
el("0");//0
el("1");//5
el("2");//3
//write
el("0", 12);//do not override prot
//also with multidim stuff:
el("0.a");
}
Its mainly an improved version of prototypes:
var obj={
0:function(){
alert("original prototype");
},
1:5
}
callfunc(Object.create(obj));//...
callfunc(Object.create(obj));//...
This will allow you to access the prototypes props, wich cant be overriden that easily:
function callfunc(arg){
arg[0]();//works as expected
arg[0]=function(){
alert("hi");
}
arg[0]();//hi
}
This doesnt override the prototype, it extends the arg...
To override you can still do
arg.prototype[0]=function(){
alert("hi prototype");
};
I want to access (get/set) a nestedJS object with a variable.
For example, static it would look like that:
$obj.children.12.children.32.Name; // Returns "Foo"
Now I have an "Route" array (or whatever is easy too handle):
["children",12,"children",32,"Name"]
And want to get the value of the object.
Like I read here on Stackover, there is an very easy way to do it (Solution 2).
But, now I want to change the value for the passed key/route. Is there any way to do that?
Thank you very much!
Edit:
I can use jQuery/Angluar-Features, if it helps me.
Borrowing code from the accepted answer on the post you've linked to, we can trivially make a getter:
function getFromPath(obj, pathArray) {
var res = obj;
for (var i=0; i<pathArray.length; i++) { res = res[pathArray[i]]; }
return res;
}
We call this with getFromPath($obj, ["children",12,"children",32,"Name"]);.
Since you want to transform this getter function into a setter, you want to set a property on the second-to-last object. We can do this by stopping the loop one iteration early and then performing set with the final property name on the object:
function setToPath(obj, pathArray, valueToSet) {
var res = obj;
// note the `length - 1` here: we don't go to the end of the path
for (var i=0; i<pathArray.length - 1; i++) { res = res[pathArray[i]]; }
// res is now the second-to-last object in the path,
// and we'll set the final value as a property on the object
var finalKey = pathArray[pathArray.length-1];
res[finalKey] = valueToSet;
}
We call this with setToPath($obj, ["children",12,"children",32,"Name"], "Dana");.
Alternatively, if you wanted to do this with just a getter, you could shorten your path by one item and perform the set on the result from the getter:
var secondToLast = getFromPath($obj, ["children",12,"children",32]);
secondToLast["Name"] = "Dana";
I'm trying to create an array that maps strings to variables. It seems that the array stores the current value of the variable instead of storing a reference to the variable.
var name = "foo";
var array = [];
array["reference"] = name;
name = "bar";
// Still returns "foo" when I'd like it to return "bar."
array["reference"];
Is there a way to make the array refer to the variable?
Put an object into the array instead:
var name = {};
name.title = "foo";
var array = [];
array["reference"] = name;
name.title = "bar";
// now returns "bar"
array["reference"].title;
You can't.
JavaScript always pass by value. And everything is an object; var stores the pointer, hence it's pass by pointer's value.
If your name = "bar" is supposed to be inside a function, you'll need to pass in the whole array instead. The function will then need to change it using array["reference"] = "bar".
Btw, [] is an array literal. {} is an object literal.
That array["reference"] works because an Array is also an object, but array is meant to be accessed by 0-based index. You probably want to use {} instead.
And foo["bar"] is equivalent to foo.bar. The longer syntax is more useful if the key can be dynamic, e.g., foo[bar], not at all the same with foo.bar (or if you want to use a minimizer like Google's Closure Compiler).
Try pushing an object to the array instead and altering values within it.
var ar = [];
var obj = {value: 10};
ar[ar.length] = obj;
obj.value = 12;
alert(ar[0].value);
My solution to saving a reference is to pass a function instead:
If the variable you want to reference is called myTarget, then use:
myRef = function (newVal) {
if (newVal != undefined) myTarget = newVal;
return myTarget;
}
To read the value, use myRef();. To set the value, use myRef(<the value you want to set>);.
Helpfully, you can also assign this to an array element as well:
var myArray = [myRef];
Then use myArray[0]() to read and myArray[0](<new value>) to write.
Disclaimer: I've only tested this with a numerical target as that is my use case.
My solution to saving a reference is to pass a function instead:
If the variable you want to reference is called 'myTarget', then use:
myRef = function (newVal) {
if (newVal != undefined)
myTarget = newVal;
return myTarget;
}
To read the value, use myRef();. To set the value, use myRef(value_to_set);.
Helpfully, you can also assign this to an array element as well:
var myArray = [myRef];
Then use myArray0 to read and myArray[0](value_to_set) to write.
Disclaimer: I've only tested this with a numerical target as that is my use case.
I have this on a javascript var: (it's a http returned data, and I don't know if it's an array or string - (how can we see that?) - Update: using typeof returned "string", so it's a string.
[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}]
How can we pass/transform that, into something like this:
["gggg.fa","rarar.fa"]
?
Thanks a lot,
MEM
You can figure out if is a string or an already parsed object by checking the type of your variable, e.g.:
ajax('url', function (response) {
alert(typeof response);
});
You will now figure out if it's a "string" or an Array "object".
If it's a string, you can use the JSON.parse method as #alcuadrado suggest, otherwise you can simply use the array.
Several answers suggest the use of the for-in statement to iterate over the array elements, I would discourage you to use it for that.
The for-in statement should be used to enumerate over object properties, to iterate over Arrays or Array-like objects, use a sequential loop as #Ken Redler suggests.
You should really avoid for-in for this purpose because:
The order of enumeration is not guaranteed, properties may not be visited in the numeric order.
Enumerates also inherited properties.
You can also use the Array.prototype.map method to meet your requirements:
var response = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
var array = response.map(function (item) { return item.nomeDominio; });
// ["gggg.fa", "rarar.fa"]
This question is strongly related with this one.
I would suggest reading my answer there, as it would really help; and with a little variation, it would just work:
var responseString = '[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}]',
responseObject = JSON.parse(responseString),
nombresDeDominio = [];
for(var i in responseObject) {
nombresDeDominio.push(responseObject[i].nomeDominio)
}
Suerte!
Assuming your data always looks like that, you can do something like this:
var foo = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
var newarr = [];
for ( var i=0,j=foo.length;i<j;i++ ) {
newarr.push( foo[i]['nomeDominio'] );
}
Here's a working fiddle.
function transform(array, f) {
var ret = [];
$.each(array, function(index) {
var v = f.call(this, index);
if(v) {
ret.push(v);
}
});
return ret;
}
var result = transform(
[{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}],
function() { return this.nomeDominio; }
);
alert(result.toString());
it's a http returned data, and I don't
know if it's an array or string
It's JSON, and you can use it directly in JavaScript.
If you transform it into your array, you will lose the association key / value ; are you sure it's what you want ?
Okay, firstly to get the type of a "thing", use the "typeof" operator (note that the type of an array is an object, not 'array'!):
var a = "string";
var b = 1;
var c = new Array();
alert(typeof(a)); // string
alert(typeof(b)); // number
alert(typeof(c)); // object
To get at the values in the associative array (assuming it is one), you can just loop through it, like so:
var d = [{"nomeDominio":"gggg.fa"},{"nomeDominio":"rarar.fa"}];
d["bob"] = "alice";
d["gary"] = "stephen";
for(var key in d) {
alert(d[key]);
}