What is wrong with javascript? - javascript

I wrote some simple javascript code, but it does not return the expected result.
var arr = new Array();
var firstobj = {
cta: 0,
ccc: 0,
crc: 0
}
for (var ta = 1; ta <= 10; ta++) {
arr[ta] = firstobj;
}
arr[6].cta = 1;
console.log(arr);
I only change cta value of 6th element, but it changes for all elements.
Expected:
[{cta:0, ccc:0, crc:0}, ..., {cta:1, ccc:0, crc:0}, {cta:0, ccc:0, crc:0}, ...]
// ^ 6th element
Actual:
[{cta:1, ccc:0, crc:0, ...] // All have 1

Objects in Javascript are assigned by pointer (well technically JS doesn't have pointers, but it works like a pointer does in other languages). So, you have filled your array so that every element contains a pointer-like reference to the exact same object. Thus, when you change that object, you see the change everywhere because there's only one object and you changed it.
If you want to initialize an array with separate objects, you have to create a new object or clone an existing object and assign that separate object into each element of your array.
For example, you could do that like this:
var myArray = [];
var obj;
// Also, arrays start from 0, not from 1.
for (var i = 0; i < 10; i++) {
// create a new object for each item in the array
obj = {cta:0, ccc:0, crc:0};
myArray[i] = obj;
}
myArray[6].cta = 1;
document.write(JSON.stringify(myArray));

you assigned the same object reference to all values in the array
make it (use Object.create)
for (var ta = 1; ta <= 10; ta++)
{
arr [ta] = Object.create( firstobj );
}

When you save the same firstobj to your array it saved by reference so when you changing one of the values it changes all of them, my suggestion is to create a new object for each element in your array.
var arr = new Array();
for (var ta = 1; ta <= 10; ta++) {
arr [ta] = { cta:0,
ccc:0,
crc:0
};
}
arr[6].cta=1;
console.log(arr);

Only the 6th element's cta value must be 1, but all elements cta
values change.
all the elements in your array(apart from element at zero index , which would be undefined in your case) are referring to the same object so if you change property in one element it is refelected across all elements

Each element in array is referring to same object.
So when you change object value it is reflected in all elements.

Related

Map where each date holds an array, implementation problem

I would need a structure where each key (Date) holds an array of integers.
I have tried the following but it does not seem to be working.
I create a record with the array and then set all its values to 0, although it still seems they are NaN:
The first statement creates a record as a Date with an associated array of a length defined by a variable.
Dictionary.set(Meteor.jira.formatDate(moment(date),[arrayLenght]);
//initialize the array with 0 values
var i;
for (i = 0; i < arrayLenght; i++) {
Dictionary.set(Meteor.jira.formatDate(moment(date))[i]=0);
}
}
Fill array first, then put it into dictionary.
You can update it's value changing any variable that contains reference to your array.
let Dictionary = new Map();
let arrayLenght = 6;
let key = "2018-11-15" //Meteor.jira.formatDate(moment(date))
let arr = Array(arrayLenght).fill(0);
Dictionary.set(key, arr);
let value = Dictionary.get(key);
console.log(JSON.stringify(value));
value[2] = 1;
value.unshift(33);
arr.unshift(15);
console.log(JSON.stringify(Dictionary.get(key)))

javascript array seems to change my itself

I'm working with P5.js and try to save some values in an array and than creating a copy of this array to manipulate.
Unfortunately It happens that when I manipulate the second array, also the original one changes, and I can't figure out why.
var particels = []
var particelsCopy = []
function calcInitialPositions(){
for (var i = 0; i < pixels.length; i+=4) {
if (pixels[i] == 0){
var x_ = i % width
var y_ = i / width / 2
var coords_ = {x : x_ , y : y_}
particels.push(coords_)
}
};
}
function setup() {
loadPixels()
calcInitialPositions();
particelsCopy = particels
}
function draw() {
for (var i = 0; i < particelsCopy.length; i++) {
particelsCopy[0].x = 99
};
console.log(particel[0].x)
}
Console prints 99
The = operator in Javascript assigns Objects, which includes arrays, by reference not by value. So the line:
particelsCopy = particels
is redefining particelsCopy to be an alias of particels.... after that point they are the same array. You need to copy the array by value like:
particelsCopy = particels.slice();
Note this is only a shallow copy, if the array contains objects or arrays they will be copied by reference, you will have to repeat this on child items (e.g. coords_ object, though for objects the pattern is copy = Object.assign({},original);).
To deep copy everything by value, you have to do this for every child level of object/arrays. Many libraries like jQuery have ready-built functions to help this.
You can use destructuring to copy objects in an array
particelsCopy = particels.map(obj => ({...obj}));
The line:
particelsCopy = particels
makes a copy of the array reference, not the elements in the array.
You need to allocate a new array object, then copy the elements. If the elements are objects, you will have to make a shallow (or deep) copy of them as well. This solution uses Object.assign() to make a shallow copy.
particelsCopy = [] // already done previously
for (var i=0; i<particels.length; i++){
particelsCopy[i] = Object.assign({}, particels[i]};
}

removeDuplicates does not work as expected

I am trying to extend Array prototype with the following functions:
Array.prototype.uniqueItems=function(){
var ar=this,unique=[],max=ar.length;
for(var i = 0 ; i < max;i++)
if(unique.indexOf(ar[i] )==-1)
unique.push(ar[i]);
return unique;
};
Array.prototype.removeDuplicates=function(){
var self = this;
self = this.uniqueItems();
return self;
};
The first function is supposed to return an array without duplicates and the second to remove all duplicates from a given array.
Consider the following code:
var x=[1,1,1,1,2,2,2,2,3,3,3,3,4,4];
x.removeDuplicates();
console.log(x);
The output is :
[ 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4 ]
So the duplicates still remain.Any ideas why?Thanks In advance!!!!Also notice that I can not use x= x.uniqueItems() since it will work only for x.I want it to work for any given array.
You might as well do it like this in ES6
var x = [1,1,1,1,2,2,2,2,3,3,3,3,4,4],
u = a => Array.from(new Set(a)),
y = u(x);
console.log(y);
The new Set object in ES6 takes elements and keeps only one of each and discard the dupes. So it's in a way ideal to get unique items. A new set object is instantitated by the Set constructor and it will accept an array of items as an argument such as in var s = new Set([1,1,2,1,4,3,6,7,4,5,6,9,8,1,2,3,4,7,0]) and the resulting s set will be composed of unique entries of 1,2,4,3,6,7,5,9,8 and 0 in the order of appearance. Set objects have generator properties and iterator functions which can be obtained from them. Hence [...s] (the ES6 spread operator) or Array.from(s) would result a proper unique items array automatically.
Converting the Array to a Set and back allows for an arguably cleaner implementation:
Array.prototype.uniqueItems = function() {
return new Array.from(new Set(this));
};
Array.prototype.removeDuplicates = function() {
this.from(new Set(this));
};
Reassign to x.
var x=[1,1,1,1,2,2,2,2,3,3,3,3,4,4];
x = x.removeDuplicates();
console.log(x);
when you say
self = this.uniqueItems();
self is now pointing to a new array, not this
You need to either do
x = x.removeDuplicates();
or iterate this again in removeDuplicates to remove the other items.
For example
Array.prototype.removeDuplicates=function(){
var self = this;
var that = this;
self = this.uniqueItems();
//remove all items
for(var counter = that.length ; counter >= 0; counter -- )
{
that.splice(counter,1);
}
//copy the individual items to this
Object.keys(self).forEach(function(index){
that[index] = self[index]
});
return self;
};
Hey thank you all for your answers .I found a simple solution to my problem by doing the following:
Array.prototype.removeDuplicates=function(){
//First create a copy of the current array without duplicates
var clear_array=this.uniqueItems();
//Delete every item in the current array
this.length=0;
//Fill the current array with the elements of clear_array
for(var i = 0;i<clear_array.length;i++)
this[i] = clear_array[i];
return this;
};
Also I did not use a Set since I want to be sure about backwards compatibility
Hope this will be helpful to someone :)

how to generate arrays automatically in javascript?

I want to make a loop that makes arrays automatically and assign the values to it.
The problem is how to generate the array itself automatically.
for(var attGetter=1; attGetter <= num; attGetter++){
var catesArray1 = new Array();
for(var atttGetterArray=1; atttGetterArray <= series; attGetterArray++){
idOfInput = "cate"+chartGetter+"_series"+attGetterArray;
catesArray1.push($("#"+idOfInput).val());
}
}
I want the loop to generate the array itself automatically like
catesArray1
catesArray2
catesArray3
and so on..
You need an object or an array to hold the multiple arrays you wish to create. Maybe something you are looking for is like the following?
var arrayHolder = new Array();
for(var attGetter=1; attGetter <= num; attGetter++){
var catesArray = new Array();
for(var attGetterArray=1; atttGetterArray <= series; attGetterArray++){
idOfInput = "cate"+chartGetter+"_series"+attGetterArray;
catesArray.push($("#"+idOfInput).val());
}
arrayHolder.push(catesArray);
}
If you want the arrays to be in global namespace, You can try
window['catesArray' + attGetter] = [];
...
window['catesArray' + attGetter].push(...)
Else you can create a hash object and use it to hold the reference
var obj = {};
.....
obj['catesArray' + attGetter] = [];
.....
obj['catesArray' + attGetter].push(...)
In that case you will have to create one new array that holds all the cacatesArrays from first for loop
var catesArrayContainer = new Array(); //<<<---------------------
for(var attGetter=1; attGetter <= num; attGetter++){
var catesArray = new Array();
for(var atttGetterArray=1; atttGetterArray <= series; attGetterArray++){
idOfInput = "cate"+chartGetter+"_series"+attGetterArray;
catesArray.push($("#"+idOfInput).val());
}
catesArrayContainer.push(catesArray); //<<<--------------------
}
EDIT :
This happens because the scope of variable catesArray1 was limited. When the loop enters next iteration the catesArray1 gets reinitialized, thus losing all the previously stored values...
Now in the code I have posted, we are storing every instance of catesArray1 in another array, and your values persist out side of the for loop
You can do something like this for 4 arrays of 5 elements each
yourarray=[];
for (i = 0; i <4; i++) {
temparray=[];
for (j = 0; j < 5; j++) {
temparray.push($('#'+whateverID+'_'+i+'_'+j)) //your values here
}
yourarray.push(temparray);
}
Check it on this JSFiddle. open chrome console to see array
If you want to create array within loop from index
You can use eval to evaluate javascript from strings but i wont use that unless there is no other way. you can see both above and eval method in this Fiddle. Open Chrome console to see array values
Just a comparison of using eval and 2D array
Open console in chrome while you run this jsFiddle and you will see the difference in eval and 2darray in context of this question.
You should assign them to an object. In this case, make an object variable before the first for-loop to hold all arrays:
var allArrays = {};
for(var attGetter=1; attGetter <= num; attGetter++){
var currentArray = allArrays['catesArray' + attGetter] = new Array();
for(var atttGetterArray=1; atttGetterArray <= series; attGetterArray++){
idOfInput = "cate"+chartGetter+"_series"+attGetterArray;
currentArray.push($("#"+idOfInput).val());
}
}
Instead of attempting to create & allocate dynamically named variables, I would think of this more of an array of array's if you will. In other words, create an array that holds all of the arrays you want:
var collections = []; // Literal notation for creating an array in JS
From here, it's a matter of making each value you create within this array its own array:
var n = 10; // Total amount of arrays you want
for (var i = 0; i < n; i++) {
var values = [];
// Have another loop that fills in the values array as expected
collections.push(values); // Each element at collections[i] is its own array.
}
If you truly need named elements, you could potentially do something very similar with just an object {} instead, and refer to each element by a name you create.
var collections = {}; // Literal notation for an object in JS
var n = 10; // Total amount of arrays you want
for (var i = 0; i < n; i++) {
var values = []; // Literal notation for an array in JS
// Fill in the values array as desired
var name = 'arr' + i; // How you'll refer to it in the object
collections[name] = values;
}
I suggest the former though, since it does not sound like you need to have explicit names on your arrays, but just want multiple layers of arrays.

Can't reference array by index

I have an array defined as:
var subjectCache = [];
I then have some code to build it up, which is working ok.
However, if I try to reference the array by an index, e.g.:
var x = subjectCache[0];
or
var x = subjectCache[1];
I get undefined.
Also subjectCache.length is always 0 (zero).
if I try to reference it by its key, e.g.:
var x = subjectCache['12345'];
it works.
Is this normal? Shouldn't I be able to reference it by its index whatever?
I'm using Internet Explorer, if it makes a difference (and it probably does :( )
[Edit]
this is the code I'm using to build the array, although I really don't think it is to blame.
It's a callback from a webservice call. This is working fine and the array is being populated.
var subjectCache = [];
var subjectCacheCount = 0;
function refreshSubjectsCallback(data) {
// update subjects
// loop through retrieved subjects and add to cache
for( i=0; i < data.length; i++ )
{
var subject = data[i];
var subjectid = subject.SubjectId;
subjectCache[subjectid] = subject;
subjectCacheCount += 1;
}
}
[/Edit]
You're probably assigning keys manually instead of using subjectCache.push() to add new elements to the array:
var array = [];
array['foo'] = 'bar';
console.log(array.length); // 0
The length attribute isn't going to reflect those changes the way you'd expect:
> var a = [];
undefined
> a[100] = 2; // The previous `100` entries evaluate to `undefined`
2
> a.length;
101
Instead, use an object:
var object = {};
object['foo'] = 'bar';
for (var key in object) {
var value = object[key];
console.log(value);
}
From your symptoms, it sounds like you are trying to treat the array as an associative array.
In Javascript, arrays work like this:
var a = [];
a[1] = 10;
alert(a.length);
Objects work like this:
var o = {};
o.myProp = true;
o["myOtherProp"] = false;
Arrays only work with numeric keys not strings. Strings assign properties to the object, and aren't counted as part of length nor it's numeric indices.
When building the array, make sure you are assigning to a numeric position within the array.
No, it will not work, because you haven't created arrays but objects.
you will have to access it by its key.
var x = subjectCache['12345'];
If this works and subjectCache.length doesn't, I think you are making an object not an array. You are confused.
Somewhere along the road you lost the array, and the variable subjectCache points to a different kind of object.
If it was an array, it can't have the length zero and contain an item that is reachable using subjectCache['12345']. When you access an item in an array it doesn't make any difference if you use a numeric index or a string representing a number.

Categories

Resources