- Notifications
You must be signed in to change notification settings - Fork320
Embrace JavaScript naturally and confidently with coding challenges crafted not only for beginners but for JavaScript lovers, regardless of their level of expertise.
yeungon/In-JavaScript-we-trust
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
In JS we trust - The best way to learn is by building/coding and teaching. I create the challenges to help my friends learn JavaScript and in return it helps me embrace the language in much deeper level. Feel free to clone, fork and pull.
functiona(x){x++;returnfunction(){console.log(++x);};}a(1)();a(1)();a(1)();letx=a(1);x();x();x();
- A:
1, 2, 3
and1, 2, 3
- B:
3, 3, 3
and3, 4, 5
- C:
3, 3, 3
and1, 2, 3
- D:
1, 2, 3
and3, 3, 3
Answer
This question revisits closure - one of the most confusing concepts in JavaScript. Closure allows us to create astateful function
and such a function can access to the variable outside of its scope. In a nutshell, a closure can have access to theglobal
variable (scope),father function
scope andits
own scope.
We have here, the only one correct answer, 3, 3, 3 and 3, 4, 5 because first we simply call the functiona()
. It works like a normal function and we have not seen anything so-calledstateful
yet. In the following code, we declare a variablex
and it stores the value of functiona(1)
, that is why we get 3. 4. 5 rather than 3, 3, 3.
This kind of gotcha gives me the feeling ofstatic
variable in PHP world.
functionName(a,b){this.a=a;this.b=b;}constme=Name("Vuong","Nguyen");console.log(!(a.length-window.a.length));
- A:
undefined
- B:
NaN
- C:
true
- D:
false
Answer
We get true in the console. The tricky part is when we create an object from the constructor function Name but we DO NOT USEnew
keywork. That makes the variablea
global one and get the value "Vuong". Remember that it is actually a property of the global objectwindow
(in the browser) orglobal
in the nodejs.
We then geta.length
~ 5 andwindow.a.length
~ 5 which return 0. !0 returns true.
Imagine what would happen when we create the instanceme
with thenew
keywork. That is an interesting inquire!
constx=function(...x){letk=(typeofx).length;lety=()=>"freetut".length;letz={y:y};returnk-z.y();};console.log(Boolean(x()));
- A:
true
- B: 1
- C: -1
- D:
false
Answer
The spread operator...x
might help us obtain the parameter in the function in the form of array. Yet, in Javascript the typeof array return "object" rather than "array". It is totally odd if you are coming from PHP.
That is said, we now have the length of the stringobject
which returns 6. z.y() simply returns the length of the string 'freetut' (7).
Be aware that the function x() (in the form offunction express
oranonymous function
(if you are coming from PHP) return -1 when being called and when converted to bool withBoolean(-1)
return true instead of false. Noted thatBoolean(0)
return false.
(functionjs(x){consty=(j)=>j*x;console.log(y(s()));functions(){returnj();}functionj(){returnx**x;}})(3);
- A:
undefined
- B: 18
- C: 81
- D: 12
Answer
The functionjs()
can be automatically executed without calling it and known as IIFE (Immediately Invoked Function Expression). Noted the parameterx
of the functionjs
is actuallly passed with the value 3.
The value return of the function is y(s())), meaning calling three other functionsy()
,s()
andj()
because the functions()
returnsj()
.
j() returns 3^3 = 27 so that s() returns 27.
y(s()) means y(27) which returns 27*3 = 81.
Note that we can calldeclare function
BEFORE the function is actually declared but not withexpression function
.
vartip=100;(function(){console.log("I have $"+husband());functionwife(){returntip*2;}functionhusband(){returnwife()/2;}vartip=10;})();
- A: "I have $10";
- B: "I have $100";
- C: "I have $50";
- D: "I have $NaN";
Answer
We have here an IIFE (Immediately Invoked Function Expression). It means we do not have to call it but it will be excuted automatically when declared. The flow is as: husband() returns wife()/2 and wife() returns tip*2.
We might think that tip = 100 because it is a global variable when declaring withvar
keyword. However, it is actuallyundefined
because we also havevar tip = 10
INSIDE the function. As the variabletip
is hoisted with default valueundefined
, the final result would be D. We know thatundefined
returns NaN when we try to divide to 2 or multiple with 2.
If we do not re-declarevar tip = 10;
at the end of the function, we will definately get B.
JS is fun, right?
constjs={language:"loosely type",label:"difficult"};constedu={ ...js,level:"PhD"};constnewbie=edu;deleteedu.language;console.log(Object.keys(newbie).length);
- A: 2;
- B: 3;
- C: 4;
- D: 5;
Answer
This challenge revises the ES6's feature regardingspread operator ...
Spread operator is quite useful for retrieving parameter in function, tounite
orcombine
object and array in JavaScript. PHP also has this feature.
In the variableedu
, we use...js
(spread operator here) to combine both objects into one. It works in the same way with array.
Then we declare another variable namednewbie
. IMPORTANT note: By declaring the variable like that, both variables point to the SAME POSITION in the memory. We may have known something like$a = &$b
in PHP, which let both varibles work in the same way. We might have known aboutpass by reference
in the case.
Then we have 2 asedu.language
is deleted. Both objects now have only two elements.
Now is time to think about coping an object in JS either shallow or deep one.
varcandidate={name:"Vuong",age:30,};varjob={frontend:"Vuejs or Reactjs",backend:"PHP and Laravel",city:"Auckland",};classCombine{staticget(){returnObject.assign(candidate,job);}staticcount(){returnObject.keys(this.get()).length;}}console.log(Combine.count());
- A: 5;
- B: 6;
- C: 7;
- D: 8;
Answer
The buit-in methodObject.assign(candidate, job)
merges the two objectscandidate
andjob
into one object. Then the methodObject.keys
counts the number ofkey
in the object.
Note that two methodsget()
andcount()
are defined asstatic
, so they need to be called statically usingClass.staticmethod()
syntax. Then the final object get 5 elements.
varx=1;(()=>{x+=1;++x;})();((y)=>{x+=y;x=x%y;})(2);(()=>(x+=x))();(()=>(x*=x))();console.log(x);
- A: 4;
- B: 50;
- C: 2;
- D: 10;
Answer
Initiallyx
is declared with the value 1. In the first IIFE function, there are two operations. Firstx
becomes 2 and then 3.
In the second IIFE function,x = x + y
then the current value is 5. In the second operation, it returns only 1 as it undergoes5%2
.
In the third and fouth IIFE functions, we get 2x = x + x
and then 4x = x * x
. It is more than simple.
$var =10;$f =function($let)use ($var) {return ++$let +$var;};$var =15;echo$f(10);
varx=10;constf=(l)=>++l+x;x=15;console.log(f(10));
- A: 26 and 26;
- B: 21 and 21;
- C: 21 and 26;
- D: 26 and 21;
Answer
This question illustrates the diffences between PHP and JavaScript when handling closure. In the first snippet, we declare a closure with the keyworduse
. Closure in PHP is simply an anonymous function and the data is passed to the function using the keyworduse
. Otherwise, it is called aslambda
when we do not use the keyworduse
. You can check the result of the snippet herehttps://3v4l.org/PSeMY. PHPclosure
only accepts the value of the variable BEFORE the closure is defined, no matter where it is called. As such,$var
is 10 rather than 15.
On the contrary, JavaScript treats the variable a bit different when it is passed to anonymous function. We do not have to use the keyworduse
here to pass variable to the closure. The variablex
in the second snippet is updated before the closure is called, then we get 26.
Note that in PHP 7.4, we have arrow function and we then do not have to use the keyworduse
to pass the variable to function. Another way to call aglobal
ariable inside a function in PHP is to use the keywordglobal
or employ the built-in GLOBAL variable $GLOBALS.
letx={};lety={};letz=x;console.log(x==y);console.log(x===y);console.log(x==z);console.log(x===z);
- A: true true true true;
- B: false false false false;
- C: true true false false;
- D: false false true true;
Answer
Technically,x
andy
have the same value. Both are empty objects. However, we do not use the value to compare objects.
z
isx
are two objects referring to the same memory position. In JavaScript, array and object are passed byreference
.x
andz
therefore return true when being compared.
console.log("hello");setTimeout(()=>console.log("world"),0);console.log("hi");
- A: "hello" -> "world" -> "hi"
- B: "hello" -> "hi" -> "world"
- C: "hi" -> "world" -> "hello"
- D: "hi" -> "hello" -> "world"
Answer
Given that the function setTimeout() will be kept in thetask queue
before jumping back tostack,
"hello" and "hi" will be printed first, then A is incorrect. That is also the case of the answers C and D.
No matter how many seconds you set to thesetTimeout()
function, it will run after synchronous code. So we will get "hello" first as it is put into the call stack first. Though thesetTimeout()
is then being put into the call stack, it will subsequently offload to web API (or Node API) and then being called when other synchronous codes are cleared. It means we then get "hi" and finally "world".
So B is the correct answer.
Credit: @kaitoubg (voz) for your suggestion regarding the timeout throttled
by which I have decided to alter the question slightly. It will ensure that readers will not get confused as the previous code might bring out different results when tested on other browsers or environments. The main point of the question is about the discrepancy between the synchronous code and asynchronous code when usingsetTimeout.
.
String.prototype.lengthy=()=>{console.log("hello");};letx={name:"Vuong"};deletex;x.name.lengthy();
- A: "Vuong";
- B: "hello";
- C: "undefined"
- D: "ReferenceError"
Answer
String.prototype.someThing = function () {}
is the common way to define a new built-in method forString
. We can do the same thing withArray
,Object
orFunctionName
where FunctionName is the function designed by ourself.
That is not challenging to realise that"string".lengthy()
always returnshello
. Yet, the tricky part lies in thedelete object
where we might think that this expression will entirely delete the object. That is not the case asdelete
is used to delete the property of the object only. It does not delete the object. Then we gethello
rather thanReferenceError
.
Note that if we declare object withoutlet, const
orvar
, we then have a global object.delete objectName
then returntrue
. Otherwise, it always returnsfalse
.
letx={};x.__proto__.hi=10;Object.prototype.hi=++x.hi;console.log(x.hi+Object.keys(x).length);
- A: 10
- B: 11
- C: 12
- D: NaN
Answer
First we have an empty objectx
, then we add another propertyhi
for x withx.__proto__.hi
. Note this is equivalent toObject.prototype.hi = 10
and we are adding to thefather
objectObject
the propertyhi
. It means every single object will inherit this propety. The propertyhi
becomes a shared one. Say now we declare a new object such aslet y = {}
,y
now has a properyhi
inherited from thefather
Object
. Put it simplyx.__proto__ === Object.prototype
returnstrue
.
Then we overwrite the propertyhi
with a new value 11. Last we have 11 + 1 = 12.x
has one property andx.hi
returns 11.
Updated (July 27th 2021). If you writeObject.prototype.hi = 11;
instead ofObject.prototype.hi = ++x.hi;
as written in the code above, thenObject.keys(x)
will return an empty array asObject.keys(object)
only returns the property of the object itself, not the inherited ones. It means the final result will be 11 rather than 12. For some reason, the code ``Object.prototype.hi = ++x.hi;will create a property for the object
x` itself and then `Object.keys(x)` gives us the array `["hi"]`.
Yet, if you runconsole.log(x.hasOwnProperty("hi"))
it still returnsfalse
. By the way, when you deliberately add a property for x such asx.test = "testing"
, thenconsole.log(x.hasOwnProperty("test"))
returnstrue
.
constarray=(a)=>{letlength=a.length;deletea[length-1];returna.length;};console.log(array([1,2,3,4]));constobject=(obj)=>{letkey=Object.keys(obj);letlength=key.length;deleteobj[key[length-1]];returnObject.keys(obj).length;};console.log(object({1:2,2:3,3:4,4:5}));constsetPropNull=(obj)=>{letkey=Object.keys(obj);letlength=key.length;obj[key[length-1]]=null;returnObject.keys(obj).length;};console.log(setPropNull({1:2,2:3,3:4,4:5}));
- A: 333
- B: 444
- C: 434
- D: 343
Answer
This question examines how thedelete
operator works in JavaScript. In short, it does nothing when we writedelete someObject
ordelete someArray
. It nonetheless completely deletes and removes a property of an object when writing something likedelete someObject.someProperty
. In the case of array, when we writedelete someArray[keyNumber]
, it only removes thevalue
of theindex
, keep theindex
intact and the newvalue
is now set toundefined
. For that reason, in the code first snippet, we get (the length) 4 elements as in the original array but only 3 properties left in the object passed when the function object() is called, as in the second snippet.
The third snippet gives us 4 as declaring an object's propery to eithernull
orundefined
does not completely remove the property. The key is intact. So the length of the object is immutable.
For those who are familiar with PHP, we haveunset($someArray[index])
that remove the array element, both key and value. Whenprint_r
the array, we might not see the key and value that have been unset. However, when we push (usingarray_push($someArray, $someValue)
) a new element in that array, we might see that the previous key is still kept, but no value and not being displayed. That is something you should be aware of. Have a look athttps://3v4l.org/7C3Nf
vara=[1,2,3];varb=[1,2,3];varc=[1,2,3];vard=c;vare=[1,2,3];varf=e.slice();console.log(a===b);console.log(c===d);console.log(e===f);
- A: true true true
- B: false false true
- C: true true false
- D: false true false
Answer
a
andb
returns false because they point to different memory location even though the values are the same. If you are coming from PHP world, then it will return true obviously when we compare either value or value + type. Check it out:https://3v4l.org/IjaOs.
In JavaScript, value is passed by reference in case ofarray
andobject
. Hence in the second case,d
is the copy ofc
but they both point to the same memory position. Everything changes inc
will result in the change ind
. In PHP, we might have$a = &$b;
, working in the similar way.
The third one gives us a hint to copy an array in JavaScript usingslice()
method. Now we havef
, which is the copy ofe
but they point to different memory locations, thus they have different "life". We getfalse
accordingly when they are being compared.
varlanguages={name:["elixir","golang","js","php",{name:"feature"}],feature:"awesome",};letflag=languages.hasOwnProperty(Object.values(languages)[0][4].name);(()=>{if(flag!==false){console.log(Object.getOwnPropertyNames(languages)[0].length<<Object.keys(languages)[0].length);}else{console.log(Object.getOwnPropertyNames(languages)[1].length<<Object.keys(languages)[1].length);}})();
- A: 8
- B: NaN
- C: 64
- D: 12
Answer
The code snippet is quite tricky as it has a couple of different built-in methods handling object inJavaScript
. For example, bothObject.keys
andObject.getOwnPropertyNames
are used even thought they are quite similar except that the latter can return non-enumerable properties. You might want to have a look at this thoroughly written referencehttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
Object.values
andObject.keys
return the property value and property name of the object, respectively. That is nothing new.object.hasOwnProperty('propertyName')
returns aboolean
confirming whether a property exists or not.
We haveflag
true becauseObject.values(languages)[0][4].name
returnsfeature
, which is also the name of the property.
Then we have 4 << 4 in theif-else
flow that returns the bitwise value, equivalent to4*2^4
~4*16
~ 64.
varplayer={name:"Ronaldo",age:34,getAge:function(){return++this.age-this.name.length;},};functionscore(greeting,year){console.log(greeting+" "+this.name+`! You were born in${year-this.getAge()}`);}window.window.window.score.call(window.window.window.player,"Kiora",2019);score.apply(player,["Kiora",2009]);consthelloRonaldo=window.score.bind(window.player,"Kiora",2029);helloRonaldo();
- A: "Kiora Ronaldo! You were born in 1985", "Kiora Ronaldo! You were born in 1985", "Kiora Ronaldo! You were born in 1985"
- B: "Kiora Ronaldo! You were born in 1991", "Kiora Ronaldo! You were born in 1991", "Kiora Ronaldo! You were born in 1999"
- C: "Kiora Ronaldo! You were born in 1991", NaN, "Kiora Ronaldo! You were born in 1980"
- D: "Kiora Ronaldo! You were born in 1991", "Kiora Ronaldo! You were born in 1980", "Kiora Ronaldo! You were born in 1999"
Answer
We can usecall()
,apply()
andbind()
to apply a function to any object. At first sight, it seems that three functions do the same thing. Yet there are some situations where they are differently employed to handle respective contexts or solve particular problems.
Of the three, onlybind()
can be executed after binding. We can create a variable to store the result ashelloRonaldo()
in the code snippet above.apply()
andcall()
will bind and execute the function at the same time.apply()
hints usa
~ array where we need to pass an array as parameter.call()
hints usc
or comma where we pass parameters with a comma. You might want to have a look at this posthttps://stackoverflow.com/questions/15455009/javascript-call-apply-vs-bind
Note thatwindow.window.window.score
orwindow.score
or simplyscore
do the same thing. It points to thescore()
function in the global scope.
The correct anwser is D. Thescore()
andgetAge()
functions are nothing special. The only tricky part is thatthis.age
is incremented each time you call the funtiongetAge()
;
varronaldo={age:34};varmessi={age:32};functionscore(year,tr,t){if(typeoftr==="function"&&typeoft==="function"){console.log(`You score${tr(year,t(this.age))} times`);}}consttransform=(x,y)=>x-y;consttitle=(x)=>++x+x++;consthelloRonaldo=score.bind(ronaldo,2029,transform,title);helloRonaldo();consthelloMessi=score.bind(messi,2029,transform,title);helloMessi();
- A: "You score 1989 times" and "You score 1963 times"
- B: "You score 1959 times" and "You score 1989 times"
- C: "You score 1989 times" and "You score 1953 times"
- D: "You score 1959 times" and "You score 1963 times"
Answer
bind()
allows us to bind a function declared with any object. Here we bindscore()
and bothronaldo
andmessi
.
Inscore()
we pass three parametersyear
,tr
andt
in which bothtr
andt
are function. They handle simple things as defined afterwards.
When we bindscore()
withronaldo
andmessi
, we pass three parameters as declared in thescore()
function whereintransform
andtitle
are functions.
varperson={};Object.defineProperties(person,{name:{value:"Vuong",enumerable:true,},job:{value:"developer",enumerable:true,},studying:{value:"PhD",enumerable:true,},money:{value:"NZD",enumerable:false,},});classEvaluate{staticcheckFlag(obj){returnObject.getOwnPropertyNames(obj)>Object.keys(obj) ?Object.getOwnPropertyNames(obj) :Object.keys(obj);}}constflag=Evaluate.checkFlag(person);console.log(flag.length);
- A: 1
- B: 2
- C: 3
- D: 4
Answer
Object.keys(obj)
is almost identical toObject.getOwnPropertyNames(obj)
except the fact that the latter returns any type of object's property regardless ofenumerable
. By defaultenumerable
is true when creating object. UsingObject.defineProperties
orObject.defineProperty
we can manually set this option tofalse
.
As such the objectperson
will get 3 usingObject.keys(obj)
but 4 withObject.getOwnPropertyNames(obj)
.In short Object.keys(obj)
only returns the property setting the enumerable astrue
.
constid=10;constgetID=(...id)=>{id(id);functionid(id){console.log(typeofid);}};getID(id);
- A: ReferenceError
- B: 10
- C: undefined
- D: 'function'
Answer
When declaring a function inside another function, we are working with Closure in JavaScript. Note that if a function is declared as normal (rather than function expression), it is hoisted. We might see severalid
in the code snippet above but in fact, some of them does nothing.
The result of the code depending on the operatortypeof id
, which isfunction
. Soid
in this operation is theid()
function.
varbook1={name:"Name of the rose",getName:function(){console.log(this.name);},};varbook2={name:{value:"Harry Potter"},};varbookCollection=Object.create(book1,book2);bookCollection.getName();
- A: 'Harry Potter'
- B: 'Name of the rose'
- C: ReferenceError
- D: Object object
Answer
Object.create
allows us to create an object which is based on another object. If we do not pass the second parameter -book2
in this case - thename
property of the objectbookCollection
will beName of the rose
inherited from thebook1
. It means we can provide additional properties when declaring object withObject.create
.
bookCollection
has its own propertyname
and another one inherited frombook1
. In this case its own propertyname
will show up as it has higher priority. That is why we get 'Harry Potter'.
(()=>{consta=Object.create({});constb=Object.create(null);letf1=a.hasOwnProperty("toString");letf2="toString"inb;letresult=f1===false&&f2===false ?console.log((typeofa.toString()).length) :console.log(b.toString());})();
- A: ReferenceError
- B: undefined
- C: 0
- D: 6
Answer
The two objectsa
andb
are created usingObject.create()
operator. There is a bit of difference between them asa
inherits from Object prototype butb
is totally empty when we pass thenull
paramater. YethasOwnProperty('toString')
always returnsfalse
neithera
norb
given thattoString()
is not defined inside these objects. The method however is still available as it is inherited from Object prototype.
Bothf1
andf2
returnfalse
. Note that we useobject.hasOwnProperty('key')
and('key' in object)
to check the availability of a key in an object. There is a bit difference between the two as the latter also returns the key inherited. You might want to have a look here:https://stackoverflow.com/questions/455338/how-do-i-check-if-an-object-has-a-key-in-javascript
Thentypeof a.toString()
returnsstring
, which gives us 6 with the.length
property.
If the syntax is odd to you, you might look for 'self-invoking function' and 'arrow function' in JavaScript.
letpromise=newPromise((rs,rj)=>{setTimeout(()=>rs(4),0);Promise.resolve(console.log(3));console.log(2);});promise.then((rs)=>{console.log(rs ?rs**rs :rs);returnrs;}).then((rs)=>console.log(rs==256 ?rs :rs*rs));
- A: 3, 2, 256, 256
- B: 3, 2, 256, 16
- C: 256, 16, 3, 2
- D: 16, 256, 3, 2
Answer
We first declare a promise-based code withlet
and then call it. Given thatsetTimeout()
is an asynchronous action, it will run last even the time is set to 0 insetTimeout(() => rs(4), 0);
. AlthoughPromise.resolve(console.log(3))
also returns a promise but it is a Microtasks, then it has a higher priority than Tasks as set bysetTimeout()
. You might want to have a look at this posthttps://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/.
In.then()
we chain the result so that we have4^4
in the first then() and4*4
in the secondthen()
. Note thatreturn rs
returns the original value.
asyncfunctionf(){letpromise=newPromise((resolve,reject)=>{setTimeout(()=>resolve("done!"),0);});setTimeout(()=>console.log("world"),0);console.log(awaitpromise);console.log("hello");}f(setTimeout(()=>console.log("kiora"),0));
- A: ReferenceError
- B: done, hello, world
- C: hello, done, world
- D: kiora, done, hello, world
Answer
Though we do not declare any paramater for the functionf()
, we passsetTimeout(()=>console.log("kiora"),0)
when call it. We therefore get 'kiora' first.
Given that the variablepromise
returns a solved promise and it is called with the keywordawait
, JavaScript will 'pause' at this lineconsole.log(await promise);
till the result is resolved. That is why we get "done" at the next result.
Why we do not get "world" or "hello" at the second ? As JavaScript "pauses" at the line withawait
keyword, we cannot get "hello" as usual (note that whenever we call setTimeout(), this function will run last because it is an asynchronous task operator), whereassetTimeout(()=> console.log("world"), 0);
should always run last.
Here we might see a bit of difference when employingawait
keyword before asynchronous operator (in this case, we usesetTimeout()
as an example) or when call the function/operator without it.
functionname(){returnnewPromise((resolve)=>{setTimeout(()=>{resolve("New Zealand");},10);});}functionfruit(){returnnewPromise((resolve)=>{setTimeout(()=>{resolve("Kiwi");},20);});}(asyncfunctioncountryandfruit(){constgetName=awaitname();constgetFruit=awaitfruit();console.log(`Kiora:${getName}${getFruit}`);})();(asyncfunctionfruitandcountry(){const[getName,getFruit]=awaitPromise.all([name(),fruit()]);console.log(`Hello:${getName}${getFruit}`);})();
- A: Null
- B: Kiora
- C: "Hello: New Zealand Kiwi" -> "Kiora: New Zealand Kiwi"
- D: "Kiora: New Zealand Kiwi" -> "Hello: New Zealand Kiwi"
Answer
Bothcountryandfruit
andfruitandcountry
are self invoking functions. Both are declared with the keywordasync
, it means the code inside will run step by step. It helps us control the flow of data much more concise as compared to Promise-based operator or callback way.
The first function returns"Kiora: New Zealand Kiwi"
and the second one ouputs"Hello: New Zealand Kiwi"
. We might think that the order will be the same but actually the order of the result is reversed because the function withawait
keyword will run step by step rather than in in parallel as Promise.all. It meansfruitandcountry
will run faster thancountryandfruit
.
You might want to have a look at the difference between the two athttps://alligator.io/js/async-functions/
classMySort{constructor(object){this.object=object;}getSort(){returnObject.entries(this.object)[0][1].sort()[Object.values(this.object).length];}}constobject={month:["July","September","January","December"],};constsortMe=newMySort(object);console.log(sortMe.getSort());
- A: July
- B: September
- C: January
- D: December
Answer
Object.entries
returns an array consisting of both key and value from an object whileObject.values
retuns an array of the values of object andObject.keys
gives us an array of keys of the object. As such,Object.entries(object)
in the code snippet above gives us a nested array with just one element in which the values are put in another nested array like that[["month", ["July", "September", "January", "December"]]]
.
For that reason,Object.entries(this.object)[0][1].sort()
will actually sort the value array and return a new order as "December" -> "January" -> "July" -> "September". Hence, when we get the element with the index given by[Object.values(this.object).length]
we getJanuary
because[Object.values(this.object).length]
give us 1 (the length of the array given by Object.values);
constflag=[]!==!!!!![];letf=()=>{};console.log((typeoff()).length+flag.toString().length);
- A: NaN
- B: 12
- C: 13
- D: 14
Answer
Comparing two arrays or two objects in JavaScript always returnfalse
because both are passed by reference, unlike primitive types such as string, number or boolean. That is why comparing [] and [] using either == or === returnsfalse
. The weird part is the!==!!!!!
which is equivalent to!==
, nothing special. So theflag
istrue
.
In the expression functionf()
, we use arrow function here but and{}
is a part of the function rather than an object. In case you want to return an object, you have to write aslet f = () => ({})
or simply using normal way to define function. With the keywordreturn
, we can easily catch the content of the function when using normal way to define function.
Thus, thetypeof f()
returnsundefined
rathernobject
. We then get the length 9 and the flag (true) becomes 'true' (a string, by using toString() function), which returns 3 with the propertylength
. We finally get 13.
(function(a,b,c){arguments[2]=(typeofarguments).length;c>10 ?console.log(c) :console.log(++c);})(1,2,3);
- A: 4
- B: 5
- C: 6
- D: 7
Answer
We have a self-invoking function with three parameters declared. Note thatarguments
inside a function returns an object consisting of the parameters of the function.
The key part here is that when we assign a value to that array (it is array-like, as mentioned above) (or any element), the function will use that value rather than the value from the parameter we pass to it when calling the function. Hence,c
will be(typeof arguments).length;
(6) rather than 3.
Asc
has a new value of 6, it is definitely less than 10, so we get the final resultconsole.log(++c)
, which returns 7.
Note thatarguments
is not available on arrow functions. See more detailed herehttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
From ES6 onwards, it is recommended to use ...restParameter given that it is a true array. It means you can manipulate the parameter with native JavaScript functions such as map, reduce or filter.
For PHP developer, we havefunc_get_args()
in PHP that does the same thing, but it will not override the value passed. Check it by yourself athttps://3v4l.org/dMfhW
classCalculator{constructor(a,b){this.a=a;this.b=b;}staticgetFlag(){returnnewArray(this.a).length==newArray(this.b).toString().length;}getValue(){returnCalculator.getFlag() ?typeofthis.a :typeofnewNumber(this.b);}}constme=newCalculator(5,5);console.log(me.getValue());
- A: NaN
- B: "string"
- C: "object"
- D: "number"
Answer
We have a class named Calculator. When declaring a new instance of the object, we pass two parametersa
andb
. These two parameters have the same value butnew Array(this.a).length
is totally different fromnew Array(this.b).toString().length
because the latter returns a string",,,,"
meaning the length 4 while the former returns the length of an array and we therefore get 5.
For that reasongetFlag()
returnsfalse
. IngetValue()
we gettypeof new Number(this.b);
which returnsobject
. That is a bit different fromtypeof b
, which returnsnumber
.
varname="Auckland";constnz={name:"Kiwi",callMe:function(){returnthis.name;},};letme=nz.callMe;letshe=nz.callMe.bind(nz);letresult=me()===nz.callMe() ?she() :`${me()}${she()}`;console.log(result);
- A: undefined
- B: "Auckland"
- C: "Kiwi"
- D: "Auckland Kiwi"
Answer
The key point in this question involves the keywordthis
in JavaScript. We have a simple object that contains one method and one string propertyname
.
First, it is important to write down is thatlet me = nz.callMe;
and then callme()
is totally different from directly callingnz.callMe()
. If we assign a variable to a method delared inside an object,this
in that method will behave differently (when we call the variable as a method and when dirrectly call that method). In particular, in the first case,this
is thewindow
object while in the second one,this
inside the function still points to propertyname
in the objectnz
. It meansme()
returns "Auckland" whilenz.callMe
returns "Kiwi".
Thenresult
will returnfalse
and we get the final output value${me()} ${she()}
. Whyshe()
is different fromme()
? You might easily guess thatshe
stillbind
to the objectnz
rather thanwindow
object as inme()
.
constclub={name:"Juventus",player:["Ronaldo"],showMePlayer:function(){this.player.map(function(thename){console.log(this.name.length);},this);},showMe:function(){this.player.forEach(function(thename){console.log(this.name.length);}.bind(this));},show:function(){constself=this;this.player.map(function(thename){console.log(self.name.length);});},Me:function(){this.player.map(function(thename){console.log(this.name.length);});},};club.showMePlayer();club.showMe();club.show();club.Me();
- A: 8 - 8 - 8 - 8
- B: "Juventus" - "Juventus" - "Juventus" - "Juventus"
- C: "Ronaldo" - "Ronaldo" - "Ronaldo" - "Ronaldo"
- D: 8 - 8 - 8 - 0
Answer
The code snippet above is not a big challenge for you I guess. It simply gives you an example ofthis
in different contexts when we declare an anonymous function inside a method of an object. The three first methods are common ways to handlethis
usingthis
as second parameter inmap()
, by usingbind(this)
inforEach
(or map()) or bythat = this
technique (you might see people useself = this
rather thanthat= this
).
The last methodMe()
will cause unexpected result becausethis.name
does not bind to the objectclub
. Note that you might get another result when testing the code on jsbin.com. On Chrome and Firefox, we get 0.
For further information, kindly have a look athttp://speakingjs.com/es5/ch17.html#_pitfall_losing_this_when_extracting_a_method
((...a)=>{constb=["javascript","new zealand"];constc=[...a,typeofa, ...b,"kiwi"];console.log(c.length+c[0].length);})(newArray(10));
- A: 5
- B: 10
- C: 15
- D: 20
Answer
...
can be used in two ways in JavaScript (and PHP) as eitherspread operator
orrest parameter
. You might have to check the following article about the two. They are the same as three dots, but the way they are employed vary considerably between the two.https://javascript.info/rest-parameters-spread-operator
We see bothspread operator
andrest parameter
in the code snippet above. First the parameter(...a)
in the self-invoking function is of course arest parameter
while the constantc
we see thespread operator
. In the former case, it simply means that you can pass to the function as many parameter as you want. Note that thetypeof a
in this case isobject
even though it is a native array in JavaScript. (I means native array because you might think about array-like if we use arguments. Please have a look at the question 28 or this linkhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments).
Spread operator
as in the constantc
allows us to combine array. So...a
in the code above isrest parameter
when it is used as function parameter but in this case it is the syntax ofspread operator
.
Finally, we getc
with 5 elements (...a
is a nested array, so thelength
is 1) but the first element has 10 child elements (when we pass to the functionnew Array(10)
). The length of both then returns 15.
functionKiora(name, ...career){this.name=name;returnArray.isArray(career)===true&&typeofcareer==="object" ?{} :"";}varstudent=newKiora("Vuong");console.log(student.name);
- A: "Vuong"
- B: undefined
- C: ErrorReference
- D: false
Answer
We have a function constructorKiora
(written with a capital letter, but that is optional) that can be used to create object, as thestudent
object in the code above. In the function, we have two parameters with the second one is actually arest parameter
. The typeof operator isobject
but if we check withArray.isArray(array)
it also returns true.
For that reason,Array.isArray(career) === true && typeof career === "object"
returns true. Hence thereturn
operator finally returns an object{}
.
You might be surprised whenconsole.log(student.name);
outputsundefined
given that the constructor functionKiora
returns an object. Otherwise, we might simply get the valuename
.
classFilter{constructor(element){this.element=element;}filter(){returnthis.type()==="object" ?this.element[0].name :"hello";}type(){returntypeofthis.element;}}letcountries=[{name:"New Zealand",isdeveloped:true},{name:"Vietnam",isdeveloped:false},];letx=newFilter(countries);constfilter=countries.filter((item)=>{return!item.isdeveloped;});console.log(x.filter().length+filter[0].name.length);
- A: 15
- B: 16
- C: 17
- D: 18
Answer
Apologize that the code snippet is a bit longer than usual. But actually it is not really challenging as you might think. You can easily get the correct result after spending a little of time to debug.
First we declare a class that has two methods. The first methodfilter()
will returns the first element of the array (of the proptertyelement
) or simply returnshello
depending on thetype()
method. We know thattypeof of array
will returnobject
so thefilter()
method returnthis.element[0].name
.
Try to make you feel confused, we then call the built-infilter()
method. This native method returns a new array depending on the condition we pass to the call-back function. Note that!item.isdeveloped
meansfalse
. It means we getVietnam
.
Finally we getNew Zealand
.length andVietnam
.length, which in total returns 18.
asyncfunctionabc(){console.log(8);awaitPromise.resolve(2).then(console.log);console.log(3);}setTimeout(()=>{console.log(1);},0);abc();queueMicrotask(()=>{console.log(0);});Promise.resolve(4).then(console.log);console.log(6);
- A: 6 - 8 - 3 - 0 - 4 - 2 - 1
- B: 8 - 2 - 3 - 0 - 4 - 6 - 1
- C: 6 - 8 - 2 - 0 - 4 - 3 - 1
- D: 8 - 6 - 2 - 0 - 4 - 3 - 1
Answer
D is correct anwser. The order of the asynchronous code's output depends on the MicroTask or MacroTask. MicroTask has a higher priority. Note that the synchronous code always be executed before asynchronous code. So in essense, we have the order as follows:
1) synchronous code 2) microtask code (promise, queueMicrotask) 3) macrotask code (setTimeout, setInterval)
Be awared that in Nodejs environment, we also haveprocess.nextTick(callback)
which has the highest priority but we dont have it in this code.
So, first callback in thesetTimeout()
will be executed last given that this is a MacroTask. That is why we got 1 last.
Second, the functionabc()
is called next. Then we have 8 printed out in the console first. As the next line of code inside that function is an asynchrnous code with the keyword "await", we thenconsole.log(6)
asPromise.resolve(4).then(console.log)
is an asynchrnous code. That is why we got 6.
Now is the time forPromise.resolve(2)
, so we get 2. At this point, you might have some sort of confusion. What will happend if we do not pass the keyword "await" beforePromise.resolve(2)
?
As we haveawait
, the code will be blocked here. Then what? We get 0 and 4 not 3.Promise
andqueueMicrotask
are both microtask and they are already to run beforeconsole.log(3)
. The reason is that microtask queue need to be emptied before any other codes can be called in the callstack.
In the next step, we get 3 and the last one is 1.
What would happend if we do not have theawait
keyword? Then the order of the output will be 8 - 3 - 6 - 2 - 0 - 4 -1.
functionmyAccount(money){letmyMoney=money;return{status:function(){return`You have $${myMoney} in your account`;},dePoSit:function(amount){myMoney=myMoney+amount;},withDraw:function(amount){if(amount>myMoney){return`You cannot withdraw money now`;}myMoney=myMoney-amount;},};}constvuong=myAccount(1000);vuong.withDraw(500);vuong.withDraw(200);vuong.dePoSit(100);vuong.withDraw(50);console.log(vuong.status());
- A: "You have $ 950 in your account"
- B: "You have $ 1000 in your account"
- C: "You have $ 550 in your account"
- D: "You have $ 350 in your account"
Answer
As the "state" of the data is preserved each time we calldePoSit()
orwithDraw()
, hence we get $350 after all.
Noted that that is a kind of "factory" function with "preload" data. You might think about another object when pass tomyAccount(somedata);
some other data. That is a really helpful way to create multiple objects from a factory function.
consthoccoban={x:"youtube.com/hoccoban".length,getMe(){constinner=function(){console.log(++this.x);};inner.bind(this)();},};hoccoban.getMe();
- A: 20
- B: 21
- C: 22
- D: 23
Answer
We get 21. First "youtube.com/hoccoban" returns 20 as we are using the property length of the string. Then it is being added one more value in++this.x
. The question here seems trivial but it is actually not. There is a crucial note we should keep in mind is thatconsole.log(++this.x)
will not work asx
is undefined when it is called outside of the object.
We can solve the problem withthis
in this case by using arrow function in the inner so that is can become something likeconst inner = () => {}
as the arrow function does not actually havethis
. It will automatically look around and call the available object when the function is executed.
The second solution is that we can somehow "bypass" the trickythis
by using that/this solution. We just need to declare a new variableconst that = this
inside getMe() and before declaring inner function. That is a quite common practice.
The third solution is to take advantage of call(), bind() and apply() which are native methods of function (yes, function is also an object in JavaScript). In this case, we implementbind(this)
to "bind" the function and the object so thatthis
can actually point to the object when the function is executed. Note that bind() cannot be instantlly executed so that we need to add () after we bridge the function and the object. If we replace bind() with call(), then we do not need to pass () as in the above example. Soinner.bind(this)();
will becomeinner.call(this);
. They are technically equal. In practice, we tend to create a new variable to get the result from the binding of the function and the object.
function*hocCoBan(){yield"js.edu.vn";yield"youtube.com/hoccoban";yield"Vuong Nguyen";}letdata=hocCoBan();console.log((typeofdata).length+data.next().value.length);
- A: NaN
- B: 10
- C: Error
- D: 15
Answer
First, take a closer look at the function. It has a asterisk (*) next to the keyword "function". We do not havereturn
keyword inside the function itself. What is going on here?
It you have already known about generator, then this code snippet is not a big deal at all. We do not use generator very often, but this native JavaScript feature is the basis for async/await function, which is supported in ES7 that allows us to handle the flow of asynchronous code much easily.
The operatortypeof data
will returnobject
rather thanfunction
, which is the same case withtypeof hocCoBan()
. Of course,typeof hocCoBan
still returnsfunction
. But it is actually a normal function. Basically, we get 6 in the operator(typeof data).length
.
Thendata.next()
calls the the built-in methodnext()
which will output the value in the firstyield
, which is declared in the function. Then we get the length 9 with the stringjs.edu.vn
.
After all, we get 15. Not that understanding generator is quite important if you really want to understandasync/await
function.
consta=[1,2,"chó",3,1,"chó","mèo",3];constb=[...newSet(a)];b.length="chó".length;console.log(b);
- A: 4
- B: [1, 2, "chó", 3, "mèo"]
- C: [1, 2, "chó", "mèo"]
- D: [1, 2, "chó"]
Answer
When using ... in array, it is called spread operator in JavaScript which, technically, is similar to rest parameter (using in the context of function). It provides a more elegant way to concat (combine) or copy array. In the code above, b is a copy of a. However, as we pass a in to aSet
, it will return the unique value only in a. It means, now we have `[1, 2, "chó", 3, "mèo"] in b.
However, we then set the length for b as 3. Note that "chó".length returns 3 but in PHP, strlen("chó") returns 4, just in case you are coming from PHP world.
As we set the length for the array b, we also cut down the array itselt. That is the reason why we get [1, 2, "chó"] printing out in the console.
constmot=function(m){returnarguments[0];};consthai=function(...m){returnarguments[arguments[0]];};consta=[mot(123),hai(1,2,3)];console.log(typeofa!=="object" ?a[0] :a[1]);
- A: 1
- B: 2
- C: 3
- D: 123
Answer
First, it should be noted thatarguments
cannot be used in an arrow function, so in order to take advantage of this feature, we have to write the function in the casual form.arguments
returns an array-like object that contains any parameter we pass into the function when executing it.
...
is arest operator
. We use this feature in function and array. Noted that in the context of array, it is calledspread operator
and it behaves differently. When declaring a function with ..., we can pass as many parameters into the function itselt when executing it as we want.
Note that in the functionhai
, we returnarguments[arguments[0]]
which meanshai(1, 2, 3)
will return 2 rathern than 1 becausearguments[0]
return 1 and thenarguments[1]
returns 2.
The last thing we have to take note is that the typeof operator of an array will returnobject
, here the trick seems more daunting. The final anwser is 2 as we got it ina[1]
, orhai(1, 2, 3)
.
classComponent{constructor(age){this.age=age+`${typeofCoder}`.length;}getAge(){return++this.age;}}classCoderextendsComponent{constructor(age){super(age);this.age=age-`${typeofCoder}`.length;}}consta=newCoder(16);console.log(a.getAge());
- A: 7
- B: 8
- C: 9
- D: 10
Answer
We have two simple classes in which Coder extends Component. Nothing fancy. Astypeof ClassName
returnsfunction
rather thanclass
, we then get 8 in the operator"function".length
.
Though we implementsuper(age)
in the Coder class, we actually overwrite the contructor of the parent class Component in the child class Coder. Therefore, when initiating the objecta
, the following code is automatically triggeredthis.age = age -
${typeof Coder}.length;
. The difference between the child and parent 's constructor is minus (-) and plus (+) in the above code.
As such, we have 16 - 8 rather than 16 + 8, which returns 8. The functiongetAge()
returns 9, so the corrent answer is C.
Bear in mind that JavaSCript is not a "real" OOP programming language even though we can now implementclass
andobject
as in other languages.
classRemoveFalse{constructor(element){this.element=element;this.length=this.removeFalse().length;}removeFalse(){this.element=this.element.filter(Boolean);returnthis.element;}}consttheArray=[true,false,1,0,NaN,undefined,"",null,"js.edu.vn"];consta=newRemoveFalse(theArray);console.log(a.length);
- A: false
- B: true
- C: 2
- D: 3
Answer
The key message that can be taken away in the code snippet above isfiler(Boolean)
which can be taken into consideration in case you want to eliminatefalsy values
in an array. We can usefilter(callback)
orfilter(Boolean)
in particular in this case to do that. Note that we have to pass into the filter function a callback and in this case Boolean is actually a function. You can checktypeof Boolean
to see it.
Similar tomap
orreduce
function,filter
always returns a new array from the exisiting one.[true, false, 1, 0, NaN, undefined, "", null, "js.edu.vn"].filter(Boolean);
will return[true, 1, "js.edu.vn"];
, hence calling the functionremoveFalse()
gives us 3. So the correct answer is 3.
constcoderfarm=[1,[],{},[],2,3];constconverted=Number(coderfarminstanceofArray);constresult=coderfarm.indexOf(converted+true);console.log(result);
- A: []
- B: {}
- C: 2
- D: 4
Answer
We have a simple array in the code snippet above that includes some digits, two other arrays and one object. Using the built-in functionNumber
, we can convert any value passing to the function intodigit
. Ascoderfarm instanceof Array
returnstrue
, thenconverted
get 1. Noted that you can use another way to check the type of an array isArray.isArrray(arrayToBeChecked)
which return aboolean
value. Suprisingly, the operatortypeof []
returnsobject
rather thanarray
.
The built-in functionindexOf
will return the index of the element that is being checked. So asconverted + true
return 2, we are going to check the index of the element with the value 2 in the arraycoderfarm
.
We get 4 in theconsole.log
and the correct answer is D.
constconverter=(arrayInput)=>{return{ ...arrayInput};};constcontent=["function","object","decorator"];constchecking=content[Number(false)];constresult=typeofconverter(content)===content[1];console.log(checking ?(result ?(typeofconverter).length :false) :false);
- A: 6
- B: NaN
- C: true
- D: 8
Answer
The operator...
in JavaScript is very handy. The functionconverter
is quite trivial, it takes advantege of...
(rest operator || spread operator) to turn an array into an object.
First we have the constantchecking
with the valuefunction
given thatNumber(false)
gives us 0 and that is the first index in the arraycontent
.
Second, the constantresult
gives us the valuetrue
as thetypeof converter(content)
isfunction
, which is also the value ofcontent[1]
.
Then in the final code, we havechecking = true
, and thenresult = true
as well, so the final result is(typeof converter).length
which is equivalent to"function".length
because thetypeof of converter
is simplyfunction
. We get 8 after all and the correct answer is D.
So the key message here is that we can take advantate of thespread operator
(or...
) to turn an array to an object. For example:const a = ["hello", 2]
, then we can have a go withconst b = {...a}
and b is now an object with the following value:{0: "hello", 1: 2}
. The key of the object is actually the index of the original array.
function*js(length){for(leti=length.length;i>0;--i){yieldi;}}letgetJS=js(typeofjs);letresult=getJS.next().value;console.log(result+getJS.next().value);
- A: 10
- B: 14
- C: 15
- D: 16
Answer
We have a generator function in the code snippet above, which is defined with the *. Noted that we can "store" as many result as we want in a generator thanks to the keywordyield
.
As thetypeof js
isfunction
, so the length of the stringfunction
is 8. So when callinggetJS.next().value;
, we get 8. However, in the next calling, it returns 7, and in the following calling after that, we get 6. That is why generator can "store" and "release" (or return) as many value as we want.
So the answer is C, which is 8 (first execution of the generator) + 7 (second execution of the generator).
varages=[10,15,20,25];letresponse=[];ages.some(function(currentValue,index,ages){if(currentValue>ages[ages.length-index])response.push(currentValue+ages.length);});console.log(response);
- A: [20]
- B: [20, 25]
- C: [25, 29]
- D: [29]
Answer
Array.prototype.some()
is a built-in function facilitating us to iterate the array using a callback. As in the code snippet above, there are three parameters in the callback, namelycurrentValue
(the value of the current element that is being checked),index
(the index of the element in the array that is being checked/evaluated) andages
(the array itself).
The functionsome()
returns aboolean
value. The codecurrentValue > ages[ages.length - index]
returnstrue
only one time, which is the last element. Let 's examine the code when it runs through each element:
10 > ages[4 - 0]. As ages[4] returns
undefined
, and10 > undefined
returnsfalse
, it stops.15 > ages[4 - 1]. As ages[3] returns 25, it breaks as the operator returns
false
.20 > ages[4 - 2]. As ages[2] returns 20, it breaks as the operator returns
false
.25 > ages[4 - 3]. As ages[1] returns 10, it returns
true
. Only this value is being pushed to the arrayresponse
.
Soresponse.push(currentValue + ages.length)
will add the value 25 + 4 to the arrayresponse
, D is the correct answer.
constgetSTring=(string,method=false)=>{if(method===true){returnstring.slice(1,4).length;}returnstring.substr(1,4).length;};console.log(getSTring("hello",true)+getSTring("hello"));
- A: 6
- B: 7
- C: 8
- D: 9
Answer
getString()
is an arrow function with two parameters. As you can see that the parametermethod
has the default valuefalse
, then if you do not pass any value to it when executing the function, the default value will be used.
The key thing to take note from the code above is the difference betweetslice(1, 4)
(which returns 3 characters) andsubstr(1, 4)
(which returns 4 ones).
Finallyconsole.log(getSTring("hello", true) + getSTring("hello"))
returns 7 becauseslice
andsubstr
are both used.
(function(a,b,c){console.log(Boolean([...arguments].slice(2,3)[0].slice(3,4)));})("hello","world","new zealand");
- A: "new"
- B: true
- C: "land"
- D: false
Answer
The code above is a self-executing function. It runs when it is being declared. We have three parameters and three arguments passed are"hello", "world"
and"new zealand"
.
First,arguments
returns an object consisting of arguments passed to the function when executing it. However, using spread operator...
, we then convert the object to an array. We can also do it by usingArray.from(object)
.
Second,slice(2, 3)
extracts the element from the index 2 to the index 3, which returns"new zealand"
. It is still an array. We then extract the element with the index[0]
and we get the string"new zealand"
rather than an array.
Third,"new zealand".slice(3, 4)
gives us an empty string (with a space between)" "
. TheBoolean(" ")
gives ustrue
. Noted that if there is no space in the empty string, we getfalse
instead.
So the correct answer is B.
classHocCoBan{name="hello world";getSlice(slice){returnthis.getName(slice).slice(true,this.name.length);}getName(space){returnthis.name.split(space);}}HocCoBan.prototype.split=function(argument){returnthis.getSlice(argument);};consta=newHocCoBan();console.log(a.split("").length);
- A: NaN
- B: true
- C: 10
- D: 11
Answer
The code above is nothing much special. However it is written in a complicated way on purpose. First, we have a class named "HocCoBan" with two methods and one property. Then we add another methodsplit
using the tradional way (viaprototype
). Note thatclass
in JavaScript is simply a syntactic sugar offunction
given thattypeof ClassName
returnfunction
.
When we call the methodsplit
, we pass the an empty string to it. This method then call other methods. The flow is as follows:
split("")
==>this.getSlice("")
==>this.getName("")
==>this.name.split("")
. Heresplit
is a built-in function that convert a string to an array.
Noted that ingetSlice()
, we also use.slice(true, this.name.length)
toslice
(cut) the array from the index 1 to 11. So the length is 10.
So the final answer is C.
This code might help us master the concept functionprototype
in JavaScript and the understand the difference between the built in functionString.prototype.split
and the function we declare by ourselfHocCoBan.prototype.split
.
functionjavaScript(node){letmot=node.includes("I") ?"love" :"you";returnfunction(deno=mot){lethai=node.replace(deno,"done");returnfunction(done=hai){return(node+deno+done).length;};};}console.log(javaScript("I love you")()());
- A: 18
- B: 24
- C: 20
- D: 25
Answer
Apart from learning some built-in functions to handle string such asreplace
andinclues
, we are reviving the concept ofcurrying function
in JavaScript. Say you want to declare a function with three parameters, you may consider refactoring the code by declaring 3 nested functions, each with one parameter you wish to pass to. Basically, both of them work in the same way. However, noted that only the outerest (the main) function has the name asjavaScript
in the code above. Both nested (inner) functions are declared without the name. We also use threereturn
keywords in the code.
When executing the function, you then have three()
as in thejavaScript("I love you")()()
. We do not pass any argument into the second and third functions (both are inner/nested functions without the name) and these functions will take the default value we have alreaded declared when being executing.
All in all, we have the final operatorreturn (node + deno + done).length;
in whichnode
is "I love you",deno
is "love" anddone
is "I done you". The length of these strings is 24, which you can calculate by yourself the concatenated stringI love youyou I done you
. Be aware of theempty space
, which is also taken into account.
constwww=["hello","coranovirus","kiora","world","new zealand"];constfound=www.find(function(world){returnworld>"victory";});constresult=found[1]<www[0][0] ?www[false ?1 :0] :www[true ?0 :1];console.log(result);
- A: "hello"
- B: "world"
- C: "victory"
- D: "w"
Answer
The key information in the question above is about the methodArray.prototype.find()
. It returns the first element in the array that meets the condition declared in the callback function, which is passed to the function. The array is being iterated to check every single element. In the code above, we might easily see that the elementworld
is the first element in the array that has a larger value thanvictory
. Remember that "w" > "v" return trues if the two letters are compared. When two words are being compared, only the first letter in each word is being utilised to compare.
As the result,found
is nowworld
and thusfound[1]
returns the letterw
whereaswww[0][0]
gives us the letterh
in the elementhello
. It meansfound[1] < www[0][0]
returnsfalse
.
So the final result iswww[true ? 0: 1]
orwww[0]
, which ishello
. And the correct answer is A.
(function(flag){letage=Boolean(NaN===NaN ?false :flag);console.log(age.toString()[Number(flag)]);})([]);
- A: "f"
- B: "t"
- C: true
- D: false
Answer
We have a self-executing function with the parameter/argument is an empty array. Noted thatNaN === NaN
returnsfalse
, thenage
gets the valueflag
, which is an empty array. However, the boolean value istrue
when we callBoolean([])
.
The functiontoString()
returns the stringtrue
and theNumber([])
returns0
. Then we get "t" in the console.log. The correct answer is B.
Keep in mind thatBoolean([])
==>true
butNumber([])
==>0
. And sadlyNaN === NaN
returnsfalse
.
1)console.log(Boolean([]));2)console.log(Number([]));3)console.log(Number(Boolean([])));4)console.log(Boolean(Number([])));5)console.log(Boolean({}));6)console.log(Number({}));7)console.log(Number(Boolean({})));8)console.log(Boolean(Number({})));9)console.log(Boolean(newBoolean(false)));
- A: true - 0 - 1 - false - true - 1 - 1 - false - false
- B: true - 0 - 1 - false - false - NaN - 1 - false - true
- C: true - 0 - 1 - false - false - false - 1 - false - false
- D: true - 0 - 1 - false - true - NaN - 1 - false - true
Answer
JavaScript is sometimes tedious to deal with given that it is a loosely type language. The data type of a variable can be changed depending on the value. An unexpected behaviour might unfortunately occur when you change/convert the original value to another one.
For example, the code 2Number([])
returns0
and 6(Number({}))
returnsNaN
, although both(Boolean([]))
and(Boolean({}))
returntrue
.
In the code 9Boolean(new Boolean(false))
, we gettrue
even though we pass into the function constructorBoolean()
afalse
(as the) parameter. However, if we do not use the keywordnew
, thenfalse
will return. It seems that inBoolean(new Boolean(false))
, we have a valid opreration, so it istrue
. However, in theBoolean(Boolean(false)))
where we do not use the keywordnew
, we then getfalse
because now afalse
value is being evaluated rather than an operation.
So, the correct answer is D.
Credit: @tiepphan, Vietnamese Angular Facebook group.
constmyYoutube={name:"hoccoban",address:"youtube.com/hoccoban",getInfo(){returnthis;},content:()=>(this===window ?myYoutube.getInfo() :this),};console.log(myYoutube.content().name);
- A: "hoccoban"
- B: window (object)
- C: NaN
- D: undefined
Answer
To answer the tricky question above, you might want to have a look at the concept ofthis
in JavaScript (on browser environment). By default,this
refers towindow
object. Note thatWindow
(written in capital) is the Function constructor of thewindow
object. In this regard,console.log(this === window)
return true butconsole.log(this === Window)
returns false.
Ascontent()
is an arrow function,this
declared inside this function points towindow
, somyYoutube.content()
returnsmyYoutube.getInfo()
. Noted that we have to explicitly writemyYoutube.getInfo()
to make sure the code will run correctly asthis
in this case does not work as it does not refer to the currect object. In the functiongetInfo()
, however,this
actually refers to the currect object instead ofwindow
object because we use a normal function here.
Then we have the propertyname
with the value "hoccoban". So the correct answer is A.
Credit: Thankshttps://github.com/phanvigiaii for fixing the typo. Please make a pull request when you have time bro. Cheer.
constmyArray=[1,2,3];myArray.someProperty=this;Array.prototype.someOtherProperty="hello";letresult=[];for(letkeyinmyArray){result.push(key);}for(letkeyinmyArray){if(myArray.hasOwnProperty(key)){result.push(key);}}console.log(result.length);
- A: 10
- B: NaN
- C: 9
- D: 7
Answer
We have a simple array that consists of 3 elements. If checking the type of the array with the operatortypeof
, we will haveobject
. (Hint, you can make use ofArray.isArray(array))
orarray instanceof Array
to check its type).
When declaringmyArray.someProperty
, we now add a new property to that array and when declaringArray.prototype.someOtherProperty = "hello"
, we add a new property to every single array.
As a result, thefor... in
loop will iterate through the array in question and return its key/property and the inherited property as well. However, in the second iteration, we take advantage of the methodhasOwnProperty(key)
to check whether a particular key/property actually belongs to the array in question rather than the inherited one.
In short, in the first iteration, we get 5 (3 original ones, 1 property that is directly added to the array, 1 inherited from the Array.prototype. In the second one, we only get 4 as the inherited property is not taken into consideration.
Keep in mind that, we usefor... of
to loop through an array or the traditionalfor
loop. It is not a good practice to usefor ... in
to loop through an array. It is often used to loop through an object.
constcoderfarm=[1,2,3,4,5];const[top, ...bottom]=(function(a){letresult=a;a.unshift(newArray(3));returnresult;})(coderfarm);console.log(top.length+bottom.length);
- A: 8
- B: 9
- C: 10
- D: 11
Answer
We are using destructure array (or object) technique to extract element of an array (or object). We also take advantage of...
(spread parameter) here.
The array we are destructuring is returned from a self-executing function. First we pass the parametercoderfarm
, which is the parametera
when declaring the function. Then we update this array with some additional value (an array with threeundefined
elements usingnew Array(3)
) on the top of the array (usingunshift
). The array is updated now as[[undefined, undefined, undefined], 1, 2, 3, 4, 5]
.
Sotop
is the first element of the array or[undefined, undefined, undefined]
, which returns 3 when we check the length.
Thebottom
returns the rest of the array in question, which is 5 when usinglength
property.
The final number is 8 and thus the correct answer is A.
letage={number:10};constgetAge=(flag)=>{flag ?deleteage.number :deleteage;returnage.number++;};console.log(getAge(false));console.log(age.number);console.log(getAge(true));console.log(age.number);
- A: 10 - 10 - NaN - NaN
- B: 10 - 10 - undefined - undefined
- C: 10 - 11 - undefined - undefined
- D: 10 - 11 - NaN - NaN
Answer
The operatordelete
only works on the property of an object, not the object itself. In the code snippet above, we have a simple functiongetAge
with the parameterflag
. When theflag
istrue
, we triggerdelete age.number
and if it isfalse
, we will use the operatordelete
upon the whole object.
As this operator does not work on an object, if we can say that, it turns out thatdelete age
actually does nothing. As such,console.log(getAge(false))
returns 10 and simultanously increases the value ofage.number
to 11. The value is now being kept in the memory. As such,console.log(age.number)
will return 11.
When we pass the argumentflag
astrue
in theconsole.log(getAge(true))
, we will triggerdelete age.number
which removes the value and the propertyage.number
itself. It meansage.number
is nowundefined
. However, because we also attempt to increase the value of thisundefined
property using++
operator, it returnsNaN
.
console.log(age.number)
also returnsNaN
as well. So the correct answer is D.
constyoutube={name:"hoccoban"};constcopy=Object.create(youtube);constcloneA=Object.assign({},copy);constcloneB=Object.assign({},youtube);console.log(cloneA.name);console.log(cloneB.name);console.log(copy.name);
- A: undefined - "hoccoban" - "hoccoban"
- B: "hoccoban" - "hoccoban" - "hoccoban"
- C: "hoccoban" - "hoccoban" - "undefined"
- D: undefined - "undefined" - "hoccoban"
Answer
We have three outputs in the code snippet above.
Firstconsole.log(cloneA.name);
will returnundefined
but why? We useObject.assign
to clone a new object from an empty and from the objectcopy
. The objectcopy
itself is actually created from the original objectyoutube
usingObject.create
. Noted that because we useObject.create
,copy
will inherit the data from the original one but it is still an empty object itself.
Second, bothconsole.log(cloneB.name)
andconsole.log(copy.name)
return "hoccoban" becausecloneB.name
will have the actual propertyname
. On the contrary,copy.name
outputs the propertyname
inherited from theyoutube
.
So the correct answer is A.
((x)=>{constdata=!Array.isArray(x) ?x :x.entries();console.log(data.next().value[1]);})(["hello","world","vuong"]);
- A: NaN
- B: "hello"
- C: "world"
- D: "vuong"
Answer
We have a self-invoking function here and we pass an array to it when the function is executed. Note thatArray.isArray(x)
returntrue
but actually we use!
beforeArray.isArray(x)
. It meansdata
will returnx.entries()
.
The methodarray.entries()
, as you might have already known, returns agererator
. Here we will callnext()
to iterate through each element. Note that if you only callnext()
once, it will only return the first element instead of the whole iterator.
Then when we callvalue
, it returns an array with the index and the value of the iterator. So what will we get if we call console.log(data.next().value[0])
. Sure, it returns0
as0
is the index.
So the correct answer is B.
letx=Symbol();lety=Symbol();console.log(x===y ?`${typeofx}`[1] :`${typeofx}`[2]);
- A: NaN
- B: "object"
- C: "y"
- D: "m"
Answer
Asx
andy
are both instances ofsymbol
, they are unique in our codebase; therefore, the===
comparison will returnfalse
as expected. In the simple code snippet above, we get theelse
operation.
It should be noted that thetypeof x
operation gives ussymbol
, and since a string in JavaScript is iterable, we getm
as we pass in the index 2.
So the correct answer is D.
constframeworks=["react","angular","vue"];constiterator=frameworks[Symbol.iterator]();consti=frameworks.entries();iterator.next();i.next();console.log(iterator.next().value[1]);console.log(i.next().value[1]);
- A: "react" - "angular"
- B: "react" - "react"
- C: "angular" - "angular"
- D: "n" - "angular"
Answer
Asframeworks
is an array, it has a built-in method namedSymbol.iterator
. You can hence iterate through the whole array using commonly used methods such asfor... of
, normalfor loop
,forEach
ormap
, among others. That is relatively trivial, I suppose.
This code challenge above is written to help us understand the concept of iteration better. First, we use the built-in method calledentries()
to create a new iteration. So doesSymbol.iterator. Both seem to do the same thing.
Each time we callnext()
method, the iteration will output one element. We then can callvalue()
to get the value. The difference betweeniterator
andi
is that the former shows the value itself while the latter outputs an array consisting of the index and the value. It means that in the code above,iterator.next().value
returnsangular
andi.next().value
gives us[1, angular]
.
So the correct answer is D.
classReact{theName="Not React";}classAuthorextendsReact{statictheName="Real React";render(){returnthis.theName;}staticrender(){returnthis.theName;}}constme=newAuthor();console.log(me.render());console.log(Author.render());
- A: "Not React" - "Real React"
- B: "Not React" - Error
- C: Error - Error
- D: Error - "Real React"
Answer
We have two classes in the code snippet above. It sounds we are imitating React. TheReact
class has only one property namedtheName,
and no method is declared here. Providing thatAuthor
extends theReact
class, it inherits that property, surely. However, we have also declared another property with the same name in theAuthor
classs. The difference is that the property declared in the child class is given the keywordstatic.
TheAuthor
class also has two methods with the same namerender()
, one as regular methods and another withstatic
keyword. Will that work in JavaScript?
It turns out that JavaScript is quite flexible. It supports both property and method if they are declared with the same name as long as they are either regular property (or method) or static property (or method).
The last thing you should be aware of is that the methodstatic render()
only calls the static property, here isstatic theName = "Real React";
So does the regular methodrender().
As such, the code does not run into any issues.
So the correct answer is A.
classjs{say="hello";}js.prototype.say="goodbye";console.log(newjs().say);js.prototype.thename="google";console.log(newjs().thename);
- A: Error - Error
- B: "hello" - "google"
- C: "goodbye" - "google"
- D: Error - "google"
Answer
js
is a standard class declared in the code snippet above that has only one property with the namesay.
Then we again declare another property with the same namesay
for it. You might think that the propertysay
has been overwritten with a new valuegoodbye.
That is not the case as we will gethello
when we runconsole.log(new js().say);
. It is clear that the JavaScript engine prioritizes the property declared inside the class more than the property declared later using the prototype mechanism.
If the property has not been declared inside the class itself, we can then add a new one with the help ofprototype
as inthename
. Without the doubt, the codeconsole.log(new js().thename);
gives usgoogle
as expected.
So the correct answer is B.
constApp=([y,x,z])=>{return()=>{++x;return()=>{returnx++;};};};console.log(App([10,20,30,40])()());
- A: 10
- B: 32
- C: 21
- D: 22
Answer
To answer the question raised on the above code snippet, you might want to revisit two concepts,currying function
anddestructing array or object.
First,currying function
means we convert a function with multiple parameters into multiple functions with a SINGLE parameter. Then you can easily manipulate the flow of the data. Noted thatcurrying function
is relevant tohigher-order function
, you might want to have a look.
destructing array or object
means we attempt to extract a complex array or object more conveniently. For example,[y, x, z] = [10, 20, 30, 40]
will extract y, x and z with the value 10, 20 and 30 respectively.
The last thing is incremental operator here++x
returns 21 butx++
does not as it still returns 21.
So the correct answer is C.
constnumbers=[5,6,7];functioncallback(accumulator,currentValue){returnaccumulator+currentValue;}consttheCallBack=(accumulator,currentValue)=>accumulator+currentValue;constsum=numbers.reduce(callback,numbers.reduce(theCallBack,numbers.reduce(theCallBack,7)));console.log(sum);
- A: 54
- B: 55
- C: 60
- D: 61
Answer
Array.prototype.reduce()
is a bit perplexed built-in method that allows you to manipulate data in an array. It returns a single value from the array predefined as in the case withmap
orfilter
. The syntaxt of the function isarr.reduce(callback( accumulator, currentValue, [, index[, array]] )[, initialValue])
, so it accepts a callback function with four arguments includingaccumulator
,currentValue
,currentIndex
(optional) andarray
(optional).
The second argument of thereduce
method, which is optional, is calledinitialValue
that will be counted as the first element with the index 0 whenreduce
is executing. IfinitialValue
is not provided, thenreduce
will run with the index 1 instead.reduce()
sounds complicated, but truly it is not. In case you want to revise the function, kindly take a look at MDN here:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
The above code has two callback functions namedcallback
andthecallback
, which do the same thing. The seemingly creepy code is the variablesum
, which is returned by a couple of nestedreduce
functions. It turns out that there is only one "real"reduce
function and the other ones give usinitialValue
only.
- The first
initialValue
is 7; - The first nested
reduce
function gives us 7 (initialValue) + 5 + 6 + 7 = 25. - The second nested
reduce
has 25 as the initialValue, which we get from the above. Then it returns 25 + 5 + 6 + 7 = 43; - The "real"
reduce
function now has 43 as the initialValue, the we get the final result: 43 + 5+ 6 + 7 = 61.
So the correct answer is D.
consta={name:"hoccoban.com"};constb={name:"youtube.com/hoccoban"};constfirst={ ...a}.name.length;constsecond={ ...a, ...b}.name.length;constthird={ ...a, ...b,name:"hello"}.name.length;console.log(first+second+third);
- A: 12
- B: 37
- C: 5
- D: 20
Answer
The code snippet above is relatively trivial. What we can learn from it is all about thespread operator
(three-dot ...). Sometimes it is also used as arest operator
to extract data from an object or array.
We have two simple objects which both have the same keyname
but different values. The constantfirst
gives us the length of the string value of the keywordname
that is copied froma
. So,first
is now 12.
The constantsecond
mergesa
andb
into one object. However, asb
has the same keyname
witha
, the object created by merging two objects will have the value ofb
. It means the constantsecond
gives us the length ofyoutube.com/hoccoban
, which is 20.
third
does the same thing withfirst
andsecond
as it merges two objects into one. However, it also adds another key-value to the object. Coincidently, the key now isname
, which is the same with the key attained froma
andb
. Hence, this key and value will take over the merged object. That meansthird
is the length of the stringhello
, which is 5.
In total, we have 12 + 20 + 5, and the final result is 37.
So the correct answer is B.
consthocCoBan={};Object.defineProperty(hocCoBan,"domain",{value:"hoccoban.com",});asyncfunctionApp({ year, age}){returnyear-age+hocCoBan.domain.length;}App({year:2021,age:30}).then((r)=>console.log(r));
- A: 2051
- B: 2001
- C: 30
- D: 2003
Answer
The code snippet above seems complicated regarding how we take advantage ofObject.defineProperty
to add key and value to the objecthocCoBan
. In fact,Object.defineProperty
has a couple of handy features that allow us to control the behavior of the object in some situations where we want to make sure that the object created is mutable or not, whether it is iterable (usingfor..in
) and so for. For example, if we setconfigurable: false
when we declare an object withObject.defineProperty
, we cannot usedelete
operator to delete the object's property. We cannot change the value of that property as well.
The second "take away" message when reading the code above is the unpacking object technique, or a more frequent term is the destructing object. Say you have an object with two keys calledyear
andage
, then you can get them by using the destructing object technique as follows:{year, age} = theOBject;
. In the code above, when declaring the functionApp
, we also use destructing object technique to get the key from the object and use them as the parameters.
If you are familiar with asynchronous code in JavaScript when using the keywordasync,
it is not a big deal to understand why we need to usethen
to get the functionApp
being called. It fact,async
always returns a promise, so we need to usethen
method to get the data we want.
The flow of the code is: 2021 - 30 +"hoccoban.com".length
(which is 12).
The final result is 2003. So the correct answer is D.
classhoccoban{ #thisyear=2021;constructor(covidTheFirstYear){this.covidTheFirstYear=covidTheFirstYear;}getThisYear(){returnthis.#thisyear;}getCovidFirstYear(){returnthis.covidTheFirstYear;}}constmessage=newhoccoban(2019);constresult=hoccoban.hello??message.getThisYear()-message.getCovidFirstYear();console.log(result);
- A: NaN
- B: 2019
- C: undefined
- D: 2
Answer
This challenge partly illustrates the newest features of JavaScript detailed in ECMAScript 2020 or ES11.
Now you can declare a private property in a class thanks to the symbol#
. Like other languages, a private property in JavaScript can only be accessed from inside the class. It will trigger an error when you attempt to call it outside the class, surely.
The second feature you might see on the code snippet above is thenullish coalescing operator
or??
. When declaring some variable such aslet myVariable = number ?? 7
, if the variablenumber
is eitherundefined
ornull
, the variablemyVariable
will be assigned the value7
.
Sohoccoban.hello
meansundefined
because we have not added any value yet. Then by usingnullish coalescing operator
with??
the variableresult
simply returns 2 asmessage.getThisYear()
gives us 2020 andmessage.getCovidFirstYear()
gives us 2019. Note that we can access the private property outside of the class via a method, as in the methodgetThisYear()
.
So the correct answer is D.
constkeyWords="hello world";constentries=keyWords.split(" ");constcollections=[];entries.forEach((entry,index)=>{collections.push([entry,index]);});constobjectResult=Object.fromEntries(collections);const{ world}=objectResult;console.log(world);
- A: 0
- B: true
- C: 1
- D: "hello"
Answer
The code snippet above is not challenging for those who have had decent experience working with ES6 I suppose. First we turnkeywords
into an array usingsplit()
function. Then we create a variable namedcollection
, which initially is an empty array.
Take a closer look at theforEach
function, which allows us to run a for loop through the whole arrayentries
, you might realize thatpush([entry, index]);
add an array tocollections
rather than an element.
The next step is by taking advantage ofObject.fromEntries()
that converts an array with at least two elements (the form of key-value) to an object. This built-in method is the reversing version ofObject.entries()
, which extracts key and value from an object to an array.
const { world } = objectResult;
is nothing special as we unpack the object using destructing object technique supported since ES6. As the objectobjectResult
hashello
andworld
with two respective values 0 and 1, we get 1 when printing outworld
, so the correct answer is C.
consttarget={domainname:"hoccoban.com",author:"vuong",};consthandler={get:function(thetarget,prop,receiver){if(prop==="domainname"){returnthetarget.author.length;}else{returnthetarget.domainname.length;}},};constproxyObject=newProxy(target,handler);console.log(proxyObject.domainname>proxyObject.author);
- A: true
- B: false
- C: 12
- D: 5
Answer
We have implemented a basic use case ofProxy
in the code snippet above. EachproxyObject
object has two parameters (target
andhandler
).handler
is also an object.
Apart fromget()
as you might see,handler
also has a handful of other methods such asset
,defineProperty()
,has()
and so forth. Sometimes, people may say amethod is a trap
of a proxy object.
Back to the code above, theget
method allows us to modify how the proxy object will display the value of the original object.thetarget
is the original object, andprop
is the property of that object as you might guess. You might choose another name in theget
function if you want when creating your handler.
Thehandler
above calculates the length of the string value of the two properties. Based on the flow ofif - else
code, it swaps the returned value.
SoproxyObject.domainname
now should be understood astarget.author.length
which means 5 andproxyObject.author
meanstarget.domainname.length
which gives us 12. So the output isfalse
. The correct answer is B.
If you do the same thing with the original, it should be something likeconsole.log(target.domainname.length > target.author.length)
which returnstrue
.
I believe thatProxy
is worth to have a closer look. If that is the case, no place is better than MDN. So have a go at:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
constpromise1=newPromise((resolve,reject)=>{setTimeout(()=>resolve("hello"),5000);});constpromise2=newPromise((resolve,reject)=>{setTimeout(()=>resolve("world"),4000);});(async()=>{console.time("timeleap");constp1=awaitpromise1;constp2=awaitpromise2;console.log(`${p1}${p2}`);console.timeEnd("timeleap");})();
- A: Promise { } - "hello world" - timeleap: ~ 5000 ms
- B: Promise { } - "hello world" - timeleap: ~ 9000 ms
- C: Promise { } - "hello world" - timeleap: ~ 4000 ms
- D: Promise { } - "hello world" - timeleap: ~ 1000 ms
Answer
We have already had a couple of questions regarding asynchronous code in general and handling the data flow with promise in particular. If you understand how JS works, I am sure that the code challenge above is not difficult.
We have two promises; each takes 5 or 4 seconds to complete the code and returns "hello" (inpromise1
) and "world" (inpromise2
) in theresolve
methods, respectively.
Then we take advantage of theasync
function to chain the two promises to get the result we want. Asasync
function returns apromise
so to get the returned value fromasync
function, we have to usethen()
method. As we do not do that here, then we getPromise { <pending> }
.
The question is, doesp2
have to wait and only run afterp1
complete? It turns out that it does not. Bothp1
andp2
run simultaneously in the task queue thanks to web API or nodejs API (the environments by which JavaScript engine runs). So it will not take 9 seconds to finish the code but solely around 5. It meanspromise1
takes 5 seconds to complete and at the same time,promise2
reaches the bottom within only 4 seconds.
That is why A is the correct answer.
Updated: What happens ifpromise2
takes 6 seconds instead of 4 ? Well, aspromise2
runs almost at the same time withpromise1
, it will only take 1 second after thepromise1
completes. So in total, it takes approximately 6 seconds.
constpromise1=()=>{returnnewPromise((resolve,reject)=>{setTimeout(()=>resolve("hello"),5000);});};constpromise2=()=>{returnnewPromise((resolve,reject)=>{setTimeout(()=>resolve("world"),4000);});};(async()=>{console.time("timeleap");constp1=awaitpromise1();constp2=awaitpromise2();console.log(`${p1}${p2}`);console.timeEnd("timeleap");})();
- A: Promise { } - "hello world" - timeleap: ~ 5000 ms
- B: Promise { } - "hello world" - timeleap: ~ 9000 ms
- C: Promise { } - "hello world" - timeleap: ~ 4000 ms
- D: Promise { } - "hello world" - timeleap: ~ 1000 ms
Answer
The 72nd challenge is almost identical to the 71st. Please take a closer look.
The difference lies in the way we declare a promise. In question 71st, we use two constants, and both return promise, but in question 72, we declare functions and each returns a promise.
If you run the code, you might be surprised with the result as it takes around 9 seconds to complete the code in place of 5 seconds as in the previous question.
It means thatconst p1 = await promise1;
andconst p1 = await promise1();
are different as the latter (a function) might block the callstack andconst p2 = await promise2();
can only be called after thep1
completes. The two do not run in parallel as the two promises in the previous question.
As it takes 9 seconds to finish, B is the correct answer.
lethistory={year:2021,getYear:function(){console.log(this.year);},};setTimeout(history.getYear,0);setTimeout(history.getYear.bind(history),10);const{ year, getYear}=history;getYear();
- A: undefined - undefined - 2021
- B: undefined - 2021 - 2021
- C: 2021 - undefined - 2021
- D: 2021 - 2021 - 2021
Answer
We have three outputs on the code above. First, we have a simple object with one property and one method. Noted that the method point to the propertyyear
usingthis
keyword. The problem now happens when we attempt to extract data from the object.
Be aware of thesetTimeout
method, which will create a separated context that is different from the original object's context. Even though insetTimeout(history.getYear, 0);
we have explicitly called the objecthistory
, setTimeout will still execute the functionhistory.getYear
withthis
pointing to the global object. So it returnsundefined.
getYear();
is extracted from the object we have defined in the beginning. But asthis
is out of the original context when executing the function, it returnsundefined
. This code is called last, but the output is displayed first on the console window as it is a synchronous code.
setTimeout(history.getYear.bind(history), 10);
runs last and will give us 2021 as it is bound to the objecthistory
. Finally, we getundefined - undefined - 2021,
and A is the correct answer.
classhandleCovid{constructor(start){this.start=start;}calculate(someValue){this.start=this.start+someValue;returnthis.start;}vaccine(){++this.start;returnthis;}delaying(){++this.start;returnthis;}staticgetFinal(result){returnresult*2;}}constnow=newhandleCovid(2019);console.log(handleCovid.getFinal(now.vaccine().delaying().calculate(2020)));
- A: 2019
- B: 8082
- C: 8080
- D: 8084
Answer
The code snippet above is ugly and sounds complicated at first. Yet, you might encounter a situation when some good "take away" messages might be given. The flow of the code is not hard to understand, I suppose.
First, a function in JavaScript can accept another function as its parameter. With regard to thestatic
keyword, it means we can directly call a static method in the form ofclassName.staticmethod
without invoking the object created by the normal waynew ClassName
.
Besides, you might want to have a look at how we chain more than one method together. That is possible if these methodsreturn this
.
Now let break it down:
calculate(2020)
--> 2019 + 2020 = 4039;delaying().calculate(2020)
--> 4040;now.vaccine().delaying().calculate(2020)
--> 4041;handleCovid.getFinal(now.vaccine().delaying().calculate(2020)
--> 4041 * 2 = 8082;
So the correct answer is B.
functionHappyNewYear(){return"hello";}constyear2021=newHappyNewYear();year2021.__proto__.greeting="happy";HappyNewYear.prototype.say="new year";console.log(year2021.__proto__===HappyNewYear.prototype);console.log(Object.getPrototypeOf(year2021)===HappyNewYear.prototype);console.log(Reflect.getPrototypeOf(year2021)===HappyNewYear.prototype);console.log(year2021.__proto__===Object.prototype);console.log(year2021instanceofHappyNewYear);console.log(year2021instanceofObject);constthisyear=newHappyNewYear();console.log(`${thisyear.greeting}${thisyear.say}`);
- A: true - true - true - false - true - false - "happy new year"
- B: true - true - true - false - false - true - "happy new year"
- C: true - true - true - true - true - true - "happy new year"
- D: true - true - true - false - true - true - "happy new year"
Answer
The code snippet above helps us revise the concept ofprototype
in JavaScript with two essential keywords:__proto__
andFunctionName.prototype
. I believe that the codeconsole.log(year2021.__proto__ === HappyNewYear.prototype);
is the key to understand the difference between the two. So, in short, every single object in JavaScript has a built-in property__proto__
that gives us an overview of the built-in (internal) [[Prototype]]. They are the things (property and method) the object inherits from the "parent" function constructor or class).
For example, if you declare a literal object such asconst a = {}
thena.__proto__ === Object.prototype
returnstrue
becausea
inherits the prototype from the "parent"Object
. However, if an object is created using function constructor then the "parent" prototype is function constructor itself instead of theObject
. So whileconsole.log(year2021.__proto__ === HappyNewYear.prototype);
returnstrue
,console.log(year2021.__proto__ === Object.prototype);
gives usfalse
.
Be aware ofObject.getPrototypeOf (object)
andReflect.getPrototypeOf(object)
. The two are recommended to use as__proto__
is being deprecated.
You might want to read more about__proto__
at MDNhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
The correct answer is D, and btw "happy new year"!
constaddress={name:"hoccoban.com",author:"Vuong Nguyen",};constkey=Reflect.has(address,"author") ?Reflect.ownKeys(address)[0] :"hello";Reflect.set(address,"language","JavaScript");consttotalKeys=Reflect.ownKeys(address).length;constname=Reflect.get(address,key).length;constlanguage=Reflect.get(address,"language").length;console.log(totalKeys+name+language);
- A: 22
- B: 10
- C: 20
- D: 25
Answer
The correct answer is D. Why? Now let break it down:
Reflect.has(address, 'author')
gives ustrue
given that the objectaddress
has the keyauthor
. Simple as it is. So the value of the variablekey
is nowReflect.ownKeys(address)[0]
, which in fact is the keyname
.Reflect.set(address, 'language', 'JavaScript');
set another key-value to the objectaddress
.Reflect.ownKeys(address).length;
gives us 3 because now it has three keys, sototalKeys
is now 3.Reflect.get(address, key).length;
gives us the length of the stringhoccoban.com
which is 12.Reflect.get(address, 'language').length
is the length of the stringJavaScript
, which is 10.The final answer is 3 + 12 + 10 = 25.
constmyModule=(function(){constcovidYear=2019;constyear=2021;functiongetYear(){returnyear;}functiongetCovidYear(){returncovidYear;}functionexposeYear(){returngetYear();}functionexposeCovidYear(){returngetCovidYear();}return{nothing:undefined??null??null??undefined, exposeYear, exposeCovidYear,};})();constresult=myModule.nothing??myModule.exposeYear()+myModule.exposeCovidYear();console.log(result);
- A: 2021
- B: 2019
- C: 4040
- D: undefined
Answer
The challenge above will help you revise therevealing pattern
and thanks to it you can declare a private variable in JavaScript. Note that we can now declare aprivate
property in a class in modern JavaScript, so the above way of writing a private variable seems old-fashioned.
First, we have an IIFE function - immediately invoked function expressions. There are two variables and two functions as well. However, in thereturn
, there are three key-values. We can not directly access the two variablescovidYear
andyear
except for using some already-built functions inside the IIFE.
If you feel the keyword??
is odd, then you might want to have a look at the latest syntax supported in modern JavaScript called "Nullish Coalescing Operator". It means, if the left element is eitherundefined
ornull
, the value of the right element will be assigned.
In short, we havemyModule.exposeYear()
(2021) andmyModule.exposeCovidYear()
(2019). In total, the final result is 4040. So the correct answer is C.
classHocCoban{constructor(address){this.address=address;this.youtube="";}getgetAddress(){returnthis.address;}setsetYoutube(channel){this.youtube=channel;}getYoutube(){returnthis.youtube.length;}}constweb=newHocCoban("hoccoban.com");web.setYoutube="youtube.com/hoccoban";console.log(web.getAddress);console.log(web.youtube);console.log(web.getYoutube());
- A: "hoccoban.com" - "youtube.com/hoccoban" - 20
- B: "hoccoban.com" - function() - 20
- C: function() - "youtube.com/hoccoban" - 20
- D: function() - function() - 20
Answer
set
andget
are commonly called setter and getter. When declaring a method in a class and putting the keywordset
orget
before it, you can then call them without usingparenthesis - ()
. Put another way, when usingget
andset
, you can directly get or set the value of/for the properties. Somehow it might be convenient in some cases.
Be aware of the methods declared with agetter
as we just need to call the method as we call a property (without using parenthesis).
If you know how a traditional method works in JavaScript, then the code challenge above is not difficult, I suppose. The answer is A.
constresult=["ronaldo","messi","neymar","Ronaldo","LuKaKUUUU"].sort();console.log(result);
- A: ["LuKaKUUUU", "Ronaldo", "messi", "neymar", "ronaldo"]
- B: ["LuKaKUUUU", "messi", "neymar", "Ronaldo","ronaldo"]
- C: ["LuKaKUUUU", "messi", "neymar", "ronaldo", "Ronaldo"]
- D: ["messi", "neymar", "ronaldo", "Ronaldo", "LuKaKUUUU"]
Answer
In JavaScript, the built-insort()
method sorts the elements of an array. It returns a sorted array in ascending order. Note that each element will be converted to strings and then compared according to the sequences of UTF-16 code unit values. What does it mean?
It means, "banana" < "cherry" or 80 < 9 (because "80" < "9" in the Unicode order).
If you run the following codeconst result = [9, 11, 89].sort();
, the constantresult
will be sorted as[11, 8, 9]
rather than[9, 11, 89]
because the engine will convert the number value to string.
The following codes might give you a hint about the relationship between character and number. Ultimately, as the computer can only understand 0 and 1, all characters and even decimal numbers are then converted to 1 and 0.charCodeAt()
gives us the decimal value of any string evaluated.
console.log("LuKaKUUUU".charCodeAt(0))
orconsole.log("LuKaKUUUU".charCodeAt())
==> 76console.log("Ronaldo".charCodeAt(0))
orconsole.log("Ronaldo".charCodeAt())
==> 82console.log("messi".charCodeAt(0))
orconsole.log("messi".charCodeAt())
==> 109console.log("neymar".charCodeAt(0))
orconsole.log("neymar".charCodeAt())
==> 110console.log("ronaldo".charCodeAt(0))
orconsole.log("ronaldo".charCodeAt())
==> 114console.log("9".charCodeAt())
orconsole.log("99".charCodeAt())
==> 57console.log("80".charCodeAt())
orconsole.log("8".charCodeAt())
==> 56
Noted that if index is not a number, it defaults to 0. The answer is A.
constanArray=typeof[];constaTypeOfNull=typeofnull;constweirdFirst=nullinstanceofObject;constweirdSecond=[]instanceofObject;constweirdThird=[]instanceofArray;console.log(anArray);console.log(aTypeOfNull);console.log(weirdFirst);console.log(weirdSecond);console.log(weirdThird);
- A: "array" - "null" - false - true - true
- B: "array" - "object" - false - true - true
- C: "object" - "object" - false - false - true
- D: "object" - "object" - false - true - true
Answer
In the 80th challenge question, we will review some fundamental "issue" or "weird" features in JavaScript relating to thetypeof
andinstance
operators. Given that the original version of the JavaScript language was designed in just 10 days, there are a bundle of inconsistent behaviors that cannot be fixed. They are permanent features existing in the modern language. If we fix it, a lot of websites might crash.
The above code shows us some of the weird features in JavaScript. For example,[]
is an array but thetypeof []
gives usobject
. Note that you might take advantage ofArray.isArray([])
rather thantypeof
to examine whether a variable is an array or not.
typeof null;
is another weird operator as it returnsobject
. Howevernull instanceof Object;
returnsfalse
.WhatTheHell!!!
Man,[] instanceof Object;
and[] instanceof Array;
both returntrue
. How inconsistent it is.
The answer is D.
classDog{speak(){returnthis.say();}say(){console.log("hello world");}}classCat{speak(){returnthis.say();}say(){console.log("kia ora");}}constanimal=newDog();animal.speak();Object.setPrototypeOf(animal,Cat.prototype);animal.speak();
- A: "hello world" - undefined
- B: "kia ora" - "kia ora"
- C: "hello world" - "kia ora"
- D: "hello world" - "hello world"
Answer
The central issue/concept mentioned in the code above is the methodObject.setPrototypeOf(object, prototype)
. It is one of the features in ES6, or ECMAScript 2015. Another way to set the prototype of an object isObject.prototype.__proto__
but the latter is controversial.
At first,animal.speak();
gives us "hello world" which is no surprise. Yet, in the second call, we get "kia ora" instead of "hello world". When checking the prototype withObject.getPrototypeOf(animal)
, you might see thatCat
is the prototype of the objectanimal
rather thanDog
.
The answer is C.
By the way,kia ora
meanshello
in the Māori language.
constjs=[9,10];functionmutate(a,b){a.push(b);}mutate(js,1);console.log(js);
- A: [9, 10]
- B: [9, 10, 1]
- C: [1, 9, 10]
- D: ReferenceError
Answer
The code snippet might be pretty trivial if you have already obtained a solid understanding of the two different concepts:reference
andvalue.
In JavaScript, non-primitive type such as array and object does not store the value but the reference.
Also, as the arguments in function are passed by the reference, the functionmutate
will push another element into the arrayjs
. Finally, the initial variable 'js' is updated with the new value[9, 10, 1]
.
If the variablejs
is assigned a primitive value such as string or number, no matter how the functionmutate
, it will not mutate the initial variable 'js'. However, if the variable is an object, then it will also be mutated, as in the case of an array in the code above.
B is the correct answer.
console.log(this===window);console.log(this===frames);console.log(this===globalThis);console.log(this===self);console.log(this===global);
- A: true - true - true - true - "ReferenceError"
- B: true - false - true - true - "ReferenceError"
- C: true - true - true - true - true
- D: true - true - "ReferenceError" - true - "ReferenceError"
Answer
The code snippet above might output different results if running on other environments than the browser. For example, there is noself
,window
, orframes
on Nodejs.
global
plays the role of the global object in Nodejs, but that is not the case in the browser environment. In contrast,globalThis
is available in both browser and Nodejs environments.
The first takeaway message is that Nodejs does havethis
,global
, andglobalThis
. Browser environment has 5 ones includingthis
,globalThis
,window
,frames
, andself
.
The second takeaway message is that Web Worker only hasself
as the global object.
Ultimately, A is the correct answer.
classStackHocCoBan{constructor(){this.stack=[];}push(thing){returnthis.stack.push(thing);}pop(){returnthis.stack.pop();}peek(){returnthis.stack[this.length-1];}getlength(){returnthis.stack.length;}isEmpty(){returnthis.length===0;}}constfirstThing=newStackHocCoBan();firstThing.push(firstThing.length);firstThing.push(firstThing.length);!firstThing.isEmpty() ?firstThing.push(firstThing.length) :firstThing.length;firstThing.pop();console.log(firstThing.peek()+firstThing.length+firstThing.pop());
- A: 3
- B: 4
- C: 5
- D: 6
Answer
The code challenge above is a bit lengthy, frankly. But it might practically help you to revise the concept ofstack
implemented in JavaScript. Such a concept is quite crucial when it comes to the algorithm, so to say. It appears thatstack
andqueue
are blood brothers, and as a developer, you are always advised to master these concepts along with array, linked list, tree, graphs, and so on.
In my opinion, bothstack
andqueue
are simply arrays, but they are exclusively built to serve some particular jobs with strict requirements. You might seepop()
orpush()
in the code above are standard native methods we often use when working with the array.
So nowfirstThing
is an object initiated by the classStackHocCoBan
. As the class's construct initially triggers an empty array this.stack = [];
, first the codefirstThing.push(firstThing.length);
will actually push the number 0 into the array given thatfirstThing.length
returns 0 as the stack, at the beginning` is empty.
ThenfirstThing.push(firstThing.length);
(the second one) pushes number 1 to the stack as we have already had one item (the number 0).
firstThing.isEmpty()
returnsfalse
because we have two things in the stack. Yet, be causious with "!" before it. As we write!firstThing.isEmpty()
, the code with callfirstThing.push(firstThing.length)
rather thanfirstThing.length;
. It is a simply short-hand ofif-else
.
So, the stack is pushed the number 2 becausefirstThing.length
returns 2. So now the stack is as [0, 1, 2], beautiful, right?
firstThing.pop()
will eliminate the number 2 and the stack is now [0, 1].
The last line of the code above isfirstThing.peek()
(1) +firstThing.length
(2) +firstThing.pop()
(1).
So B is the correct answer.
classQueueHocCoBan{constructor(){this.queue=[];}enqueue(item){returnthis.queue.unshift(item);}dequeue(){returnthis.queue.pop();}peek(){returnthis.queue[this.length-1];}getlength(){returnthis.queue.length;}isEmpty(){returnthis.queue.length===0;}}constitems=newQueueHocCoBan();items.enqueue("constructor");items.enqueue("QueueHocCoBan");items.enqueue("hoccoban.com");constitem=items.peek().length-items.length;console.log(item);
- A: 6
- B: 7
- C: 8
- D: 9
Answer
Following up the question 85th, we now pay the attention to another important concepts -queue
- which is a bit different fromstack
. Whilestack
leverages two native array methodspush()
(for adding new item) andpop()
(for extracting new item),queue
utilisesunshift()
(for adding new item) andpop()
(for extracting new item). In essense, bothstack
andqueue
are array and thus the difference between them, IMO, lays in the waypush()
andunshift()
are implemented for adding new item. Whilepush()
adds a new item/element at the end/tail of the array,unshift()
adds the new one to the top/head of the array itself.
First, the objectitems
will add three new elements into the array (initiated by the constructor) at the top one by one, thanks to the methodenqueue
. The array will look like this ["hoccoban.com", "QueueHocCoBan", "constructor"];
Nowitems.peek()
gives us "constructor" and thusitems.peek().length
returns 11.items.length
simply returns 3 and so the final result will be 8.
So C is the correct answer.
By way of summarisation, usingqueue
, we can only take out the first element (also the tail of the array) with the methoddequeue().
You might need to find another way to extract other elements of the queue.
constdomains=newMap();domains.set("site","hoccoban.com");domains.set("youtube","youtube.com/hoccoban");constkeys=domains.keys();constvalues=domains.values();letresult=domains.has("hoccoban.com") ?values.next().value :keys.next().value;console.log(result);
- A: "site"
- B: "hoccoban.com"
- C: "youtube"
- D: "youtube.com/hoccoban"
Answer
There are two ways hash tables are implemented in #"auto">While the native object defined as {} is trivial for a JavaScript developer, a new way to design a hash table has been recently added into the language. When writingconst domains = new Map();
, we have declared an object with a couple of different features as opposed to the veteran one declared in the form of{}
ornew Object
we all know.
You are advised to take advantage of the built-in methods such asset()
,get()
,has()
ordelete()
among others to manipulate the map object.
Note that a map object can be iterated usingfor of
. You might need to usenext().value
to extract the raw information written. At this point, you might want to revisitfunction generator
to see why we need to do that.
Bothkeys()
andvalues()
are native methods of the classMap
. You might see that they works on a map object as in a normal object. Back to the code snippet above,let result = domains.has("hoccoban.com") ? values.next().value: keys.next().value
returnskeys.next().value
given thatdomains.has("hoccoban.com")
returnsfalse
.
Soconsole.log(result)
gives us "site", so A is the correct answer.
Note that if you want to extract "youtube", you must runkeys.next().value
twice.
functioninner(flag){hello=10;if(flag){return++hello;}return--hello;}varhello=12;inner(hello>11 ?false :true);console.log(hello);
- A: 9
- B: 10
- C: 11
- D: 12
Answer
As a variable in JavaScript can be declared without any functional keyword such as var, let, or const standing before the variable name, as seen on the code above, this challenge sounds a bit odd as now developers tend to useconst
orlet
everywhere. What happened when we do that? The variable will have a global scope no matter where it has been written initially. So first, the variablehello
will be accessed anywhere outside of the function scope whenever (after to be exact) the function inner has been executed.
Then we redeclare thehello
variable with a different value.
The codeinner(hello>11? false: true)
is translated toinner(false)
, so the variablehello
declared inside this function is mutated to 9.
Ashello
is now 9 instead of 12, A is the correct answer.
constcollections=["a",[123],true,"c",{abc:"hello world"}];constiterator=collections.values();consta=iterator.next().value.length;constb=iterator.next().value.length;constc=iterator.next().value.toString().length;constd=iterator.next().value.length;conste=Object.values(iterator.next().value)[Number(a>b)].length;console.log(a+b+c+d+e);
- A: 12
- B: 14
- C: 16
- D: 18
Answer
The code snippet above is frankly tedious as it does not solve any big problem but is still written in a very cryptic manner, honestly. I want you to pay a bit more attention to the native function to manipulate arrayvalues()
. For your information, I also useObject.values()
so that you can somehow make a comparison between the two by yourself.
In the beginning, we have a very simple array packed with different types of data such as boolean, string, array and object. The codecollections.values();
returns an iterator, so you can not simply access to each element as an usual array. You might run afor of
loop here to render all of the elements in this iterator. By doing that, the way iterator works is likely a typical array.
So how do we access a single element in this iterator? We need to usenext().value
. Each time we call it, the iterator will render the value, one by one, starting with the first element.
It meansconst a = iterator.next().value.length;
returns 1. So a is 1. So does b. C is a bit different and we have 4 here astrue
, a boolean, is converted to a string. d is 1. So
The code in e is not fascinating, I suppose.Object.values
gives us an array of value defined in the object{ abc: "hello world" }
.[Number(a > b)]
give us [0]. So e is simply the length of the string "hello world", which is 11.
Finally, in the console we have 1 + 1 + 4 + 1 + 11 = 18. So D is the correct answer.
constmatrix=[[1,2,3],[4,5,6],[7,8,9],];functionmatrixHandle(m){lettotal=arguments[0][0][0];letlength=m.length;for(leti=0;i<length;i++){for(letj=0;j<m[i].length;j++){total+=m[i][j];}}returntotal;}console.log(matrixHandle(matrix));
- A: 44
- B: 45
- C: 46
- D: 47
Answer
You can easily create a two-dimensional array by nesting an array inside the parent one as the variable `matrix` above. To render all of the elements in the matrix, we implement a simple code with two for-loop functions which are nested.
arguments[0][0][0];
gives us 1 becausearguments
has wrapped the variablematrix
in an array. Note thatarguments
is a Array-like.
So the variabletotal
at first is 1, and then the final value cumulated by looping through the matrix is 46.
In short, we have 1 + 1 + 2 + 3 + 4 + 5 + 6 + 7+ 8 + 9 = 46. So C is the correct answer.
constcontainer1={stack:"Docker",getStack:function(){returnthis.stack;},};consta=container1.getStack();constcontainer2={stack:"Kubernetes",getStack:()=>this.stack,};constb=container2.getStack();constcontainer3={architect:"microservice",getStack:function(){conststack=["K8s"];returnstack.map(function(element){return`${element} -${this.architect}`;});},};constc=container3.getStack();constcontainer4={architect:"microservice",getStack:function(){conststack=["K8s"];returnstack.map((element)=>`${element} -${this.architect}`);},};constd=container4.getStack();console.log(`${a} ->${b} ->${c} ->${d}`);
- A: "Docker -> Kubernetes -> K8s - undefined -> K8s - microservice"
- B: "Docker -> Kubernetes -> K8s - microservice -> K8s - microservice"
- C: "Docker -> undefined -> K8s - microservice -> K8s - undefined"
- D: "Docker -> undefined -> K8s - undefined -> K8s - microservice"
Answer
The code above might help you revise how the arrow function works in different contexts, especially when dealing with the keyword `this` in JavaScript. There are two crucial takeaway messages you might need to keep in mind when using a function, as follows:
First: The arrow function does not create a new
this
binding when you use them. It inherits from the parent one(environment) when it is defined.Second: The keyword
this
could be problematic when it is called in a callback function. For example when implementingsetTimeout
,setInterval
ormap
,filter
,reduce
orsome
,every
among others, you will need to pass a callback function. Given that the callback function changes the context,this
might therefore change toglobal
object and no longer point to the parent object.
We have 4 objects in the snippet above. Each has a simple property and a trivial method.a
returnsdocker
becausethis.stack
exactly points to the object declaredcontainer1
. However,b
returnsundefined
becausethis
in the arrow function points to the global one rather thancontainer2
. Why? As we mentioned above, the arrow function does not create a context for itself, socontainer2.getStack()
is still bound to the global object.this.stack
becomesundefined
as a result.
Nextc
gives usK8s - undefined
becausethis
is called in the callback function when we usemap
. A new context is now created by the functionmap
, sothis
will not point to the objectcontainer3
. The callback function implemented withmap
orfilter
always creates a new context so thatthis
changes.
We getK8s - microservice"
ind
because the arrow function helps us fix the problem caused by switching context as in the objectcontainer3
. Here are some lessons learned when dealing with context, nested functions (or implementing callback function):
Use normal function rather than arrow function when you write a method inside an object in which the method does not have a nested function(method) or callback one. Arrow function is not recommended when creating object prototypes, classes along with object literals as well.
Use the arrow function when you want to access to
this
, especially in the case of nested method (function) or when using callback function. Otherwise,this
will no longer point to the object in these cases (nested method or using callback function with map, filter). There are two other techniques (old-fashion ones) to fix that.There are 3 ways to fix
this
issue relating to the nested method or callback function: using arrow function as mentioned above, useself = this
technique or explicitly binding withcall
,bind
orapply
method.
classAngular{vendor="Google";lang="TypeScript";overview(){letreport=[];report.push(this.lang);report=report.map(function(e){returne.length+this.vendor.length;});returnreport;}}constme=newAngular();console.log(me.overview());
- A: 16
- B: 106
- C: NaN
- D: TypeError
Answer
The code snippet above might help you revise the concept of context in conjunction with the waythis
is treated in JavaScript. In short, if you implement a callback function for themap
method (or in another case: nested function), then you might need to pay attention tothis
binding.
Whilereport.push(this.lang);
works pretty well asthis
points to the property declared within the classAngular
, the linereturn e.length + this.vendor.length;
does not work asthis
no longer points tovendor
we have already declared as a property in the class. Themap
function creates a new context here. Asvendor
is undefined inside the callback of themap
function, we getTypeError
in the console. So D is the correct answer.
How to fix that? We can quickly fix this one with one of three techniques: (1) use arrow function for the callback passing tomap
, (2) temporarily create an alternativethis
such aslet self = this
before we call map and useself
instead ofthis
. (3) explicitly bind the callback formap
using bind, call or apply. We can also passthis
as the second parameter for the map function. It also works.
classFrameWork{constructor(options){this.options=options??["Angular","React","Vue"];}total(){returnthis.options.length;}filter(){constselected=this.options.filter(function(element){returnelement[0]==="A";});returnselected[0].length+this.total();}}constapp=newFrameWork();console.log(app.filter());
- A: 8
- B: 2
- C: 10
- D: 1
Answer
The code challenge above implements a simple class with two methods. There is only one point in the syntax that you might need to pay a bit more attention to is??
(nullish coalescing operator ) which is quite similar to||
(OR).
??
returns the right-hand side value if the left-hand side is eithernull
orundefined
while||
does the same thing forfalsy
value (false, null, undefined, 0, -0, 0n, NaN, "").length
So as we do not pass anything into the constructor when we initiate the objectapp
,this.options
takes the default value["Angular", "React", "Vue"]
, then the methodtotal()
evaluates the length of the array, which is 3.
filter()
gives us the length of "Angular", which is 8. So the final value is 10. The correct answer is C.
constorigin=[[[123],321],213];constmanipulated=origin.flat(origin.length);console.log(manipulated.length+origin.length);
- A: 2
- B: 3
- C: 4
- D: 5
Answer
The challenge might hopefully help you have a grip on the native array methodflat()
, which is quite handy to flatten a nested array.flat()
accepts a parameter that defines the level of the nested array you are going to manipulate. By default, this parameter is 1.
The method returns a manipulated array. So on the code aboutorigin.length
returns 2 given that the arrayorigin
has two elements. When flattening the original array namedorigin
withflat(2)
, we then have a new array[123, 321, 213]
.
Finally, we have 5 in the console, and D is the correct answer.
constpipe=(...funs)=>(v)=>{funs.reduce((res,func)=>{returnfunc(res);},v);};constplusFour=(v)=>v+4;constmultiplyBySix=(v)=>v*6;constdivideByTwo=(v)=>v/2;pipe(plusFour,multiplyBySix,divideByTwo,multiplyBySix,console.log)(1);
- A: 80
- B: 90
- C: 100
- D: 110
Answer
Thepipe
function can receive an unlimited number of arguments/parameters thanks to rest parameter...funcs
. These arguments/parameters turn out are function as we call the parent functionpipe
. In JavaScript, it is quite common to pass a function as a parameter of another function.
Please call these functions, which are passed topipe
, are child functions. They are then looped and executed one by one withreduce
method, no matter how many functions you attempt to pass topipe
.v
in the code is simply the argument defined in each child function.
So first we have 1, then by executingplusFour
it becomes 5. WhenmultiplyBySix
is called, the output turns to 30. It becomes 15 when we calldivideByTwo
. Finally, it becomes 90 as we multiply 15 * 6 when the functionmultiplyBySix
is called again.
So B is the correct answer.
constquickSortRecursive=function(arrayInput){if(!Array.isArray(arrayInput)){console.log("The input data is not an array");returnarrayInput;}constpivotIndex=arrayInput.length-1;constpivot=arrayInput[pivotIndex];constleft=[];constright=[];letcurrentItem;for(leti=0;i<pivotIndex;i++){currentItem=arrayInput[i];if(currentItem<pivot){left.push(currentItem);}else{right.push(currentItem);}}return[...quickSortRecursive(left),pivot, ...quickSortRecursive(right)];};console.log(quickSortRecursive([1,100,8,19,8,6]));
- A: [1, 100, 8, 19, 8, 6]
- B: [1, 6, 8, 8, 19, 100]
- C: [100, 19, 8, 8, 6, 1]
- D: 6
Answer
You might see a commonly used algorithm here in the code challenge called "quicksort" in which we apply the strategy "divide and conquer". We also use the "recursive" method when we want to recall the function until it meets our expectations. You might also need to know about the "rest parameter" in JavaScript, as shown by the three dots (...) above.
The code above helps us to arrange an array in such a way that the value will increase from left to right. Using the quicksort method, we need to create a pivot (likely the first item from right to left or the first item from left to right). First, we divide the original array into two parts: left and right, depending on the value compared to the pivot.
Next, by calling the function recursively, we keep creating new pivots for the right and left arrays created above for the purpose of sorting value.
Finally, the original array is sorted from left to right depending on the value.
So B is the correct answer.
consthasOwn=(a)=>{returnfunction(o={a:10}){o.property=a[1];return(b)=>{returno.a+o.property+b;};};};console.log(hasOwn([10,20])()(10));
- A: 10
- B: 20
- C: 30
- D: 40
Answer
We have quite trivial nested functions. If you are familiar with the concept ofclosure
in JavaScript, then it is not a big deal to read the code above. The final function, named hasOwn, has three parameters, and when we execute it, we only pass two arguments because we have already defined the default value for the second nested function.
The final result is aso.a + o.property + b
, meaning 10 + 20 + 10. So D is the correct answer.
functioncraft(text){constp=document.createElement("p");p.innerHTML=text;document.body.append(p)}craft("1 - sync A")constfetchItem=newPromise((resolve)=>{craft("2 - eager sync B")setTimeout(function(){craft("3 - eager async C")resolve("4 - async - D");},2000)});craft("5 - sync E")fetchItem.then(data=>craft(data))
- A: 1 - 2 - 3 - 4 - 5
- B: 1 - 2 - 5 - 3 - 4
- C: 1 - 2 - 5 - 4 - 3
- D: 1 - 2 - 3 - 5 - 4
About
Embrace JavaScript naturally and confidently with coding challenges crafted not only for beginners but for JavaScript lovers, regardless of their level of expertise.
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.