Pass and return an array from WebAssembly - javascript

I want to take an array in JavaScript, pass it to WebAssembly, have WASM transform the array, and have WASM return the transformed array back to JavaScript.
e.g.
/* main.js */
const array = [1, 2, 3, 4, 5];
// WASM code that squares the above array
const squaredArray = wasmModule.exports.squareArray(array);
console.log(squaredArray); // [1, 4, 9, 16, 25]
I figured I could achieve this in C by iterating over the array, like
/* square.c */
// the array variable is [1, 2, 3, 4, 5]
for (int i = 0; i < arrayLength; i++){
array[i] = array[i] * array[i];
}
return array;
and compiling to WASM by doing
emcc square.c -o square.wasm -s WASM=1
However, some research has lead me to believe that it's much more complicated than this, involving allocating and de-allocating memory, and a bit more to do on the C end.
Could anybody give me a boilerplate example of passing and returning an array from WebAssembly? I would appreciate any help you could give. I'm new to WebAssembly and haven't used any other programming language than JS.
If another language that can compile to WASM would better suited for this (C++, Go, Rust), I would be happy for examples on those too.

Rust makes it easy with wasm-bindgen and wasm-pack. I used Node.js for quick testing.
Quick setup:
cargo new --lib --vcs=none wasm_pass_return_ary
cd wasm_pass_return_ary
cargo add js-sys
cargo add wasm-bindgen
Inside Cargo.toml, add this before [dependencies]:
[lib]
crate-type = ["cdylib"]
I'm assuming that the parameter is guaranteed to be a signed 32-bit integer.
src\lib.rs
use js_sys::Int32Array;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn square_array(ary: &[i32]) -> Int32Array {
let out = ary.into_iter()
.map(|x| x.pow(2))
.collect::<Vec<_>>();
Int32Array::from(&out[..])
}
Build with wasm-pack build --target nodejs
main.js file at the project root:
const wasmModule = require("./pkg/wasm_pass_return_ary.js");
const { square_array } = wasmModule;
const array = [1, 2, 3, 4, 5];
const squaredArray = square_array(array);
console.log(squaredArray); // the data type is Int32Array
console.log([...squaredArray]);
Run with node .\main.js

Related

Constant Array in JavaScript

How can I keep an array of constants in JavaScript?
And likewise, when comparing, it gives me the correct result.
Example,
const vector = [1, 2, 3, 4];
vector[2] = 7; // An element is not constant!
console.log(JSON.stringify(vector));
// [1,2,7,4] ... Was edited
// OR
const mirror = [1, 2, 7, 4];
console.log(`are equals? ${vector == mirror}`);
// false !
With Object.freeze you can prevent values from being added or changed on the object:
'use strict';
const vector = Object.freeze([1, 2, 3, 4]);
vector[2] = 7; // An element is not constant!
'use strict';
const vector = Object.freeze([1, 2, 3, 4]);
vector.push(5);
That said, this sort of code in professional JS is unusual and a bit overly defensive IMO. A common naming convention for absolute constants is to use ALL_CAPS, eg:
const VECTOR =
Another option for larger projects (that I prefer) is to use TypeScript to enforce these sorts of rules at compile-time without introducing extra runtime code. There, you can do:
const VECTOR: ReadonlyArray<Number> = [1, 2, 3, 4];
or
const VECTOR = [1, 2, 3, 4] as const;
I have not investigated thoroughly, but it is inferred that JS will have immutable native types, here is a presentation:
https://2ality.com/2020/05/records-tuples-first-look.html
const vector = #[1, 2, 3, 4]; // immutable
The const keyword can be confusing, since it allows for mutability. What you would need is immutability. You can do this with a library like Immutable or Mori, or with Object.freeze:
const array = [1,2,3]
Object.freeze(array)
array[0] = 4
array // [1,2,3]

What is the difference between returning a function call vs only calling the function again during recursion?

I am trying to implement a DFS and I do not understand the difference between calling a function inside itself (recursion) and returning the function call (also recursion?)
Snippet 1: Returning a function call (Wrong answer)
In this case, the code is not backtracking correctly.
const graph = {
1: [2, 3],
2: [4, 5],
3: [1],
4: [2, 6],
5: [2, 6],
6: [4, 5]
}
let visited = [];
const dfs = (node) => {
if (visited.includes(node))
return;
console.log(node);
visited.push(node);
for (let i = 0; i < graph[node].length; i++) {
if (!visited.includes(graph[node][i]))
return dfs(graph[node][i])
}
}
dfs(1);
Snippet 2: Only calling the function (Correct answer)
Seems to work okay
const graph = {
1: [2, 3],
2: [4, 5],
3: [1],
4: [2, 6],
5: [2, 6],
6: [4, 5]
}
let visited = [];
const dfs = (node) => {
if (visited.includes(node))
return;
console.log(node);
visited.push(node);
for (let i = 0; i < graph[node].length; i++) {
if (!visited.includes(graph[node][i]))
dfs(graph[node][i])
}
}
dfs(1);
What is the difference between the two? (I thought they'd be the same)
Is this some language specific (JS) thing or am I misunderstanding recursion?
When you return the "function call", you actually return the value that the function that is called yields. When you simply call a function recursively without returning it, you don't do anything with the return value. They are both cases of recursion, and they would work similarly when NOT in a loop.
In this case, since you are using the return value of the function within your for loop, once dfs(graph[node][i]) runs for the first time, and the function finishes executing by returning a value (or just finishes executing, like in this case) and exits the stack call, the for loop ends, and the function execution stops too.
You will experience fewer headaches if you write functions that avoid mutating external state and instead operate on the supplied arguments. Below we write dfs with three parameters
t - the input tree, or graph
i - the id to start the traversal
s - the set of visited nodes, defaults to a new Set
function* dfs (t, i, s = new Set)
{ if (s.has(i)) return
s.add(i)
yield i
for (const v of t[i] ?? [])
yield* dfs(t, v, s)
}
const graph =
{ 1: [2, 3]
, 2: [4, 5]
, 3: [1]
, 4: [2, 6]
, 5: [2, 6]
, 6: [4, 5]
}
for (const node of dfs(graph, 1))
console.log(node)
1
2
4
6
5
3
remarks
1. Your original dfs function has a console.log side effect — that is to say the main effect of our function is to traverse the graph and as a side (second) effect, it prints the nodes in the console. Separating these two effects is beneficial as it allows us to use the dfs function for any operation we wish to perform on the nodes, not only printing to the console -
dfs(1) // <- traverse + console.log
Using a generator allows us to easily separate the depth-first traversal from the console printing -
for (const node of dfs(graph, 1)) // <- traverse effect
console.log(node) // <- print effect
The separation of effects makes it possible to reuse dfs in any way we need. Perhaps we don't want to print all of the nodes and instead collect them in an array to send them elsewhere -
const a = []
for (const node of dfs(graph, 1)) // <- traverse effect
a.push(node) // <- array push effect
return a // <- return result
2. When we loop using an ordinary for statement, it requires intermediate state and more syntax boilerplate -
for (let i = 0; i < graph[node].length; i++)
if (!visited.includes(graph[node][i]))
dfs(graph[node][i])
Using for..of syntax (not to be confused with for..in) allows us to focus on the parts that matter. This does the exact same thing as the for loop above -
for (const child of graph[node])
if (!visited.includes(child))
dfs(child)
3. And using an Array to capture visited nodes is somewhat inefficient as Array#includes is a O(n) process -
const visited = [] // undefined
visited.push("x") // 1
visited.includes("x") // true
Using a Set works almost identically, however it provides instant O(1) lookups -
const s = new Set // undefined
s.add("x") // Set { "x" }
s.has("x") // true
Others have explained why return is short-circuiting your process.
But I would suggest that the main issue is that you are not really using that recursive function to return anything, but only relying on the the side effect (of printing to the console) inside the function. If you really want a traversal of your graph, it would be cleaner to write a function which returned an ordered collection of the nodes. The answer from Thankyou gives you one such function, using generator functions, as well as some valuable advice.
Here's another approach, which turns your (connected) graph into an array:
const dft = (graph, node, visited = new Set([node])) => [
node,
... (graph [node] .flatMap (
(n) => visited .has (n) ? [] : dft (graph, n, visited .add (n))
)),
]
const graph = {1: [2, 3], 2: [4, 5], 3: [1], 4: [2, 6], 5: [2, 6], 6: [4, 5]}
console .log (dft (graph, 1)) //~> [1, 2, 4, 6, 5, 3]
We also use a Set rather than an array to track the visited status of nodes. We first visit the node supplied, and then for each node it connects to, we recursively visit that node if we haven't already marked it as visited. (I call this dft as it's a depth-first traversal, not a depth-first search.)
But please do carefully read the advice in Thankyou's answer. It's quite valuable.
In programming terms a recursive function can be defined as a routine that calls itself directly or indirectly.So in your example both would be considered recursion.
But when considering the fact that the recursion principle is based on the fact that a bigger problem is solved by re-using the solution of subset problem, then we would need those subset results to compute the big result. Without that return you will only get an undefined which is not helping you to solve your problem.
A quite easy example would be the factorial where fact(n) = n * fact(n-1)
function fact (n) {
if (n===0 || n===1) return 1;
else return n*fact(n-1);
}
As you can see on this example, fact(4) = 4 * fact(3) without the return, it will be undefined.
P.S: In your example not calling a return might work simply because we are not re-using the result of the subset

How to execute user submitted javascript code in sandbox environment in node?

So what I am trying to do is as take a javascript code as input from user and return him the result. Right now I am executing the code submitted by user just using eval (with some safety checks). But I understand this is highly unreliable. So what I want to achieve is run this in sandbox environment safely and return the result to user.
E.g
Input:
var a =[1,2,3];
a.map(n => n*2);
Output:
[2,4,6]
I tried using vm in node but I don't really understand how to get the final result from it.
I tried using vm in node but I don't really understand how to get the final result from it.
Many vm module functions, like vm.runInNewContext(), will return the result of the last statement in the string, similar to eval().
var vm = require('vm');
var script = 'var a = [1, 2, 3]; a.map(n => n * 2);';
var sandbox = {};
var result = vm.runInNewContext(script, sandbox);
console.log(sandbox); // { a: [1, 2, 3] }
console.log(result); // [2, 4, 6]
An example of capturing the result is given in the description for vm.runInThisContext()

Writing a parameterless function in Ramda in a point free style?

Consider the working code below:
var randN = x => () => Math.floor(x*Math.random());
var rand10 = randN(10)
times(rand10, 10) // => [6, 3, 7, 0, 9, 1, 7, 2, 6, 0]
randN is a function that takes a number and returns an RNG that, when called, will return a random int in the range [0, N-1]. So it's a factory for specific RNGs.
I've been using ramda.js, and learning functional programming theory, and my question is: Is it possible to rewrite randN in a point free style using ramda?
For example, I could write:
var badAttempt = pipe(multiply(Math.random()), Math.floor)
This would satisfy the "point-free style" requirement, but fails to behave the same way as randN: calling badAttempt(10) simply returns a single random number between 1 and 10, rather than a function that generates a random number between 1 and 10 when called.
I have not been able to find a combination of ramda functions that enables me to do the rewrite in a point-free style. I can't tell if this is just a failure on my part, or something special about using random, which breaks referential transparency and therefore may be incompatible with a point free style.
update
my own slight variation on the solution, after discussing it with Denys:
randN = pipe(always, of, append(Math.random), useWith(pipe(multiply, Math.floor)), partial(__,[1,1]))
This would help with an extra function for abstracting a function to re-evaluate its arguments each time it is called.
thunk = fn => R.curryN(fn.length, (...args) => () => fn(...args))
The only purpose of this function would be to cause some side effect within the given fn function.
Once we have thunk function, we can define randN like so:
randN = thunk(R.pipe(S.S(R.multiply, Math.random), Math.floor))
R.times(randN(10), 5) // e.g. [1, 6, 9, 4, 5]
Note: S.S here is the S combinator from Sanctuary which does effectively the same thing as R.converge(multiply, [Math.random, identity]).
I do however only recommend going with a point-free solution if it actually improves the readability of a function.
I don't know if it's a good idea to learn functional programming using a specific library, because the characteristics of a lib and the functional paradigm will mix inevitably. In practice, however, Ramda is incredibly useful. It bridges the gap between the imperative reality and the functional Fantasy Land in Javascript :D
Here's a manual approach:
// a few generic, reusable functions:
const comp = f => g => x => f(g(x)); // mathematical function composition
const comp2 = comp(comp)(comp); // composes binary functions
const flip = f => x => y => f(y)(x); // flips arguments
const mul = y => x => x * y; // first class operator function
// the actual point-free function:
const randN = comp2(Math.floor)(flip(comp(mul)(Math.random)));
let rand10 = randN(10); // RNG
for (let i = 0; i < 10; i++) console.log(rand10());
It's worth mentioning that randN is impure, since random numbers are impure by definition.
var randN = R.converge(R.partial, [R.wrap(R.pipe(R.converge(R.multiply, [Math.random, R.identity]), Math.floor), R.identity), R.of])
var rand10 = randN(10)
alert(R.times(rand10, 10)) // => [3, 1, 7, 5, 7, 5, 8, 4, 7, 2]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.19.1/ramda.js"></script>

How to initialize an array's length in JavaScript?

Most of the tutorials that I've read on arrays in JavaScript (including w3schools and devguru) suggest that you can initialize an array with a certain length by passing an integer to the Array constructor using the var test = new Array(4); syntax.
After using this syntax liberally in my js files, I ran one of the files through jsLint, and it freaked out:
Error: Problem at line 1 character 22: Expected ')' and instead saw '4'.
var test = new Array(4);
Problem at line 1 character 23: Expected ';' and instead saw ')'.
var test = new Array(4);
Problem at line 1 character 23: Expected an identifier and instead saw ')'.
After reading through jsLint's explanation of its behavior, it looks like jsLint doesn't really like the new Array() syntax, and instead prefers [] when declaring arrays.
So I have a couple questions:
First, why? Am I running any risk by using the new Array() syntax instead? Are there browser incompatibilities that I should be aware of?
And second, if I switch to the square bracket syntax, is there any way to declare an array and set its length all on one line, or do I have to do something like this:
var test = [];
test.length = 4;
Array(5) gives you an array with length 5 but no values, hence you can't iterate over it.
Array.apply(null, Array(5)).map(function () {}) gives you an array with length 5 and undefined as values, now it can be iterated over.
Array.apply(null, Array(5)).map(function (x, i) { return i; }) gives you an array with length 5 and values 0,1,2,3,4.
Array(5).forEach(alert) does nothing, Array.apply(null, Array(5)).forEach(alert) gives you 5 alerts
ES6 gives us Array.from so now you can also use Array.from(Array(5)).forEach(alert)
If you want to initialize with a certain value, these are good to knows...
Array.from('abcde'), Array.from('x'.repeat(5))
or Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]
With ES2015 .fill() you can now simply do:
// `n` is the size you want to initialize your array
// `0` is what the array will be filled with (can be any other value)
Array(n).fill(0)
Which is a lot more concise than Array.apply(0, new Array(n)).map(i => value)
It is possible to drop the 0 in .fill() and run without arguments, which will fill the array with undefined. (However, this will fail in Typescript)
Why do you want to initialize the length? Theoretically there is no need for this. It can even result in confusing behavior, because all tests that use the length to find out whether an array is empty or not will report that the array is not empty.
Some tests show that setting the initial length of large arrays can be more efficient if the array is filled afterwards, but the performance gain (if any) seem to differ from browser to browser.
jsLint does not like new Array() because the constructer is ambiguous.
new Array(4);
creates an empty array of length 4. But
new Array('4');
creates an array containing the value '4'.
Regarding your comment: In JS you don't need to initialize the length of the array. It grows dynamically. You can just store the length in some variable, e.g.
var data = [];
var length = 5; // user defined length
for(var i = 0; i < length; i++) {
data.push(createSomeObject());
}
[...Array(6)].map(x => 0);
// [0, 0, 0, 0, 0, 0]
OR
Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]
Note: you can't loop empty slots i.e. Array(4).forEach(() => …)
OR
( typescript safe )
Array(6).fill(null).map((_, i) => i);
// [0, 1, 2, 3, 4, 5]
OR
Classic method using a function ( works in any browser )
function NewArray(size) {
var x = [];
for (var i = 0; i < size; ++i) {
x[i] = i;
}
return x;
}
var a = NewArray(10);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Creating nested arrays
When creating a 2D array with the fill intuitively should create new instances. But what actually going to happen is the same array will be stored as a reference.
var a = Array(3).fill([6]);
// [ [6], [6], [6] ]
a[0].push(9);
// [ [6, 9], [6, 9], [6, 9] ]
Solution
var a = [...Array(3)].map(x => []);
a[0].push(4, 2);
// [ [4, 2], [], [] ]
So a 3x2 Array will look something like this:
[...Array(3)].map(x => Array(2).fill(0));
// [ [0, 0], [0, 0], [0, 0] ]
N-dimensional array
function NArray(...dimensions) {
var index = 0;
function NArrayRec(dims) {
var first = dims[0], next = dims.slice().splice(1);
if(dims.length > 1)
return Array(dims[0]).fill(null).map((x, i) => NArrayRec(next ));
return Array(dims[0]).fill(null).map((x, i) => (index++));
}
return NArrayRec(dimensions);
}
var arr = NArray(3, 2, 4);
// [ [ [ 0, 1, 2, 3 ] , [ 4, 5, 6, 7] ],
// [ [ 8, 9, 10, 11] , [ 12, 13, 14, 15] ],
// [ [ 16, 17, 18, 19] , [ 20, 21, 22, 23] ] ]
Initialize a chessboard
var Chessboard = [...Array(8)].map((x, j) => {
return Array(8).fill(null).map((y, i) => {
return `${String.fromCharCode(65 + i)}${8 - j}`;
});
});
// [ [A8, B8, C8, D8, E8, F8, G8, H8],
// [A7, B7, C7, D7, E7, F7, G7, H7],
// [A6, B6, C6, D6, E6, F6, G6, H6],
// [A5, B5, C5, D5, E5, F5, G5, H5],
// [A4, B4, C4, D4, E4, F4, G4, H4],
// [A3, B3, C3, D3, E3, F3, G3, H3],
// [A2, B2, C2, D2, E2, F2, G2, H2],
// [A1, B1, C1, D1, E1, F1, G1, H1] ]
Math filled values
handy little method overload when working with math
function NewArray( size , method, linear )
{
method = method || ( i => i );
linear = linear || false;
var x = [];
for( var i = 0; i < size; ++i )
x[ i ] = method( linear ? i / (size-1) : i );
return x;
}
NewArray( 4 );
// [ 0, 1, 2, 3 ]
NewArray( 4, Math.sin );
// [ 0, 0.841, 0.909, 0.141 ]
NewArray( 4, Math.sin, true );
// [ 0, 0.327, 0.618, 0.841 ]
var pow2 = ( x ) => x * x;
NewArray( 4, pow2 );
// [ 0, 1, 4, 9 ]
NewArray( 4, pow2, true );
// [ 0, 0.111, 0.444, 1 ]
The shortest:
let arr = [...Array(10)];
console.log(arr);
ES6 introduces Array.from which lets you create an Array from any "array-like" or iterables objects:
Array.from({length: 10}, (x, i) => i);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In this case {length: 10} represents the minimal definition of an "array-like" object: an empty object with just a length property defined.
Array.from allows for a second argument to map over the resulting array.
Sparse arrays are here! 🥳 [2021]
In modern JS engines, sparse arrays are fully supported. You can use [] or new Array(len) in any way you like, even with random access. Dictionary mode seems to be a thing of the past.
In current Chrome (and I guess any V8 environment), Arrays can have a length of up to 2^32-1 and allocation is sparse (meaning empty chunks don't use up any memory):
However, there is a catch
On the one hand, for loops work as intended, however, Array's builtin higher order functions (such as map, filter, find, some etc.) ignore unassigned elements. They require fill (or some other method of population) first:
const a = new Array(10);
const b = new Array(10).fill(0);
a.forEach(x => console.log(x)); // does nothing
b.forEach(x => console.log(x)); // works as intended
Old Version
(I removed most of the old version.) The gist was that creating a large array using new Array(largeNumber) or random accessing an array in places that have not yet been allocated would tumble it into "dictionary mode". Meaning you are using an array with indexes, but under the hood it would use a dictionary to store the values, thus messing with performance, and also with iteration behavior. Luckily that is a thing of the past.
This will initialize the length property to 4:
var x = [,,,,];
I'm surprised there hasn't been a functional solution suggested that allows you to set the length in one line. The following is based on UnderscoreJS:
var test = _.map(_.range(4), function () { return undefined; });
console.log(test.length);
For reasons mentioned above, I'd avoid doing this unless I wanted to initialize the array to a specific value. It's interesting to note there are other libraries that implement range including Lo-dash and Lazy, which may have different performance characteristics.
Here is another solution
var arr = Array.apply( null, { length: 4 } );
arr; // [undefined, undefined, undefined, undefined] (in Chrome)
arr.length; // 4
The first argument of apply() is a this object binding, which we don't care about here, so we set it to null.
Array.apply(..) is calling the Array(..) function and spreading out the { length: 3 } object value as its arguments.
Please people don't give up your old habits just yet.
There is a large difference in speed between allocating memory once then working with the entries in that array (as of old), and allocating it many times as an array grows (which is inevitably what the system does under the hood with other suggested methods).
None of this matters of course, until you want to do something cool with larger arrays. Then it does.
Seeing as there still seems to be no option in JS at the moment to set the initial capacity of an array, I use the following...
var newArrayWithSize = function(size) {
this.standard = this.standard||[];
for (var add = size-this.standard.length; add>0; add--) {
this.standard.push(undefined);// or whatever
}
return this.standard.slice(0,size);
}
There are tradeoffs involved:
This method takes as long as the others for the first call to the function, but very little time for later calls (unless asking for a bigger array).
The standard array does permanently reserve as much space as the largest array you have asked for.
But if it fits with what you're doing there can be a payoff.
Informal timing puts
for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}
at pretty speedy (about 50ms for the 10000 given that with n=1000000 it took about 5 seconds), and
for (var n=10000;n>0;n--) {
var b = [];for (var add=10000;add>0;add--) {
b.push(undefined);
}
}
at well over a minute (about 90 sec for the 10000 on the same chrome console, or about 2000 times slower).
That won't just be the allocation, but also the 10000 pushes, for loop, etc..
(this was probably better as a comment, but got too long)
So, after reading this I was curious if pre-allocating was actually faster, because in theory it should be. However, this blog gave some tips advising against it http://www.html5rocks.com/en/tutorials/speed/v8/.
So still being unsure, I put it to the test. And as it turns out it seems to in fact be slower.
var time = Date.now();
var temp = [];
for(var i=0;i<100000;i++){
temp[i]=i;
}
console.log(Date.now()-time);
var time = Date.now();
var temp2 = new Array(100000);
for(var i=0;i<100000;i++){
temp2[i] = i;
}
console.log(Date.now()-time);
This code yields the following after a few casual runs:
$ node main.js
9
16
$ node main.js
8
14
$ node main.js
7
20
$ node main.js
9
14
$ node main.js
9
19
var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6
The simplest form is to use
Array.from({ length: 3 });
// gives you
[undefined, undefined, undefined]
Unlike Array(3) which will give you an array you can't iterate over. Array.from({ length }) gives you an array you can iterate easily.
Array.from({ length: 3 }).map((e, idx) => `hi ${idx}`);
// ['hi 1', 'hi 2', 'hi 3']
Assuming that Array's length is constant. In Javascript, This is what we do:
const intialArray = new Array(specify the value);
The array constructor has an ambiguous syntax, and JSLint just hurts your feelings after all.
Also, your example code is broken, the second var statement will raise a SyntaxError. You're setting the property length of the array test, so there's no need for another var.
As far as your options go, array.length is the only "clean" one. Question is, why do you need to set the size in the first place? Try to refactor your code to get rid of that dependency.
In addition to the answers of others, another clever way is to use Float32Array to create an array and iterate on it.
For this purpose, create an instance from Float32Array with your desired length like this:
new Float32Array(5)
This code returns an array-like that you can convert it to an array with Array.from():
Array.from(new Float32Array(5)) // [0, 0, 0, 0, 0]
You can also use fill() to change the value of items:
Array.from(new Float32Array(5).fill(2)) // [2, 2, 2, 2, 2]
And of course you can iterate on it:
Array.from(new Float32Array(5)).map(item => /* ... */ )
In most answers it is recommended to fill the array because otherwise "you can't iterate over it", but this is not true. You can iterate an empty array, just not with forEach. While loops, for of loops and for i loops work fine.
const count = Array(5);
Does not work.
console.log('---for each loop:---');
count.forEach((empty, index) => {
console.log(`counting ${index}`);
});
These work:
console.log('---for of loop:---');
for (let [index, empty] of count.entries()) {
console.log(`counting for of loop ${index}`);
}
console.log('---for i loop:---');
for (let i = 0, il = count.length; i < il; ++i) {
console.log(`counting for i loop ${i}`);
}
console.log('---while loop:---');
let index = 0;
while (index < count.length) {
console.log(`counting while loop ${index}`);
index++;
}
Check this fiddle with the above examples.
Also angulars *ngFor works fine with an empty array:
<li *ngFor="let empty of count; let i = index" [ngClass]="
<span>Counting with *ngFor {{i}}</span>
</li>
You can set the array length by using array.length = youValue
So it would be
var myArray = [];
myArray.length = yourValue;
The reason you shouldn't use new Array is demonstrated by this code:
var Array = function () {};
var x = new Array(4);
alert(x.length); // undefined...
Some other code could mess with the Array variable. I know it's a bit far fetched that anyone would write such code, but still...
Also, as Felix King said, the interface is a little inconsistent, and could lead to some very difficult-to-track-down bugs.
If you wanted an array with length = x, filled with undefined (as new Array(x) would do), you could do this:
var x = 4;
var myArray = [];
myArray[x - 1] = undefined;
alert(myArray.length); // 4

Categories

Resources