Assigning 'undefined' a value, how? - javascript

I was trying to assign a value to the items of an empty array, but I couldn't manage.
I used the Array constructor, and tried using both the .map() and the for ... of, but it didn't work.
let chrom = new Array(4);
const randomN = () => Math.floor(Math.random()*2);
for (g of chrom) {
g = randomN()
}
However, this solution worked
let emptyArr = new Array(4);
const randomN = () => Math.floor(Math.random()*2);
for (i=0; i<chrom.length; i++) {
chrom[i] = randomN()
}
Somehow it seems like only specifying the indexes does the trick.
does anybody know why this happens? what should I read? I tried looking in the documentation, but I couldn't see anything there.

The explanation is that in your first solution, g is going to be a local variable (a copy) instead of a reference to the actual value in the chrom array.
For example:
let nums = [1, 2, 3]
for (let num of nums) {
num = 1 // num in this case is a totally different variable
}
console.log(nums) // will still output [1, 2, 3]
Here is a good article explaining the difference between value vs reference in Javascript.

Using the for...of loop does not work since g is only a variable that holds the value of the element of the array at the current index; modifying it does not modify the array.
Array#map skips all empty slots, like those created by Array(size) or new Array(size). An array literal with an empty slot looks like this: [,]. You can fill the array before mapping or use spread syntax.
chrom.fill().map(randomN);
//or
[...chrom].map(randomN);
The standard index-based for loop uses the length of the array, which includes empty slots and sets elements using the index, so it has the desired effect.

Related

JS arrays 3 deep getting lost

Learing JS by game. and of course the simplist is a clicker :-)
OK, so I have had lots of help with this, but the array section is just not sinking in. JS arrays do not work like arrays I am used to. two part question:
1. Why does the following code keep saying weaponlevelIfo[0] undefined, when it is defined? Please explain your answer, don't just correct mine LOL
2. I am more interesting in populating the code at runtime
As stated, all the research I am coming across as well as videos, talk about static data, i.e. it is put in at programing level, not run time.
I have had a really patient community person that has tried to help me understand JS arrays, but I must be blind as I am not seeing it. I can do in in other language just fine. but JS? nope.
// produces weaponLevelNfo[weaponId][level][cost] and [goldperclick]
// weapon, level 1-9, cost/goldperclick on each level
var weaponLevelNfo = new Array(14); // Outter array comprised of weapons 0-14
function initGame() {
for (let i=0; i <= weaponLevelNfo.length; i++) {
weaponLevelNfo[i] = new Array(9); // create leves array under weaponid array
for (let j = 0; j < weaponLevelNfo[i].length; j++) {
// loop through each 9 levels changing as needed
weaponLevelNfo[i][j] = new Array(2); // create an object for readability
}
}
}
initGame();// added - forgot to add this in the original post (sorry)
weaponLevelNfo[0][0][2]=3;
console.log(weaponLevelNfo[0][0][2]);
// always gives me weaponLevelNfo[0] not defined
I prefer the results to be as such
weaponLevelNfo[x][y].cost,
weaponLevelNfo[x][y].incomePerClick,
but am quite happy with
weaponLevelNfo[x][y][z],
weaponLevelNfo[x][y][z],
But as you can see from the code, assigning them direct or at runtime, I get the not defined error
What is missing to allow me to assign these at run time?
Two issues:
You need to call initGame to create all those subarrays, otherwise weaponLevelNfo[0] is not defined and so weaponLevelNfo[0][0] will trigger the error you get.
Your outer loop performs one iteration too many (<=). Change:
for (let i=0; i <= weaponLevelNfo.length; i++) {
by
for (let i=0; i < weaponLevelNfo.length; i++) {
Without that change, the last iteration is actually adding an element to the array in slot i, and so the length of the array increases... the loop becomes infinit.
Note that there are shorter ways to define such a nested array. For instance:
var weaponLevelNfo = Array.from({length:14}, () => Array.from({length:9}, () => [0, 0]));
When you create an array in javascript with new Array(2) this is an array with two positions. In this example (new Array(2)), you can access it at index 0 and index 1. Consider the following:
var newArr = new Array(2);
You can then access the two positions by the following:
var position1 = newArr[0];
var position2 = newArr[1];
So when you try this:
var position = newArr[2];
This will throw an undefined exception.
You can change the end of your example code to this:
weaponLevelNfo[0][0][1]=3;
console.log(weaponLevelNfo[0][0][1]);
You define array with two elements Array(2) with indexes 0 and 1 but you use index 2.
To initialize multidimensional array filled by zeros (if not remove .fill(0)) use
[...Array(14)].map(x=>[...Array(9)].map(y=>Array(2).fill(0)));
let a=[...Array(14)].map(x=>[...Array(9)].map(y=>Array(2).fill(0)));
a[13][8][1]=3;
console.log('Last element value:',a[13][8][1]);
console.log(JSON.stringify(a));

How to initialize array length and values simultaneously in new Array()?

Let’s consider, I have to initialize an Array with some values
So I can achieve this by writing following code.
var arr = new Array("a", "b", "c", "d")
console.log(arr)
Similarly, I have to determine the length of the array before using it.
So I can achieve this by following code.
var arr = new Array(5)
console.log(arr.length)
Finally, I have a following questions ?
Is it possible to initialize an array with array length and different values (not similar values) simultaneously using new Array() ?
How to initialize a single integer value using new Array() ?
EDIT:
here, different values refers there are some specific string values.
I know it is straightforward when using array literals. but that's not exactly what I want.
The answer for both questions is no. Looking at the docs, there are two overloads for the Array function.
A JavaScript array is initialized with the given elements, except in the case where a single argument is passed to the Array constructor and that argument is a number (see the arrayLength parameter below).
If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with its length property set to that number.
Only these two possibilities exist, there is no overload for specifying both the size and the values of an array.
You can create and fill an array like so:
let a = Array(100).fill(null)
console.log(a)
Or to increment your filled values:
let i=0,a = Array(100).fill(0).flatMap(x=>[x+i++])
console.log(a)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
You could use .fill().
console.log(new Array(5).fill(2));
// [2, 2, 2, 2, 2]
Is it possible to initialize an array with array length and values simultaneously using new Array() ?
As far as I know, this isn't possible yet.
How to initialize a single integer value using new Array() ?
That would be k => new Array(1).fill(k). But if I had to choose, I'd use k => [k]. Note it is recommended not to use new Array() in other scenarios than to initialize it's lenght. But even then, you should rather be sure you are giving it an integer because the behaviour of new Array(n) is a bit erratic, and won't throw you an error when you wish it did.
Actually, I wish it was not possible to initialize an array with value using new Array(). The worst being using new Array(...args), whose behaviour will change dramatically when args is [5]. You should stick to [] arrays if you want to initialize an array with values.
Array("") gives [""]
Similarly Array([]) gives [[]] and Array({}), [{}]
Array(5) gives an array with 5 empty slots
Array(2.5) produces an Uncaught RangeError: Invalid array length.
Also, Array() gives []
Note: This is Chromium's behaviour. I didn't check Firefox.
There are few ways to create an array:
1) Literals
const a = [1,2,3];
console.log(a);
But you say you don't want to use it.
2) Array constructor:
const a = new Array(10); //array of length 10
console.log(a);
const b = new Array(1,2,3);
console.log(b); // array with elements 1,2,3
But you say that you don't want to go for it
3) Array.from
const a = Array.from(new Array(10), (val, ind) => ind); // array of 10 values and map applied to these elements
console.log(a);
Over these 3 ways, you have the Array.fill method, which can be called with static values only:
const a = new Array(10);
console.log(a.fill(5)); // array of 10 number elements with value of 5
Considering your case, maybe your solution could be to go with Array.from, using the map function you can provide as second parameter.
You could think to create some function like the following:
function createMyArray(length, start, end) {
return Array.from(new Array(length), (val, ind) => ind >= start && ind <= end ? ind : undefined);
}
console.log(createMyArray(5, 2, 4));
console.log(createMyArray(5, 1, 3));
console.log(createMyArray(10, 2, 6));
The question you should ask to yourself is: Where and how is the data I want to use coming from? Otherwise this is really too much vague
Is it possible to initialize an array with array length and different values (not similar values) simultaneously using new Array() ?
No you cannot do that with the Array constructor only.
An alternative way is to do it like this:
var a = ['a', 'b', 'c', 'd'];
a.length = 10;
console.log(a);
How to initialize a single integer value using new Array() ?
You can't. This is what happens when you try to do so according to the specification:
Array(len)
[...]
Let intLen be ToUint32(len).
If intLen ≠ len, throw a RangeError exception.
Let setStatus be Set(array, "length", intLen, true).
Assert: setStatus is not an abrupt completion.
Return array.
Use the other ways to create an array instead (e.g. [1] or Array.of(1)).
Here's a different but related take on initializing an array without using an array literal.
let arr = [...Array(10)].map((emptyItem, index) => index);
// [0,1,2,3,4,5,6,7,8,9]
I can't find documentation that matches how this expression is constructed, so I can't fully explain it. But it is using the spread syntax to spread 10 empty items into an array.

Javascript array in array - first index is always overwritten

I have a problem with my JS function. For simplification, I want to fill an array (arr1) with n other arrays (arr2). In my loop I use a counter for the current postion in arr1 (cant use arr1.push for a reason). If I log all my arr2's in arr1 they are all the same, always the last one that was added. So I wrote a basic script to test it. I always log the first element and incement the counter.
I'm new to JS, is there some huge misunderstanding I don't get?
function test(){
var arr1 = [];
var arr2 = [];
var counter=1;
arr2[0]="first";
arr2[1]="first";
arr2[2]="first";
arr1[0]=arr2;
arr1[0].forEach(function(elem){console.log(elem);});
for (var i = 0; i < 10 ; i++) {
arr2[0]=counter;
arr2[1]=counter;
arr2[2]=counter;
arr1[counter]=arr2;
arr1[0].forEach(function(elem){console.log(elem);});
counter++;
}
}
<button onclick="test()">Click</button>
You can try to use the spread operator.
arr1[0]=[...arr2];
arr1[counter]=[...arr2];
An array is a reference type, so you always refer to the base, you don't put a copy of it inside of arr1 but a reference to the arr2.
You want a copy of arr2 to be assigned to arr1.
You can do this by creating a new Array, or more modern the ... spread operator
As Pointy said it, it just referenced the arr2 and doesn't create a copy.
So you need to
arr2=new Array();
at the beginning of the loop.

Using push() to copy one array into another

Let's assume I have a function like this
function createMultiDimArray() {
let results = [];
let current = [];
for (let i = 1; i <= 10; i++) {
current.push(i);
if (i % 2 === 0) {
results.push(current);
current = [];
}
}
return results;
}
When I execute it
let arr = createMultiDimArray();
arr will look like this
[[1,2][3,4][5,6][7,8][9,10]]
I have tested it in multiple browsers and it seems to work. So apparently push() is creating a copy of the array passed to it instead of just using the reference, because otherwise arr would look like this (as current === [] when the function ends)
[[],[],[],[],[]]
I have searched the internet but I haven't found anything about this behavior of push(). So my question is: Is it safe to use push() to copy one array into another?
push does not copy the array (or whatever argument it's given).
Rather, the line
current = [];
creates a new array object and assigns it to the array reference current. From your analysis, I guess you assumed it would empty the existing array object referred to by current, but that's not the case.
No, in the code you are pushing the values into result using results.push(current);, and after that you create a new current array using current = [];. So after every even number you'll get sets of numbers pushed into results.

How do array sizes work in Javascript

In JavaScript, if you set an array to be of size 5 ( var foo = new Array(5); ), is this just an initial size? Can you expand the number of elements after it is created. Is it possible to do something like this as well - arr = new Array() and then just assign elements one by one? Thanks in advance :-)
Yes it is just an initial size, and it is not required. If you don't use a single number, you can immediately populate.
It is also more common to use the simpler [] syntax.
var arr = ['something', 34, 'hello'];
You can set (or replace) a specific index by using brackets:
arr[0] = "I'm here replacing whatever your first item was";
You can add to the end by using push:
arr.push('add me');
There may be faster performance in some browsers if you do it like this instead:
arr[arr.length] = 'add me';
You can add something at any index.
You can remove an item completely using splice:
arr.splice(0, 1); // remove first item in the array (start at index 0, with 1 being removed)
When you give a new array an explicit size in javascript (using new Array(5)), you populate each index with value of undefined. It is generally considered better practice to instantiate using the array literal [] expression:
var arr = [];
Then, you can push new elements using push()
var arr = [];
arr.push('first value'):
arr.push('second value'):
Check out the MDC Array documentation for more info: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
Theres a few ways to declare and put values in an array.
First like what you want to do,
var myarr = new Array();
myarr[0] = 'element1';
myarr[1] = 'element2';
myarr[2] = 'element3';
Second way is to define them
var myarr =new Array("element1","element2","element3");
and third is similar to the second
var myarr =["element1","element2","element3"];
You can also check out https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array for a little more information about using the arrays as well. You could use push and pop if you wanted to as well.
If you use jquery or mootools they also have built-in functions to perform on arrays,
http://api.jquery.com/jQuery.each/ for instance.
Have a look at http://www.w3schools.com/js/js_obj_array.asp
var myCars=new Array(); // regular array (add an optional integer
myCars[0]="Saab"; // argument to control array's size)
myCars[1]="Volvo";
myCars[2]="BMW";
Check the documentation for Array, but the simple answer to your question is yes.
var arr5 = new Array(1, 2, 3, 4, 5); // an array with initial 5 elements
var arr = new Array(); // an array without initial
You can also use array literals:
var arr5 = [1, 2, 3, 4, 5];
var arr = [];
Arrays are dynamic in JavaScript. You don't have to initialize them with a certain length. In fact you should use the literal notation [] because of the Array constructor's ambiguity:
If you pass only one parameter to Array, it will set the array length to this parameter. If you pass more than one parameter, these elements are added to the array.
How is the size of the array determined?
The size of an array is the highest index + 1. This can be quite confusing. Consider this:
var arr = [];
arr[41] = 'The answer?';
console.log(arr); // [undefined, undefined, ..., 'The answer?']
console.log(arr.length) // 42
You can even set the length yourself by assigning a number to .length:
arr.length = 99;
If you now add a new element using arr.push(), it will get the index 100 and the length will increase. Whenever you add an element to the array via an index, it is tested whether arr.length is smaller than the index and updated accordingly. But it does not get smaller.
So in fact what var arr = new Array(5) is doing is setting the length of the array to 5. Nothing else.
For more information about creating and populating arrays, I suggest to read about it in the MDC JavaScript Guide.

Categories

Resources