Open utterances-bot opened 3 years ago
Questions 5
for log function to return need incremented value we need to put message variable in the body of log function
function log() {
let message = `Count is ${count}`;
console.log(message);
}
so on every (log) function call a new message variable will be created with latest modification of count
variable from outer scope.
Question 4
for (var i = 0; i < 3; i++) {
setTimeout(function log(j) {
console.log(j); // What is logged?
}, 1000, i);
}
Thanks a lot for such useful posts!
Questions 5
for log function to return need incremented value we need to put message variable in the body of log function
That's the solution @noidar. Thanks for sharing.
Question 4
for (var i = 0; i < 3; i++) { setTimeout(function log(j) { console.log(j); // What is logged? }, 1000, i); }
Yes, that's a good fix.
Thanks a lot for such useful posts!
You're welcome @nodm!
for(let i=0; ....) will resolve scoping issue
for(let i=0; ....) will resolve scoping issue
Yes, that's the right fix.
In Javascript, an argument can hold a value of another argument. So it can be done like this:
function multiply(num1, num2 = num1) {
return num1 * num2;
}
7
In Javascript, an argument can hold a value of another argument. So it can be done like this:
function multiply(num1, num2 = num1) { return num1 * num2; }
Nope, it won't work.
7
In Javascript, an argument can hold a value of another argument. So it can be done like this:
function multiply(num1, num2 = num1) { return num1 * num2; }
Nope, it won't work.
Sorry. I didn't read the question well :)) Just wanted to give some solutions.
Question 5 : rewrite log
method
function log() {
console.log(Count is ${count}
);
}
question 5
set count as parameter, we know clousres "remembers" parameters
function createIncrement(count = 0) {
function increment() {
count++;
}
function log() {
console.log(`Count is ${count}`);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // What is logged?
question 6:
There is no way to directly modify items array because this approach below is exposing only an API to modify an initial array exisiting with const stack = createStack(); so right after this you can only use push or pop. if you want to modify the items directly you would need to create another "instance" or scope with createStack and that's another "row".
function createStack (items= []) {
function push (par) {
items.push(par);
}
function pop () {
items.pop();
}
function checkItems(){
console.log(`items status: ${items}`)
}
return { push, pop, checkItems}
}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop();
stack.checkItems()
const createIncrement=(c=0)=>[_=>c++,_=>console.log("Count is "+c)];
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // What is logged?
no second param? ok then return a closure remembering the first argument and expecting to multiply with a second one the second call. to avoid NaN value just default to 1 if there is not num2 param... again...
function multiply(num1, num2= null) {
if (!num2) return num2 => num1 * (num2 || 1)
return num1 * num2
}
const n1 = multiply(2, 2);
const n2 = multiply(3)
console.log(n1, n2(5))
thanks a lot for this post, didnt think i would get nailed into this. greetings from Colombia :colombia:
const multiply = (a , b = c => a * c ) => typeof b == 'function' ? b : a * b;
multiply(4,5)
multiply(3,3)
const double = multiply(2);
double(5);
double(11);
class saveArray extends Array {
get items() {
console.log("You can't access the items!");
}
set items(value){
console.log("I said! You can't access the items! And use modern ES code!");
}
}
const stack = new saveArray();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
stack.items; // => undefined
question 5
set count as parameter, we know clousres "remembers" parameters
function createIncrement(count = 0) { function increment() { count++; } function log() { console.log(`Count is ${count}`); } return [increment, log]; } const [increment, log] = createIncrement(); increment(); increment(); increment(); log(); // What is logged?
There's no need to make count
a parameter: that's not the main problem. Either way, using console.log(`Count is ${count}`);
is a good solution too.
question 6:
There is no way to directly modify items array because this approach below is exposing only an API to modify an initial array exisiting with const stack = createStack(); so right after this you can only use push or pop. if you want to modify the items directly you would need to create another "instance" or scope with createStack and that's another "row".
function createStack (items= []) { function push (par) { items.push(par); } function pop () { items.pop(); } function checkItems(){ console.log(`items status: ${items}`) } return { push, pop, checkItems} } const stack = createStack(); stack.push(10); stack.push(5); stack.pop(); stack.checkItems()
Yes, your solution doesn't expose the stack.items
.
However, your implementation still has a broken encapsulation: I can modify items
array through the argument. For example:
function createStack(items = []) {
function push(par) {
items.push(par);
}
function pop() {
return items.pop();
}
function checkItems() {
console.log(`items status: ${items}`)
}
return { push, pop, checkItems }
}
const items = [];
const stack = createStack(items);
stack.push(10);
stack.push(5);
// Hack the items! Broken encapsulation!
items.length = 1;
console.log(stack.pop()); // returns 10 instead of 5
stack.checkItems()
I can still modify items
directly, for example I cut the number of items items.length = 1
, thus breaking the encapsulation of the stack.
no second param? ok then return a closure remembering the first argument and expecting to multiply with a second one the second call. to avoid NaN value just default to 1 if there is not num2 param... again...
function multiply(num1, num2= null) { if (!num2) return num2 => num1 * (num2 || 1) return num1 * num2 } const n1 = multiply(2, 2); const n2 = multiply(3) console.log(n1, n2(5))
Your solution doesn't work if the second argument is 0
:
function multiply(num1, num2 = null) {
if (!num2) return num2 => num1 * (num2 || 1)
return num1 * num2
}
console.log(multiply(5, 0)); // logs a function instead of 0
thanks a lot for this post, didnt think i would get nailed into this. greetings from Colombia
You're welcome!
no second param? ok then return a closure remembering the first argument and expecting to multiply with a second one the second call. to avoid NaN value just default to 1 if there is not num2 param... again...
function multiply(num1, num2= null) { if (!num2) return num2 => num1 * (num2 || 1) return num1 * num2 } const n1 = multiply(2, 2); const n2 = multiply(3) console.log(n1, n2(5))
Your solution doesn't work if the second argument is
0
:function multiply(num1, num2 = null) { if (!num2) return num2 => num1 * (num2 || 1) return num1 * num2 } console.log(multiply(5, 0)); // logs a function instead of 0
thanks a lot for this post, didnt think i would get nailed into this. greetings from Colombia
You're welcome!
just forgot 0 evaluate to fasly
function multiply(num1, num2= null) {
if (!num2 && num2 !== 0) return num2 => num1 * (num2 || 1)
return num1 * num2
}
question 6: There is no way to directly modify items array because this approach below is exposing only an API to modify an initial array exisiting with const stack = createStack(); so right after this you can only use push or pop. if you want to modify the items directly you would need to create another "instance" or scope with createStack and that's another "row".
function createStack (items= []) { function push (par) { items.push(par); } function pop () { items.pop(); } function checkItems(){ console.log(`items status: ${items}`) } return { push, pop, checkItems} } const stack = createStack(); stack.push(10); stack.push(5); stack.pop(); stack.checkItems()
Yes, your solution doesn't expose the
stack.items
.However, your implementation still has a broken encapsulation: I can modify
items
array through the argument. For example:function createStack(items = []) { function push(par) { items.push(par); } function pop() { return items.pop(); } function checkItems() { console.log(`items status: ${items}`) } return { push, pop, checkItems } } const items = []; const stack = createStack(items); stack.push(10); stack.push(5); // Hack the items! Broken encapsulation! items.length = 1; console.log(stack.pop()); // returns 10 instead of 5 stack.checkItems()
I can still modify
items
directly, for example I cut the number of itemsitems.length = 1
, thus breaking the encapsulation of the stack.function createStack(items = []) { const noRefItems = [...items]; function push(par) { noRefItems.push(par); }
function pop() { return noRefItems.pop(); }
function checkItems() {
console.log(items status: ${noRefItems}
)
}
return { push, pop, checkItems } }
const items = []; const stack = createStack(items);
stack.push(10); stack.push(5);
// Hack the items! Broken encapsulation! items.length = 1;
console.log(stack.pop()); // returns 10 instead of 5
stack.checkItems()
there you go. the problem: modification by reference, solution: mutation avoidance by spread only value cloning
Question:4->
for(let i=0;i<3;i++){ setTimeout(function log(){ console.log(i) },1000); }
First solution of #4 that came to my mind:
for (var i = 0; i < 3; i++) {
setTimeout((function log(x) {
console.log(x);
})(i), 1000);
}
First solution of #4 that came to my mind:
for (var i = 0; i < 3; i++) { setTimeout((function log(x) { console.log(x); })(i), 1000); }
@omachala Your solution logs the numbers right away, but the numbers should be logged with a delay of 1 second.
Thank you for your challenges.
It's better to use let
but it was challenging to do it grandpa-style.
for (var i = 0; i < 3; i++) {
(function (x) {
setTimeout(function () {
console.log(x); // What is logged?
}, 1000);
})(i);
setTimeout(
(function (r) {
return function () {
console.log(r); // What is logged?
};
})(i),
1000
);
}
Too obvious.
Quite obvious too. And the best solution has been described already:
console.log("I said! You can't access the items! And use modern ES code!")
const multiply = (num1, num2) => (num2 !== undefined ? num1 * num2 : (n2) => num1 * n2);
"Questions 5 for log function to return need incremented value we need to put message variable in the body of log function That's the solution @noidar. Thanks for sharing." Are you sure @panzerdp ? I've tested it and it outputs : 'Count is 3' 'Count is 3' 'Count is 3'
Sorry, wrong question... please ignore my message above
Hi, thanks about this useful article.
I use bind method for multiply:
function multiply(num1, num2){ return num2 !== undefined ? num1 * num2 : multiply.bind(null, num1); }
Hi, thanks about this useful article.
Thanks @webdev-sulfur.
I use bind method for multiply:
function multiply(num1, num2){ return num2 !== undefined ? num1 * num2 : multiply.bind(null, num1); }
Looks good!
I removed message variable that won't store the count value at the beginning, instead directly read the count variable.
function createIncrement() {
let count = 0
function increment() {
count++;
}
function log() {
console.log(`Count is ${count}`);
}
return [increment, log];
}
const [increment, log] = createIncrement();
increment();
increment();
increment();
log(); // What is logged?
no new tricks but let's cut it even thinner =)
for (var i = 0; i < 3; i++) setTimeout(console.log, 1000, i);
or to round out other valid interview responses if candidate didn't remember setTimeout's full signature (i sure didn't =)
for (var i = 0; i < 3; i++) ((j) => setTimeout(() => console.log(j), 1000))(i);
Solution 5 :
function createIncrement() { let count = 0; let message = ''; function increment() { count++; message = `Count is ${count}`; } function log() { console.log(message); } return [increment, log]; }
FOR 4. QUESTION
var i = 0;
for (; i < 3; i++) {
setTimeout(
(function log(j) {
console.log(j); // What is logged?
})(i),
1000
);
}
FOR 4. QUESTION var i = 0; for (; i < 3; i++) { setTimeout( (function log(j) { console.log(j); // What is logged? })(i), 1000 ); }
I.... don't think this is doing what you think this is doing... You are actually doing
setTimeout(undefined, 1000);
3 times..
@WORMSS Didn't he want that ? app.js:4 0 app.js:4 1 app.js:4 2
@WORMSS Didn't he want that ? app.js:4 0 app.js:4 1 app.js:4 2
Up your timeout to 60000 (eg, 1 minute) and see how quickly your code does the console logs to see the problem with your code.
@WORMSS Didn't he want that ? app.js:4 0 app.js:4 1 app.js:4 2
@kadiryetisen Sorry, the question is a bit confusing. You have to log 0, 1, 2 with a delay of 1 second.
I have updated the question in the post to be more accurate.
@panzerdp @WORMSS oohh ok i've just understood. for (var i = 0; i < 3; i++) { function close(i) { setTimeout(() => { console.log(i); }, i * 1000); } close(i); } Is it true ?
@kadiryetisen that would work. by the way, you can use ```js my code ``` and you will keep formatting and highlighting
@WORMSS oh I got it , thanks :))
Questions 4: Tricky closure
for (var i = 0; i < 3; i++) {
;(lockedInIndex => {
setTimeout(function log() {
console.log(lockedInIndex) // What is logged?
}, 1000)
})(i) //used an IIFE inspired by http://benalman.com/news/2010/11/immediately-invoked-function-expression/
}
@pietow interesting that you mixed arrow functions with standard functions in such a small code snippet. Any reason you felt you had to do that?
As much as I love the setTimeout(func,time,arguments)
as mentioned above..
There is also the simple fix of just doing
for (var i = 0; i < 3; i++) {
const j = i;
setTimeout(function log() {
console.log(j); // What is logged?
}, 1000);
}
^^^^@WORMSS or better yet. Use let instead of var.
for (let i = 0; i < 3; i++) {
setTimeout(function log() {
console.log(i); // What is logged?
}, 1000);
}
Can anyone explain how does the below code work? I'm able to modify the item array even if it is private!
function createStack() {
const items = [];
return {
push(item) {
items.push(item);
},
pop() {
return items.pop();
}
};
}
const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5
console.log(stack.items) //undefined
stack.items = [12,13]
console.log(stack.items) // prints [12,13]
You are adding a new property to the object that has the { push() pop() } methods on.
Begginer here ...
Anyone care to explain why in Question 4) for(let i=0; ....) would resolve the problem?
I guet that Let is blockscoped, but if the log() is scheduled for execution after the 1000ms, and the for() cycle is completed by then, shouldn't read i = 3?
When will log() read 0 and 1?
Thanks in advance ! (and thanks for the article!)
Hey PuffCab!, Look into closures, that will give an insight of what is really going on under the hood of javascript... essentially you're passing a FUNCTION ( console.log() ) ENCLOSED/BUNLED-TOGETHER WITH ITS SURROUNDING STATE ( i ) aka LEXICAL ENVIRONMENT. This can only be achieved with let and const ( local-scoped ) vs var ( global-scoped ).
Hope this didnt confuse you, Just trying to help,
This is a great video about closures. Little long tho...but you will learn a lot. https://www.youtube.com/watch?v=ZVXrJ4dnUxM&t=5594s
Questions 4:
for (var i = 0; i < 3; i++) { setTimeout(log(i), 1000); }
function log(i) { console.log(i); // What is logged? }
Questions 4:
for (var i = 0; i < 3; i++) { setTimeout(log(i), 1000); }
function log(i) { console.log(i); // What is logged? }
try that again with 30000 (30 seconds) notice they appear immediately.
7 Interview Questions on JavaScript Closures. Can You Answer Them?
Can you answer these 7 interview questions on the closure concept in JavaScript?
https://dmitripavlutin.com/javascript-closures-interview-questions/