I feel puzzled when I rethink of these two functions:
The first one goes like this:
var test = [1,2,3];
var ele = test[0];
ele= 2;
alert(test[0]);
The result is 1. I think this is obvious. But when I meet this:
var test = [{id:1},{},{}];
var ele = test[0];
ele.id = 2;
alert(test[0].id);
The result turns to be 2
So could anyone tell me that how the javascript work when it happens like this in the object array?
In JavaScript, objects are assigned by reference, rather than copied in memory. So if you assign an existing object to a different variable, both will point to the same object in memory. Modifications to either will therefore be reflected in both.
var a = {id: 1, name: "bob"};
var b = a;
console.log(b.name); // bob
b.name = "bill";
console.log(a.name); // bill
So in your example, executing ele.id = 2; operates on the memory location holding the object at test[0]. The change to the id property of that object is reflected in both variables referencing it (test[0], ele)
Note that if you had assigned the entire array test to ele, modifying one of the array members would have been reflected in both test, ele since Arrays are objects in Javascript:
var test = [1,2,3];
// Assign array test to ele
var ele = test;
// Modify one member
ele[0] = 2;
alert(test[0]); // 2
Related
So here's the thing. I've declared the following variables to concat my object:
var newObj = obj[property];
var fullObj = newObj[id];
Then I'm matching the value of "fullObj" with the value of another obj named "Array". I do it like this:
fullObj = Array;
Then "fullObj" gets the new value, but the original object, which is something like: "obj.property.id" does not. Any ideas?
EDIT:
This is the function
function updateData(obj, Array, id, property) {
var newObj = obj[property];
var fullObj = newObj[id];
fullObj = Array;
}
The property that I'm sending back is "obj", with all its inner elements (obj.property.id).
As you can see, "fullObj" is the same thing as saying that last object construction. Imagine something like "object.id["0"]. So imagine the value of "Array" is "object.id["1"]. I'm giving "fullObj" that value by matching them both, but the original object won't get it.
Am I being clear enough?
The problem is that you are re-assigning the value for the fullObj variable. You can access the referenced object like that, but you can't change it.
Anyway, i don't see the point of doing that the way you are doing it. You can assign the value directly like this:
function updateData(obj, Array, id, property) {
obj[property][id] = Array;
}
You changed the reference of fullObj to some other reference (Array). The reference of newObj[id] remains the same.
Example
var a = [1];
var b = a;
b = [2];
console.log(a, b); // it logs [1] [2]
this works:
var f = function(a){
a.push(1);
};
var a = [];
f(a);
console.log(a);//[1];
But this:
var f = function(a){
a = a.concat([1]);
};
var a = [];
f(a);
console.log(a);//[];
Does not work. With work I mean that the changes made persist after the function call.
Now I realise that this most likely has something to do with the arguments being passed 'as reference by value', meaning that a change in reference (ie assigning a new object) does not persist after the function call.
So I wonder, is there a persistent version of concat? Or do I manualy have to push all elements from one array into the other?
Edit: All of you suggesting to return the newly created array: that's pretty much exactly what I don't want. If I wanted to do that I wouldn't have created this question. And I certainly would not have ended it specifically asking for a persistent version of concat.
concat returns a new array, it doesn't mutate the source array.
var f = function(a){
return a.concat([1]);
};
var a = f([]);
console.log(a);//[1];
If you do want to mutate the array, just use push.apply to pass array elements as individual arguments to the push function.
var f = function(a) {
a.push.apply(a, [1]);
};
var a = [];
f(a);
console.log(a); //1
That's because the function parameter, a, is not the same as the variable a declared in the outer scope. When you assign a new value to the parameter a, it has no effect on the outer variable.
a = a.concat([1]);
Instead, simply return the new array, and use the return value in the outer scope, like this:
var f = function(a){
return a.concat([1]);
};
var a = [];
a = f(a);
Or perhaps consider using push like this:
var f = function(a){
Array.prototype.push.apply(a, [1, 2, 3]);
};
This will push multiple values onto the source array, so it's pretty much equivalent to concat except that it modifies the original array.
I have:
var test;
var abc = [1,2,3];
test.active = [];
test.active.$selected = 123;
Is it possible to copy the array that contains [1,2,3] into the test.active array without making the test.active.$selected = 123 disappear?
When I try test.active = abc then the value $selected is lost.
You can use Array.prototype.push() coupled with apply() to copy the elements to the test.active array, while keeping any properties intact.
Note: you didn't define test as an object, so I've changed that.
Fiddle
var test = {}; // define as object
var abc = [1,2,3];
test.active = [];
test.active.$selected = 123;
// copy abc's elements to test.active, while keeping any of test.active's properties
test.active.push.apply(test.active, abc);
console.log(test.active.$selected); // 123
console.log(test.active[0]); // 1
console.log(test.active[1]); // 2
console.log(test.active[2]); // 3
Actually, yes, it's possible. But I'm not sure if you need it. In a simple way:
var test;
test.active = [1,2,3];
test.active.$selected = 123;
In that case you'll assign to test.active a new array. And as soon as everything is JavaScript is an object - you can add a new property to it. But from the common sense point of view - it's not a good practice to mix up 2 different data types (array and object). So in your case I would recommend to use separate properties for array and integer value:
var test;
test.active = [1,2,3];
test.$selected = 123;
Note: if you have a more complex array of, e.g. objects, etc - it's better to use any library for deep clone of it. But it depends on your exact problem.
I have a loop goes through an array of objects MyArrayOfObjects and then pushes the objects to a new array like this:
var NewArray = new Array();
for (i = 0; i < MyArrayOfObjects.length; i++) {
TempObject = null;
TempObject = new Object();
// I have logic that copies certain properties but not others
// but overall it looks like this:
TempObject.prop1 = MyArrayOfObjects[i].prop1;
TempObject.prop2 = MyArrayOfObjects[i].prop2;
NewArray.push(TempObject);
}
As I loop through MyArrayOfObjects, I clear the TempObject and create a new one each time. Does NewArray contain the objects that I'm copying or just a reference to the objects copied and that then become deleted as the loop iterates?
Thanks.
It contains references to the objects themselves.
This code shows that concept in action (notice that changing the object after pushing it into the array changes the object in the array as well):
var ray = new Array();
var obj = { foo: 123 };
ray.push(obj);
obj.foo = 321;
alert(ray[0].foo);
> var NewArray = new Array();
It is generally considered better to use an array literal to create an array. Variable names starting with a capital letter are, but convention, used for constructors. Using "new" at the start of a variable name can easily slip to become "new Array", and the name should reflect its purpose, so something like the following might be better:
var objectArray = [];
.
> for (i = 0; i < MyArrayOfObjects.length; i++) {
You should always declare variables, especially counters as undeclared variables are made properties of the global object (effectively global variables) when they are first assigned a value. Also, it is considered better to store the length of the array than get it in each iteration:
for (var i = 0, iLen = MyArrayOfObjects.length; i < iLen; i++) {
.
> TempObject = null;
> TempObject = new Object();
Again, declare variables. Assigning a value of null serves no useful purpose when you're going to assign some other value immediately afterward. Just do the second assignment (and use a literal):
var TempObject = {};
.
> // I have logic that copies certain properties but not others
> // but overall it looks like this:
>
> TempObject.prop1 = MyArrayOfObjects[i].prop1;
> TempObject.prop2 = MyArrayOfObjects[i].prop2;
>
> NewArray.push(TempObject);
At this point, TempObject and NewArray[NewArray.length - 1] both reference the same object.
> }
As I loop through MyArrayOfObjects, I clear the TempObject and create
a new one each time.
There is no need to "clear" the object, just assign a new value to the variable. In javascript, all variables have a value that might be a primitive (e.g. string, number) or a reference to an object (e.g. Object, Array, Number, String)
Does NewArray contain the objects that I'm
copying or just a reference to the objects copied and that then become
deleted as the loop iterates?
It contains references to the new objects created on each iteration.
As variables hold references to objects, assigning a new value to the variable doesn't do anything to the object. When an object is no longer referenced by any variable or object property, it is made available for garbage collection and may be removed automatically at some later time when garbage collection runs.
Using map or its jquery counterpart might be a more idiomatic way of doing this. For example:
var oldArray = [
{ prop1: 1, prop2: 10 },
{ prop1: 2, prop2: 20 },
{ prop1: 3, prop2: 30 }
]
var newArray = $.map(oldArray, function(oldObj) {
return { newProp: oldObj.prop1 }
})
console.log(newArray)
I'm faced with a situation in JavaScript when I need to update an object via its pointer similar to ะก++ array of pointers to objects
Example code for my issue:
var foo = new Array();
var bar = function(){
this.test = 1;
foo.push(this); // push an object (or a copy of object?) but not pointer
};
var barInst = new bar(); // create new instance
// foo[0].test equals 1
barInst.test = 2;
// now barInst.test equals 2 but
// foo[0].test still equals 1 but 2 is needed
So, how can I solve this? Should I use a callback or something like this or there is an easy way to help me to avoid copying the object instead pushing the raw pointer into an array?
JS is pass-by-value, so your original assignment was this.test = the value of 1, in my example, it's this.test = the object pointed to by ptr, so when I change ptr this.test changes as well.
var foo = [],
ptr = {val: 1},
bar = function(){
this.test = ptr;
foo.push(this); // push an object (or a copy of object?) but not pointer
},
barInst = new bar(); // create new instance
// foo[0].test.val equals 1
ptr.val = 2;
// foo[0].test.val equals 2
Although if you thought that foo.push(this); was similar, it isn't. Since this is an object, the array will indeed contain "raw pointers" to objects, just like you want. You can prove this simply:
foo[0].test = 3;
// barInst.test === 3
Which shows that it is indeed a pointer to the object that was pushed onto the array
"create object method pointer"
Object.defineProperty(Object.prototype,'pointer',{
value:function(arr, val){
return eval(
"this['"+arr.join("']['")+"']"+
((val!==undefined)?("="+JSON.stringify(val)):"")
);
}
});
ex of use
var o={a:1,b:{b1:2,b2:3},c:[1,2,3]}, arr=['b','b2']
o.pointer(arr) // value 3
o.pointer(['c',0], "new_value" )