JavaScript Fundamentals

Made for the #100Devs Homework on JavaScript.info tasks

Variables

Working with variables

  1. Declare two variables: admin and name.
  2. Assign the value "John" to name.
  3. Copy the value from name to admin.
  4. Show the value of admin using alert (must output “John”).
(or press "Escape" to close)
            
let admin, name;

name = "John";

admin = name;

function showAlert() {
    alert(admin)
}
        

Giving the right name

  1. Create a variable with the name of our planet. How would you name such a variable?
  2. Create a variable to store the name of a current visitor to a website. How would you name that variable?
(or press "Escape" to close)
            
const ourPlanetName = "Earth";
let currentUser;
        

Uppercase const?

Examine the following code:

        
    const birthday = '18.04.1982';
    
    const age = someCode(birthday);
    

Here we have a constant birthday for the date, and also the age constant.

The age is calculated from birthday using someCode(), which means a function call that we didn’t explain yet (we will soon!), but the details don’t matter here, the point is that age is calculated somehow based on the birthday.

Would it be right to use upper case for birthday? For age? Or even for both?

        
    const BIRTHDAY = '18.04.1982'; // make birthday uppercase?

    const AGE = someCode(BIRTHDAY); // make age uppercase?    
    
(or press "Escape" to close)
            
Making the variables upper case does not do anything in Javascript. However, by convention variables in upper case mean that these values should be constant or should not change. If BIRTHDAY and AGE are intended to have values that should not be altered, It is alright for both to use upper case.
        

Functions — Basics

Is "else" required?

The following function returns true if the parameter age is greater than 18.

Otherwise it asks for a confirmation and returns its result:

        
    function checkAge(age) {
        if (age > 18) {
            return true;
        } else {
        // ...
        return confirm('Did parents allow you?');
        }
    }    
    

Will the function work differently if else is removed?

        
    function checkAge(age) {
        if (age > 18) {
            return true;
        }
        // ...
        return confirm('Did parents allow you?');
    }    
    

Is there any difference in the behavior of these two variants?

(or press "Escape" to close)
            
The current function will work the same even with the 'else' removed. The two variants will not have difference in behavior.
        

Rewrite the function using '?' or '||'

The following function returns true if the parameter age is greater than 18.

Otherwise it asks for a confirmation and returns its result

    
    function checkAge(age) {
        if (age > 18) {
            return true;
        } else {
            return confirm('Did parents allow you?');
        }
    }    
    

Rewrite it, to perform the same, but without if, in a single line.

Make two variants of checkAge:

  1. Using a question mark operator ?
  2. Using OR ||
(or press "Escape" to close)
            
// Using a question mark operator ?
const fnRewriteV1 = function(age) {
    return age > 18 ? true : confirm('Did your parents allow you?')
}

// Using OR ||
const fnRewriteV2 = function(age) {
    return age > 18 || confirm('Did your parents allow you?')
}
        

Function min(a, b)

Write a function min(a,b) which returns the least of two numbers a and b.

For instance:

        
    min(2, 5) == 2
    min(3, -1) == -1
    min(1, 1) == 1    
    
(or press "Escape" to close)
            
function min(a, b) {
    return a > b ? b : a
}
        

Function pow(x, n)

Write a function pow(x,n) that returns x in power n. Or, in other words, multiplies x by itself n times and returns the result.

        
    pow(3, 2) = 3 * 3 = 9
    pow(3, 3) = 3 * 3 * 3 = 27
    pow(1, 100) = 1 * 1 * ...* 1 = 1    
    

Create a web-page that prompts for x and n, and then shows the result of pow(x,n).

P.S. In this task the function should support only natural values of n: integers up from 1.

(or press "Escape" to close)
            
function showPowers() {
    const x = prompt('What would be the value of x?')
    const n = prompt('What would be the value of y?')
    if (n < 1) {
        alert(`Power ${n} in not supported, use a positive integer`)
    }
    const resultxN = x**n
    alert(`x=${x}\ny=${n}\n${x}^${n}=${resultxN}`)
}
        

Arrow Functions — Basics

Rewrite with arrow functions

Replace Function Expressions with arrow functions in the code below:

        
    function ask(question, yes, no) {
        if (confirm(question)) yes();
        else no();
    }

    ask(
        "Do you agree?",
        function() { alert("You agreed."); },
        function() { alert("You canceled the execution."); }
    );    
    
(or press "Escape" to close)
            
const ask = (question, yes, no) => {

    question = "Do you agree?"

    yes = () => {
        alert("You agreed.")
    }

    no = () => {
        alert("You canceled the execution.")
    }

    if (confirm(question)) {
        return yes()
    } else {
        return no()
    }
}
        

Array Methods

Translate border-left-width to borderLeftWidth

Write the function camelize(str) that changes dash-separated words like “my-short-string” into camel-cased “myShortString”.

That is: removes all dashes, each word after dash becomes uppercased.

Examples:
        
    camelize("background-color") == 'backgroundColor';
    camelize("list-style-image") == 'listStyleImage';
    camelize("-webkit-transition") == 'WebkitTransition';    
    

P.S. Hint: use split to split the string into an array, transform it and join back.


Filter range

Write a function filterRange(arr, a, b) that gets an array arr, looks for elements with values higher or equal to a and lower or equal to b and return a result as an array.

The function should not modify the array. It should return the new array.

For instance:
        
    let arr = [5, 3, 8, 1];

    let filtered = filterRange(arr, 1, 4);

    alert( filtered ); // 3,1 (matching values)

    alert( arr ); // 5,3,8,1 (not modified)    
    

Filter range "in place"

Write a function filterRangeInPlace(arr, a, b) that gets an array arr and removes from it all values except those that are between a and b. The test is: a ≤ arr[i] ≤ b.

The function should only modify the array. It should not return anything.

For instance:
        
    let arr = [5, 3, 8, 1];

    filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4

    alert( arr ); // [3, 1]    
    

Sort in decreasing order

        
    let arr = [5, 2, 1, -10, 8];

    // ... your code to sort it in decreasing order

    alert( arr ); // 8, 5, 2, 1, -10    
    

Copy and sort array

We have an array of strings arr. We’d like to have a sorted copy of it, but keep arr unmodified.

Create a function copySorted(arr) that returns such a copy.

        
    let arr = ["HTML", "JavaScript", "CSS"];

    let sorted = copySorted(arr);

    alert( sorted ); // CSS, HTML, JavaScript
    alert( arr ); // HTML, JavaScript, CSS (no changes)    
    

Create an extendable calculator

Create a constructor function Calculator that creates “extendable” calculator objects.

The task consists of two parts.

  1. First, implement the method calculate(str) that takes a string like "1 + 2" in the format “NUMBER operator NUMBER” (space-delimited) and returns the result. Should understand plus + and minus -.

    Usage example:
                        
        let calc = new Calculator;
    
        alert( calc.calculate("3 + 7") ); // 10    
                    
  2. Then add the method addMethod(name, func) that teaches the calculator a new operation. It takes the operator name and the two-argument function func(a,b) that implements it.

    For instance, let’s add the multiplication *, division / and power **:

                        
        let powerCalc = new Calculator;
        powerCalc.addMethod("*", (a, b) => a * b);
        powerCalc.addMethod("/", (a, b) => a / b);
        powerCalc.addMethod("**", (a, b) => a ** b);
        
        let result = powerCalc.calculate("2 ** 3");
        alert( result ); // 8    
                    

No parentheses or complex expressions in this task.

The numbers and the operator are delimited with exactly one space.

There may be error handling if you’d like to add it.


Map to names

You have an array of user objects, each one has user.name. Write the code that converts it into an array of names.

For instance:
        
    let john = { name: "John", age: 25 };
    let pete = { name: "Pete", age: 30 };
    let mary = { name: "Mary", age: 28 };

    let users = [ john, pete, mary ];

    let names = /* ... your code */

    alert( names ); // John, Pete, Mary
    

Map to objects

You have an array of user objects, each one has name, surname and id.

Write the code to create another array from it, of objects with id and fullName, where fullName is generated from name and surname.

For instance:
        
    let john = { name: "John", surname: "Smith", id: 1 };
    let pete = { name: "Pete", surname: "Hunt", id: 2 };
    let mary = { name: "Mary", surname: "Key", id: 3 };
    
    let users = [ john, pete, mary ];
    
    let usersMapped = /* ... your code ... */
    
    /*
    usersMapped = [
      { fullName: "John Smith", id: 1 },
      { fullName: "Pete Hunt", id: 2 },
      { fullName: "Mary Key", id: 3 }
    ]
    */
    
    alert( usersMapped[0].id ) // 1
    alert( usersMapped[0].fullName ) // John Smith
    

So, actually you need to map one array of objects to another. Try using => here. There’s a small catch.


Sort users by age

Write the function sortByAge(users) that gets an array of objects with the age property and sorts them by age.

For instance:
        
    let john = { name: "John", age: 25 };
    let pete = { name: "Pete", age: 30 };
    let mary = { name: "Mary", age: 28 };
    
    let arr = [ pete, john, mary ];
    
    sortByAge(arr);
    
    // now: [john, mary, pete]
    alert(arr[0].name); // John
    alert(arr[1].name); // Mary
    alert(arr[2].name); // Pete      
    

Shuffle an array

Write the function shuffle(array) that shuffles (randomly reorders) elements of the array.

Multiple runs of shuffle may lead to different orders of elements. For instance:

        
    let arr = [1, 2, 3];

    shuffle(arr);
    // arr = [3, 2, 1]
    
    shuffle(arr);
    // arr = [2, 1, 3]
    
    shuffle(arr);
    // arr = [3, 1, 2]
    // ... 
    

All element orders should have an equal probability. For instance, [1,2,3] can be reordered as [1,2,3] or [1,3,2] or [3,1,2] etc, with equal probability of each case.


Get average age

Write the function getAverageAge(users) that gets an array of objects with property age and returns the average age.

The formula for the average is (age1 + age2 + ... + ageN) / N.

For instance:
        
    let john = { name: "John", age: 25 };
    let pete = { name: "Pete", age: 30 };
    let mary = { name: "Mary", age: 29 };
    
    let arr = [ john, pete, mary ];
    
    alert( getAverageAge(arr) ); // (25 + 30 + 29) / 3 = 28
    

Filter unique array members

Let arr be an array.

Create a function unique(arr) that should return an array with unique items of arr.

For instance:
        
    function unique(arr) {
        /* your code */
    }
    
    let strings = ["Hare", "Krishna", "Hare", "Krishna",
        "Krishna", "Krishna", "Hare", "Hare", ":-O"
    ];
    
    alert( unique(strings) ); // Hare, Krishna, :-O 
    

Create keyed object from array

Let’s say we received an array of users in the form {id:..., name:..., age:... }.

Create a function groupById(arr) that creates an object from it, with idid as the key, and array items as values.

For example:
        
    let users = [
        {id: 'john', name: "John Smith", age: 20},
        {id: 'ann', name: "Ann Smith", age: 24},
        {id: 'pete', name: "Pete Peterson", age: 31},
    ];

    let usersById = groupById(users);
    
    /*
    // after the call we should have:
    
    usersById = {
        john: {id: 'john', name: "John Smith", age: 20},
        ann: {id: 'ann', name: "Ann Smith", age: 24},
        pete: {id: 'pete', name: "Pete Peterson", age: 31},
    }
    */      
    

Such function is really handy when working with server data

In this task we assume that id is unique. There may be no two array items with the same id.

Please use array .reduce method in the solution.


Objects

Hello, object

Write the code, one line for each action:

  1. Create an empty object user.
  2. Add the property name with the value John.
  3. Add the property surname with the value Smith.
  4. Change the value of the name to Pete.
  5. Remove the property name from the object.

Check for emptiness

Write the function isEmpty(obj) which returns true if the object has no properties, false otherwise.

Should work like that:
        
    let schedule = {};

    alert( isEmpty(schedule) ); // true

    schedule["8:30"] = "get up";

    alert( isEmpty(schedule) ); // false   
    

Sum object properties

We have an object storing salaries of our team:

        
    let salaries = {
        John: 100,
        Ann: 160,
        Pete: 130
    }
    

Write the code to sum all salaries and store in the variable sum. Should be 390 in the example above.

If salaries is empty, then the result must be 0.


Multiply numeric property values by 2

Create a function multiplyNumeric(obj) that multiplies all numeric property values of obj by 2.

For instance:
        
    // before the call
    let menu = {
      width: 200,
      height: 300,
      title: "My menu"
    };
    
    multiplyNumeric(menu);
    
    // after the call
    menu = {
      width: 400,
      height: 600,
      title: "My menu"
    };
    

Please note that multiplyNumeric does not need to return anything. It should modify the object in-place.

P.S. Use typeof to check for a number here.


Using "this" in object literal

Here the function makeUser returns an object.

What is the result of accessing its ref? Why?

        
    function makeUser() {
        return {
            name: "John",
            ref: this
        };
    }

    let user = makeUser();

    alert( user.ref.name ); // What's the result?
    

Create a calculator

Create an object calculator with three methods:

        
    let calculator = {
        // ... your code ...
    };
    
    calculator.read();
    alert( calculator.sum() );
    alert( calculator.mul() );
    

Chaining

There’s a ladder object that allows to go up and down:

        
    let ladder = {
        step: 0,
        up() {
            this.step++;
        },
        down() {
            this.step--;
        },
        showStep: function() { // shows the current step
            alert( this.step );
        }
    };
    

Now, if we need to make several calls in sequence, can do it like this:

        
    ladder.up();
    ladder.up();
    ladder.down();
    ladder.showStep(); // 1
    ladder.down();
    ladder.showStep(); // 0
    

Modify the code of up, down and showStep to make the calls chainable, like this:

        
    ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0
    

Such approach is widely used across JavaScript libraries.


Two functions – one object

Is it possible to create functions A and B so that new A() == new B()?

        
    function A() { ... }
    function B() { ... }
    
    let a = new A();
    let b = new B();
    
    alert( a == b ); // true 
    

If it is, then provide an example of their code.


Create new Calculator

Create a constructor function Calculator that creates objects with 3 methods:

For instance:
        
    let calculator = new Calculator();
    calculator.read();

    alert( "Sum=" + calculator.sum() );
    alert( "Mul=" + calculator.mul() );
    

Create new Accumulator

Create a constructor function Accumulator(startingValue).

Object that it creates should:

In other words, the value property is the sum of all user-entered values with the initial value startingValue.

Here’s the demo of the code:

        
    let accumulator = new Accumulator(1); // initial value 1

    accumulator.read(); // adds the user-entered value
    accumulator.read(); // adds the user-entered value

    alert(accumulator.value); // shows the sum of these values