← Academy Blog

Training marathon 2022

Translated into:

Embarking on our Binary Studio Academy 2022 JS/Mobile entrance test prep marathon! Weekly blog posts featuring test-like questions, explanations.

  • [JS/Mobile] What will be printed on the console?

    a)

    for (var i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 1);
    }

    b)

    for (let i = 0; i < 5; i++) {
      setTimeout(() => console.log(i), 1);
    }

    a) a) 0 1 2 3 4; b) 5 5 5 5 5
    b) a) 5 5 5 5 5; b) 0 1 2 3 4
    c) a) 5 5 5 5 5; b) 5 5 5 5 5

    Expand the correct answer with an explanation

    First we need to understand what is the difference between var and let. The scope of a variable declared with var is its current execution context. Which can be limited to the function or be global to variables declared outside the function. However, var has one weakness. Let's take a look at the example below.

    var greeting = 'say hi';
    var times = 4;
    
    if (times > 3) {
      var greeting = 'say Hello instead';
    }
    
    console.log(greeting); // "say Hello instead"

    As you can see, since the times > 3 condition returns true, the value of the greeter variable is redefined as say Hello instead. If you unconsciously use greeting elsewhere in your code, you will get unpredictable results. This can cause a lot of bugs in your code. This is why there is a need for let and const.

    let has block scope. A block is a piece of code delimited by curly braces {}. Everything inside the curly braces belongs to the block. Thus, a variable declared in a block with let will only be available within that block. Let's now look at another example.

    let times = 4;
    
    if (times > 3) {
      let greeting = 'say Hello';
      console.log(greeting); // "say Hello"
    }
    
    console.log(greeting); // ReferenceError: greeting is not defined

    From this example, we can see that trying to use greeting outside of a block (the curly braces within which the variable was defined) will return an error, since let is block scoped.

    So, back to the task. Since setTimeout is executed asynchronously, and one millisecond is a very long time for a computer, the passed callback will be called after the loop has completed.

    In the case of a, the variable i is declared with the var keyword, so it is global. It will be overwritten every iteration, and when setTimeout is called, it will have its last value of 5, so 5 5 5 5 5 will be sequently printed to the console .

    In the case of b, the variable i is already declared via let and has block scope. It means that it’s only available in the scope of the for loop. During each iteration, the variable will have a new value, and after the code executing, 0 1 2 3 4 will be displayed in the console.

    Therefore, the correct answer is a) 5 5 5 5 5; b) 0 1 2 3 4

  • [JS/Mobile] What will this code display?
    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b());
    console.log(obj.с());

    a) 1 1
    b) undefined undefined
    c) 1 undefined
    d) null null

    Expand the correct answer with an explanation

    Before analyzing this example, we need to understand what is mean a call point, context, and arrow functions.

    Execution point — this is the place in the code where the function was called (not where it was declared). We need to explore the point of call to answer the question: what does this mean?

    In general, finding a call point is like "finding where the function is called from", but this is not always so easy, as certain coding patterns can be misleading about the real call point.

    It's important to think about the call stack (the stack of functions that were called to bring us to the current code execution point). The call point we are interested in is in the call before the currently performed function.

    Execution context — is a concept that describes the environment in which the code runs. The code is always executed within some context

    Стрілочна функція (arrow function) — it is a simple and concise syntax for creating functions, which is often better than the usual Function Expression

    Long story short

    let func = (arg1, arg2, ...argN) => expression;

    Is the same that

    let func = function (arg1, arg2, ...argN) {
      return expression;
    };

    However, in addition to the syntax of writing, there are also important differences that we will talk about later, but all in turn.

    Now let's look at how the call point affects what will be in this when the function is executed.

    There are 4 rules:

    • default binding;
    • implicit binding;
    • explicit binding;
    • tight binding;

    In our example, we consider implicit binding. Let's analyze the following code:

    function foo() {
      console.log(this.a);
    }
    
    var obj = {
      a: 2,
      foo: foo,
    };
    
    obj.foo(); // 2

    First, note the way in which the function foo() was declared, and then later added as a reference in obj. Whether foo() was first declared in obj or added later as a reference (as in the code above), neither function is actually "contained" in the obj object.

    However, the call point uses the obj context to refer to the function, so it can be said that the obj object "owns" or "contains" a function reference at the time the function is called.

    Whatever name you choose for this template, when foo() is called, it is preceded by an object reference to obj. When there is a context object to reference a function, the implicit binding rule states that this is the object that should be used to bind this to the function call.

    Since obj is this for calling foo() ,this.a is the same with obj.a.

    Based on this, we can answer the first part of our task

    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b()); // 1

    Do you think we will get the same result when we write console.log(obj.c());? If your answer is no, then you are absolutely right.

    The case in context. Unlike other functions, arrow functions do not have their own context. In practice, this means that they inherit the essences of this and arguments from parent functions. The anonymous function b () has its own context, which it intercepts in obj. And in c () the arrow function remembers its context at the time of creation and accordingly when calling this function it will refer to it. So we get a window.

    However, you may ask, "But why was there a window at the time the context was created and not the object inside which it was declared as a method?"

    The arrow function at the time of creation looks for the closest context to it and remembers it, and it is the same as in the case of a simple assignment inside obj.

    Summarizing all that is written above, we highlight two main theses.

    Thesis 1

    For functions declared with function f () {}, this is calculated at the time of the call and is equal to the object before the point. If there is no such object - then this will point to the global context (window). However, this does not apply to strict execution.

    Thesis 2

    For arrow functions this is determined at the time of their creation and never changes again

    So, the correct answer is:

    const obj = {
      a: 1,
      b: function () {
        return this.a;
      },
      c: () => this.a,
    };
    console.log(obj.b()); // 1
    console.log(obj.с()); // undefined
  • [JS/Mobile] GalleryWeekly Challenge

    Implement logic that will allow you to make the slide active by clicking on it (add the active class).

    Slider

    Source Code

    Expand the correct answer with an explanation
  • [JS/Mobile] What will someVariable be equal to?
    function func() {
      return this;
    }
    
    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };
    
    const target = outerObj.innerObj;
    const someVariable = target.method();

    a) window
    b) outerObj
    c) innerObj
    d) undefined

    Expand the correct answer with an explanation

    To properly answer this question, we need to know at least a little about how the this keyword in JavaScript works, so we'll take a quick look at that now.

    What is “this”?

    Typically, an object method requires access to the information stored in the object in order to perform some action on it (according to the purpose of the method).

    For example, the code inside user.sayHi() might need the username stored in the user object.

    To access information within an object, a method can use the this keyword.

    For example:

    const user = {
      name: 'Tanya',
      sayHi: function () {
        return this.name;
      },
    };
    
    user.sayHi(); // 'Tanya'

    Here, when the user.sayHi() code is executed, the value of this will be user (a reference to the user object).

    Using this allows you to create generic functions that work correctly as methods on various objects. This is the power of this - the value of this keyword is calculated when the code is executed and depends on the context.

    Understanding what this is equal to in a particular case is quite simple: this is the object before the dot. For example, when obj.f() is called, the value of this inside f is obj.

    function sayHi() {
      console.log(this.name);
    }
    
    const user = {
      name: 'Tanya',
    };
    
    const admin = {
      name: 'Misha',
    };
    
    user.f = sayHi;
    admin.f = sayHi;
    
    // function calls below have different this values
    // "this" inside the function is a reference to the object specified "before the dot"
    user.f(); // Tanya (this == user)
    admin.f(); // Misha (this == admin)
    
    admin['f'](); // Misha (unimportant way to access the method - through a dot or square brackets)

    If we call the function without an object before the dot, we get undefined (if we work in "use strict" mode), or a global object (if "use strict" mode is not activated). In the browser environment, the global object is the window object.

    function sayHi() {
      console.log(this);
    }
    
    sayHi(); // undefined or global object

    There are some other ways to explicitly tell a function which object it should consider this during its execution. The methods call, apply and bind.

    Now let's move on to the task

    Right from the start, we have a func function that simply returns this. We already know that this can be different and its value will depend on how we call this function.

    function func() {
      return this;
    }

    Next, we create an object in which the object inside is nested. And already to this nested object we add our function as a method.

    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };

    An nested object is a full-fledged object like any other, it can also have its own methods and properties. Our code could look like this:

    const innerObj = {
      value: 20,
      method: func,
    };
    
    const outerObj = {
      value: 10,
      innerObj: innerObj,
    };

    Next, we create a new target variable and specify that it is equal to our nested object. Okay, now we have 2 variables that point to the same nested object.

    const target = outerObj.innerObj;

    If you didn't know, JS objects is a complex data type, and unlike primitive types such as number or term, objects are assigned and are copied at the link. In other words, the variable does not store the "value of the object", but the "link" (address in memory) of this value. Therefore, copying such a variable or passing it as an argument to a function copies the reference, not the object itself. All operations using copied links (for example, adding or deleting properties) are performed with the same object.

    That is, in our case, target is the same innerObj, and not a copy of it. It's just that now we have 2 paths to its properties and methods - outerObj.innerObj and target. Take a close look at this code if you don't really understand what I'm talking about:

    const outerObj = {
      value: 10,
      innerObj: {
        value: 20,
        method: func,
      },
    };
    
    const target = outerObj.innerObj;
    
    target.value = 0;
    console.log(outerObj.innerObj.value); // 0
    // because 'target' is just a reference to the same innerObj object, not a copy of it

    Okay, with that figured out, what do we have next?

    const someVariable = target.method();

    And then we just call target.method(), where method is our func function that returns this. this is equal to the object before the dot, in which case the object before the dot is target. But, as we understood above, target and innerObj are not just two identical objects or two copies - they are the same object. Therefore, we have someVariable, target and outerObj.innerObj are all references to a single object in memory.

    The correct answer - innerObj.

  • [JS/Mobile] Create a drop-down block with application icons like Google`s.Weekly Challenge

    Google Bar

    The main stages of the task:

    • create a button that will open / close the block with applications;
    • create the block itself with application icons;
    • implement a custom scrollbar for this block;
    • polish the styles so that everything looks like in the original.

    The less your button and block differ from the original one, the better you managed to complete the task! Ideally, they can be generally identical, with all styles and hover effects. But if you manage to complete only a part of these tasks, it will already be very useful for you!

    What can and should be done to complete the task:

    • check out this menu in Google, see how it works;
    • use dev-tools to look inside - how it's done, how images for menu items are exposed, how images from there or even CSS code can be reused to complete the task;
    • use google - how to make a custom checkbox, how to make a custom scrollbar and everything else you need;
    • use only HTML, CSS and images.

    What NOT to do:

    • do not use JS or any CSS libraries.

    You can try to complete this challenge from scratch, or use this billet where we already have:

    • general markup and styles;
    • the block itself with application icons.

    In this case, you will only need:

    • create a button that will open / close the block with applications;
    • finalize the positioning of the block and make it react to the button;
    • add a custom scrollbar for this block;
    • add hover, focus style for the button.
    Expand the correct answer with an explanation
  • [JS/Mobile] Which line was missed?

    A young programmer was engaged in code refactoring. He decided to wrap the function of a third-party library that accepts a callback in a promise, but he made a mistake. Specify which line was missed:

    // before
    someFunc((err, res) => {
      if (err) {
        console.log(err);
      } else {
        console.log(res);
      }
    });
    
    // after
    1 const someFuncPromise = () =>
    2   new Promise((resolve, reject) => {
    3     //
    4     someFunc((err, res) => {
    5       if (err) {
    6         console.log('Error');
    7         //
    8       }
    9       resolve(res);
    10      console.log('Sucess');
    11      //
    12    });
    13  });

    a) return cb() - 7th line
    b) if - 3rd line
    c) return reject(err) - 7th line
    d) else - 7th line
    e) return - 11th line

    Expand the correct answer with an explanation

    To solve this problem, first of all, we need to understand how the callback that passed to the third-party function library should work. It takes two parameters, err and res , and then an if block checks if the condition is true. In JavaScript, all values are truthy unless they are defined as falsy. It means that all values except false, 0, "", null, undefined, and NaN are truthy. So in our case, if we get an error, it will be logged to the console. If there is no error, then execution will go to the else block and then the console will log the value of res.

    During refactoring the function was wrapped in a "promise", which is supposed to end its lifecycle in one of the following states: fulfilled (via calling resolve()) or rejected (via calling reject()).

    Let’s dive into detailed code flow:

    • If we do not have an error, the first condition if (err) will return false and then execution will go to the next block and resolve and console.log ('Sucess') will be executed.
    • In case of an error the condition if (err) will return true. Because of this, ‘Error’ will be logged to the console, but the function will not be affected in any way - the promise will be successfully resolved and the "successful" console.log will work.

    So, firstly, we should follow the logic of working with promises and call reject(err) in case of error.

    And secondly, we should not forget that functions resolve and reject change the state of the promise, but do not stop it, because of this the console will still log the message "Success".

    So the full correct answer should be: return reject(err) 7th line.

  • [JS/Mobile] Searching characters from The Game of Thrones v2Weekly Challenge

    Today we’re gonna improve our last week challenge and add some new features.

    • Let’s add an ability to select favourite characters.
    • Also let’s improve our UI a bit and add loader indicator during data fetching.

    Here is a repo to start with.

    Expand the correct answer with an explanation
  • [JS/Mobile] How much 1 is displayed in the console?
    const func = (x) => {
      switch (isNaN(x) || x) {
        case null: {
          console.log(1);
          break;
        }
        case undefined: {
          console.log(1);
        }
        case NaN: {
          console.log(1);
          return;
        }
        case false: {
          console.log(1);
        }
        case true: {
          console.log(1);
        }
        default:
          break;
      }
    };
    
    func();

    a) 1
    b) 2
    c) 3
    d) 4

    Expand the correct answer with an explanation

    In order to answer this question correctly, we need to understand how to work with the switch operator, how function parameters are passed as well as how the isNaN function and the OR operator (||) work.

    Firstly, it is necessary to understand what value will be in the parameter x. Since no parameters were passed to the function when it was called, the default value - undefined will be used. This can be easily checked by following piece of code.

    const f = (arg) => console.log(arg === undefined);
    
    f();

    Next, we should understand how the switch operator works. This operator evaluates the value given to it and executes the code associated with the corresponding case clause and, what is important to remember, all the following statements will be executed as well. This can be easily checked by executing the following code:

    switch (2) {
      case 1:
        console.log('1');
      case 2:
        console.log('2');
      case 3:
        console.log('3');
      default:
        console.log('default');
    }

    The result in console will be:

    2
    3
    default

    There are 3 ways to stop the execution of all case clauses - break, return, throw.

    • break - stop execution of all subsequent case clauses, and continue execution of function.
    • return - stop execution of all following case clauses, and return value from function.
    • throw - stop execution of all case clauses and throw an error.

    So, if we rewrite the code above using break we will get a completely different result:

    switch (2) {
      case 1:
        console.log('1');
        break;
      case 2:
        console.log('2');
        break;
      case 3:
        console.log('3');
        break;
      default:
        console.log('default');
    }

    Result in console:

    2

    On the next step we should determine the value that the isNaN function will return. To understand this, we must first understand what NaN is. NaN - represents a value that could not be converted into a number (Not-a-Number), such cases may occur when:

    • Number cannot be parsed (Number('foo'))
    • A mathematical operation is performed that does not result in a real number (Math.sqrt (-1))
    • The operator of the mathematical operation is NaN (7 * NaN)
    • The result of the expression is indefinite (0 * Infinity)
    • Any operation that includes a string and is not an add operation ('foo'/ 5)

    The isNaN function converts the value passed to it into a number and checks if this value is NaN.

    console.log(isNaN('55')); // false
    console.log(isNaN(undefined)); // true

    The last thing we need to know to solve this problem is the behavior of the operator OR (||). This statement returns the second value only when the first is falsy.

    console.log(false || 'shown'); // 'shown'
    console.log(true || 'not shown'); // true

    Now, we can say that in the function the parameter x has the value undefined. The isNaN function will return true, because this value cannot be converted to a number. So, the || operator will also return true because this value is truly. This means that the following clause is executed

    case true: {
      console.log (1);
    }

    and since there is no operator that would stop the execution of case clause, the default is also executed (although it does not output anything in this task). So the console will display:

    1

    The correct answer is - 1.

  • [JS/Mobile] The challenge for this week will be to implement the app for searching characters from The Game of Thrones.Weekly Challenge

    The data about the characters we will get from this API.

    View Example Example

    To simplify the task, we have prepared a boilerplate for you where you will have to add only getting the data about the characters from the API. So, clone the boilerplate repository and read the description.

    Expand the correct answer with an explanation