I'm currently learning javascript and I would appreciate some help.
I've been playing around trying to create a program that would multiply two numbers without using the * operator. I already found an easier way to do it than my approach but I'd like to know why the code I wrote doesn't work:
function addToItself(a) {
a = a + a;
return a;
}
function times(b) {
for (count = 0; count < b; count++) {
addToItself(a)
}
return a;
}
function multiply (x, y) {
a = x;
times(y);
}
let output = multiply(5, 2);
alert(output);
Is it not working because the binding "a" in the addToItself function has a local scope and the multiply function can't read it or is it something else?
Thanks a lot in advance!
The issue is with the scope of each variable. In JavaScript, a variable declated within a function is scoped to that function. This means that a variable declared within a function can only be accessed within the function. Scopes are nested, so a variable declared globally is accessible inside a function too, though that's often discouraged.
Additionally, function arguments (such as a in addToItself and b in times) are treated like variables scoped to the function.
I would advise looking at the MDN docs for "scope" and familiarizing yourself with how variables are scoped in JavaScript.
I have included a fixed version of your code is below, for reference:
function addToItself(a) {
// I used a new variable here since reassigning to an argument is discouraged
const twoA = a + a;
return twoA;
}
console.log('5 + 5 = ' + addToItself(5));
function times(value, times) {
let temp = 0;
for (let count = 0; count < times; count++) {
temp += value;
}
return temp;
};
console.log('5 * 5 = ' + times(5, 5));
No you can't read variable inside another function, there are easier way, like
function multiply(x, y) {
var result = 0;
for (var count = 0; count < y; count++) {
result += x
}
return result;
}
console.log("5 * 2 = " + multiply(5, 2));
I have two javascript closures and I'm trying to understand why one will accept and input with a particular syntax and the other will reject.
function multiply(factor) {
var ace = (function(number) {
return number*factor;
});
return ace;
}
var yup = multiply(4);
console.log(yup(5));
This outputs 20 to the console as it should.
The second Closure I have is
var k = 3;
var add = (function () {
console.log(k);
var counter = k;
return function (j) {counter += 1; return counter*j}
})(k);
add();
console.log(add(5));
The output is 20 as it should be.
This issue I'm having that if I try to use the syntax of
(function() {
})(number);
In the first closure it does not work and outputs "number is not defined"
And if I try to input into the second closure
(function (k) {
var counter = k;
return function (j) {counter += 1; return counter*j}
});
I get out
function (j) {counter += 1; return counter*j}
to the console.
My question is, what am I not understanding about closers the () at the end of them.
The difference is whether you are creating the closure right away through an IIFE, or a function that makes the closure when called.
Your first snippet written in the second style would be
var yup = (function multiply(factor) {
return function ace(number) {
return number*factor;
};
})(4); // the multiply(4) call is inlined into the statement with the definition
console.log(yup(5));
Your second snippet written in the first style would be
function makeAdd(k) {
console.log(k);
var counter = k;
return function (j) {
counter += 1;
return counter*j;
}
}
var add = makeAdd(3);
add();
console.log(add(5));
JSHint shows the error:
"Function declared within loop referencing an outer scope variable may lead to confusing semantics".
How can I improve the following code to get rid of the warning?
var getPrecedence = function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(function (item) {
return item === operator;
});
if (check) return operators[keys[i]][operator];
}
};
You are supposed not to use the function expression inside the loop body, but instead declare it outside:
function getPrecedence(operator, operators) {
function isOperator(item) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
return item === operator;
}
var keys = Object.keys(Object(operators));
for (var i = 0, len = keys.length; i < len; i++) {
var check = Object.keys(operators[keys[i]]).some(isOperator);
// ^^^^^^^^^^
if (check) return operators[keys[i]][operator];
}
}
Of course the whole thing could be simplified by just using includes instead of some, and find instead of the loop:
function getPrecedence(operator, operators) {
var keys = Object.keys(Object(operators));
var opkey = keys.find(key =>
Object.keys(operators[key]).includes(operator)
);
if (opkey) return operators[opkey][operator];
}
And finally, Object.keys(…).includes(…) can be simplified to operator in operators[key].
Add it before calling the function, this one will bypass that check
/* jshint -W083 */
Regardless of functional differences, does using the new keywords 'let' and 'const' have any generalized or specific impact on performance relative to 'var'?
After running the program:
function timeit(f, N, S) {
var start, timeTaken;
var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
var i;
for (i = 0; i < S; ++i) {
start = Date.now();
f(N);
timeTaken = Date.now() - start;
stats.min = Math.min(timeTaken, stats.min);
stats.max = Math.max(timeTaken, stats.max);
stats.sum += timeTaken;
stats.sqsum += timeTaken * timeTaken;
stats.N++
}
var mean = stats.sum / stats.N;
var sqmean = stats.sqsum / stats.N;
return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}
var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;
function varAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += variable1;
sum += variable2;
sum += variable3;
sum += variable4;
sum += variable5;
sum += variable6;
sum += variable7;
sum += variable8;
sum += variable9;
sum += variable10;
}
return sum;
}
const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;
function constAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += constant1;
sum += constant2;
sum += constant3;
sum += constant4;
sum += constant5;
sum += constant6;
sum += constant7;
sum += constant8;
sum += constant9;
sum += constant10;
}
return sum;
}
function control(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
}
return sum;
}
console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));
.. My results were the following:
ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}
However discussion as noted here seems to indicate a real potential for performance differences under certain scenarios: https://esdiscuss.org/topic/performance-concern-with-let-const
TL;DR
In theory, an unoptimized version of this loop:
for (let i = 0; i < 500; ++i) {
doSomethingWith(i);
}
might be slower than an unoptimized version of the same loop with var:
for (var i = 0; i < 500; ++i) {
doSomethingWith(i);
}
because a different i variable is created for each loop iteration with let, whereas there's only one i with var.
Arguing against that is the fact the var is hoisted so it's declared outside the loop whereas the let is only declared within the loop, which may offer an optimization advantage.
In practice, here in 2018, modern JavaScript engines do enough introspection of the loop to know when it can optimize that difference away. (Even before then, odds are your loop was doing enough work that the additional let-related overhead was washed out anyway. But now you don't even have to worry about it.)
Beware synthetic benchmarks as they are extremely easy to get wrong, and trigger JavaScript engine optimizers in ways that real code doesn't (both good and bad ways). However, if you want a synthetic benchmark, here's one:
const now = typeof performance === "object" && performance.now
? performance.now.bind(performance)
: Date.now.bind(Date);
const btn = document.getElementById("btn");
btn.addEventListener("click", function() {
btn.disabled = true;
runTest();
});
const maxTests = 100;
const loopLimit = 50000000;
const expectedX = 1249999975000000;
function runTest(index = 1, results = {usingVar: 0, usingLet: 0}) {
console.log(`Running Test #${index} of ${maxTests}`);
setTimeout(() => {
const varTime = usingVar();
const letTime = usingLet();
results.usingVar += varTime;
results.usingLet += letTime;
console.log(`Test ${index}: var = ${varTime}ms, let = ${letTime}ms`);
++index;
if (index <= maxTests) {
setTimeout(() => runTest(index, results), 0);
} else {
console.log(`Average time with var: ${(results.usingVar / maxTests).toFixed(2)}ms`);
console.log(`Average time with let: ${(results.usingLet / maxTests).toFixed(2)}ms`);
btn.disabled = false;
}
}, 0);
}
function usingVar() {
const start = now();
let x = 0;
for (var i = 0; i < loopLimit; i++) {
x += i;
}
if (x !== expectedX) {
throw new Error("Error in test");
}
return now() - start;
}
function usingLet() {
const start = now();
let x = 0;
for (let i = 0; i < loopLimit; i++) {
x += i;
}
if (x !== expectedX) {
throw new Error("Error in test");
}
return now() - start;
}
<input id="btn" type="button" value="Start">
It says that there's no significant difference in that synthetic test on either V8/Chrome or SpiderMonkey/Firefox. (Repeated tests in both browsers have one winning, or the other winning, and in both cases within a margin of error.) But again, it's a synthetic benchmark, not your code. Worry about the performance of your code when and if your code has a performance problem.
As a style matter, I prefer let for the scoping benefit and the closure-in-loops benefit if I use the loop variable in a closure.
Details
The important difference between var and let in a for loop is that a different i is created for each iteration; it addresses the classic "closures in loop" problem:
function usingVar() {
for (var i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("var's i: " + i);
}, 0);
}
}
function usingLet() {
for (let i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("let's i: " + i);
}, 0);
}
}
usingVar();
setTimeout(usingLet, 20);
Creating the new EnvironmentRecord for each loop body (spec link) is work, and work takes time, which is why in theory the let version is slower than the var version.
But the difference only matters if you create a function (closure) within the loop that uses i, as I did in that runnable snippet example above. Otherwise, the distinction can't be observed and can be optimized away.
Here in 2018, it looks like V8 (and SpiderMonkey in Firefox) is doing sufficient introspection that there's no performance cost in a loop that doesn't make use of let's variable-per-iteration semantics. See this test.
In some cases, const may well provide an opportunity for optimization that var wouldn't, especially for global variables.
The problem with a global variable is that it's, well, global; any code anywhere could access it. So if you declare a variable with var that you never intend to change (and never do change in your code), the engine can't assume it's never going to change as the result of code loaded later or similar.
With const, though, you're explicitly telling the engine that the value cannot change¹. So it's free to do any optimization it wants, including emitting a literal instead of a variable reference to code using it, knowing that the values cannot be changed.
¹ Remember that with objects, the value is a reference to the object, not the object itself. So with const o = {}, you could change the state of the object (o.answer = 42), but you can't make o point to a new object (because that would require changing the object reference it contains).
When using let or const in other var-like situations, they're not likely to have different performance. This function should have exactly the same performance whether you use var or let, for instance:
function foo() {
var i = 0;
while (Math.random() < 0.5) {
++i;
}
return i;
}
It's all, of course, unlikely to matter and something to worry about only if and when there's a real problem to solve.
"LET" IS BETTER IN LOOP DECLARATIONS
With a simple test (5 times) in navigator like that:
// WITH VAR
console.time("var-time")
for(var i = 0; i < 500000; i++){}
console.timeEnd("var-time")
The mean time to execute is more than 2.5ms
// WITH LET
console.time("let-time")
for(let i = 0; i < 500000; i++){}
console.timeEnd("let-time")
The mean time to execute is more than 1.5ms
I found that loop time with let is better.
T.J. Crowder's answer is so excellent.
Here is an addition of: "When would I get the most bang for my buck on editing existing var declarations to const ?"
I've found that the most performance boost had to do with "exported" functions.
So if file A, B, R, and Z are calling on a "utility" function in file U that is commonly used through your app, then switching that utility function over to "const" and the parent file reference to a const can eak out some improved performance. It seemed for me that it wasn't measurably faster, but the overall memory consumption was reduced by about 1-3% for my grossly monolithic Frankenstein-ed app. Which if you're spending bags of cash on the cloud or your baremetal server, could be a good reason to spend 30 minutes to comb through and update some of those var declarations to const.
I realize that if you read into how const, var, and let work under the covers you probably already concluded the above... but in case you "glanced" over it :D.
From what I remember of the benchmarking on node v8.12.0 when I was making the update, my app went from idle consumption of ~240MB RAM to ~233MB RAM.
T.J. Crowder's answer is very good but :
'let' is made to make code more readable, not more powerful
by theory let will be slower than var
by practice the compiler can not solve completely (static analysis) an uncompleted program so sometime it will miss the optimization
in any-case using 'let' will require more CPU for introspection, the bench must be started when google v8 starts to parse
if introspection fails 'let' will push hard on the V8 garbage collector, it will require more iteration to free/reuse. it will also consume more RAM. the bench must take these points into account
Google Closure will transform let in var...
The effect of the performance gape between var and let can be seen in real-life complete program and not on a single basic loop.
Anyway, to use let where you don't have to, makes your code less readable.
Just did some more tests, Initially I concluded that there is a substantial difference in favor of var. My results initially showed that between Const / Let / Var there was a ratio from 4 / 4 / 1 to 3 / 3 / 1 in execution time.
After Edit in 29/01/2022 (according to jmrk's remark to remove global variables in let and const tests) now results seem similar 1 / 1 / 1.
I give the code used below. Just let me mention that I started from the code of AMN and did lots of tweaking, and editing.
I did the tests both in w3schools_tryit editor and in Google_scripts
My Notes:
In GoogleScripts there seems that the 1st test ALWAYS takes longer, no-matter which one, especially for reps<5.000.000 and before separating them in individual functions
For Reps < 5.000.000 JS engine optimizations are all that matters, results go up and down without safe conclusions
GoogleScripts constantly does ~1.5x time longer, I think it is expected
There was a BIG difference when all tests where separated in individual functions, execution speed was at-least doubled and 1st test's delay almost vanished!
Please don't judge the code, I did try but don't pretend to be any expert in JS.
I would be delighted to see your tests and opinions.
function mytests(){
var start = 0;
var tm1=" Const: ", tm2=" Let: ", tm3=" Var: ";
start = Date.now();
tstLet();
tm2 += Date.now() - start;
start = Date.now();
tstVar();
tm3 += Date.now() - start;
start = Date.now();
tstConst();
tm1 += (Date.now() - start);
var result = "TIMERS:" + tm1 + tm2 + tm3;
console.log(result);
return result;
}
// with VAR
function tstVar(){
var lmtUp = 50000000;
var i=0;
var item = 2;
var sum = 0;
for(i = 0; i < lmtUp; i++){sum += item;}
item = sum / 1000;
}
// with LET
function tstLet(){
let lmtUp = 50000000;
let j=0;
let item = 2;
let sum=0;
for( j = 0; j < lmtUp; j++){sum += item;}
item = sum/1000;
}
// with CONST
function tstConst(){
const lmtUp = 50000000;
var k=0;
const item = 2;
var sum=0;
for( k = 0; k < lmtUp; k++){sum += item;}
k = sum / 1000;
}
code with 'let' will be more optimized than 'var' as variables declared with var do not get cleared when the scope expires but variables declared with let does. so var uses more space as it makes different versions when used in a loop.
I have a question to a specific behavior of javascript:
I have an object which I want to fill with generated functions. Each function contains a variable which is changed during the loop of function generation.
My problem is that the variable does not get replaced when assigning the function to the object. Instead the reference to the variable stays in the function and when executing the function only the last value of the variable is remembered.
Here is a minimal example (also on jsfiddle: http://jsfiddle.net/2FN6K/):
var obj = {};
for (var i = 0; i < 10; i++){
var nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
for (var x = 0; x < 10; x++){
obj[x]();
}
The second loop executes all generated functions and all print a 9 as result. But i want that they print the value which the variable had at the time of generation (0, 1, 2, ...).
Is there a way to do this? Thanks in advance.
One approach is to call a function that returns a function:
function makeFunc(i) {
return function() {
console.log("result: " + i);
}
}
for (...) {
obj[i] = makeFunc(i);
}
Another approach is the immediately invoked function expression:
for (i = 0; ...; ...) {
(function(i) {
obj[i] = function() {
console.log("result: " + i);
}
})(i);
}
where in the latter case the (function(i) ... )(i) results in a permanent binding of i passed as a parameter to the outer function within the scope of the inner function
The problem is that all the functions you create are sharing a reference to the same nr variable. When you call them they fetch the value using that reference and therefore all of them get the same result.
Solve it like this:
for (var i = 0; i < 10; i++){
(function(nr) {
obj[nr] = function(){
console.log("result: " + nr);
}
})(i);
}
Your surmise is correct, and yes, there's a solution:
obj[i] = function( nr_copy ) {
return function() {
console.log("result: " + nr_copy);
};
}( nr );
JavaScript variables are scoped at the function level, unlike some other block-structured languages. That is, the fact that you declare "nr" inside the for loop doesn't make it "local" to that block — the effect is precisely the same as if you'd declared it at the top of the function.
By introducing another function scope with that anonymous function, you make a new copy of the value of "nr", which is then privately accessible to the actual function that's returned. Each of those functions will have it's own copy of the value of "nr" as it stood when that slot of the "obj" array was initialized.
what you want is to create a closure for every function you create.
Yet, the var(s) have not a block scope, so your code is the same as :
var obj = {};
var i;
var nr;
for (i = 0; i < 10; i++){
nr = i;
obj[i] = function(){
console.log("result: " + nr);
}
}
which hopefully makes it more obvious all functions will refer to the very same 'nr' var.
What you want to do implies creating a new scope each time, which might be done using bind, but let's stick to your original intent and build a new closure each time with a lambda :
var obj = {};
for (var i = 0; i < 10; i++) {
obj[i] = (function(){
var this_nr = i;
return function(){
console.log("result: " + this_nr);
}
}() );
}