📕
TIC
  • Tehnologii ale Informaţiei şi Comunicaţiilor (TIC)
  • Basic web principles
    • How web pages work
    • The pillars of a web page
    • Extra: Getting Started with GitHub
  • Basic HTML
    • Description and Basic Syntax
    • Extra resources
  • Basic CSS
    • Description and Basic Syntax
    • Advanced Positioning
    • Extra Resources
  • Basic Javascript
    • Description and basic syntax
    • The Document Object Model
    • Extra Resources
    • Basic assignment
    • The Color Game
  • Advanced Javascript
    • Runtime Engine, Callstack, Scope
    • ES6
  • Advanced Javascript 2
  • Programming paradigms
  • OOP Javascript
  • Functional Programming
  • OOP vs. Functional Programming
  • Asynchronous Javascript
  • Backend Javascript
    • NodeJS
    • ExpressJS
    • REST APIs
    • Authentication and Authorization
  • Firebase
    • NoSQL Databases
    • Database as a Service
    • Google Cloud Firestore
    • CRUD operations
    • Securing your database
  • Basic VueJS
  • Agenda: VueJS and Frontend Frameworks
  • Single Page Applications
  • VueJS basic syntax
  • Vue Components
  • Advanced VueJS
  • Advanced apps with Vue CLI
  • Vue Router
  • SPA State Management - Vuex
  • Composition API
  • Evaluation
    • Final Individual assignment
Powered by GitBook
On this page
  • var vs. let vs. const
  • === vs ==
  • Arrow functions
  • Template literals
  • this keyword
  • .call()
  • .apply()
  • .bind()
  • Spread operator and Rest parameters
  • ES6 Utility functions
  • .forEach()
  • .map()
  • .filter()
  • .reduce()
  • More examples of ES6 utility functions

Was this helpful?

  1. Advanced Javascript

ES6

ES6 refers to version 6, of the ECMAScript which is a JavaScript standard meant to ensure the interoperability of Web pages across different Web browsers. It was published in June 2015, therefore you might find it renamed as ES2015.

It is a major enhancement to the JavaScript language and adds many more features intended to make large-scale software development easier.

Along with these, it brings a so-called syntactical sugar, which is syntax with the same behavior but designed to make things easier to read or to express.

var vs. let vs. const

The main difference between var and let is that instead of being function scoped, let is block scoped. What that means is that a variable created with the let keyword is available inside the “block” that it was created in as well as any nested blocks. “Block”, means anything surrounded by a curly brace {} like in a for loop or an if statement.

{
   var globalVar = "Hello globalVar"
}

{
   let globalLet = "Hello globalLet";
}

console.log(globalVar)
console.log(globalLet)

let declarations are not hoisted.

let me = "go";  // locally scoped
var i = "able"; // globally scoped

console.log(window.me); 
console.log(window.i);
//Function Scope
function loop() {
  for( var i = 0; i < 5; i++) {
    console.log(i);
  }
  console.log(i)
}

//Block Scope
function loop2() {
  for( let i = 0; i < 5; i++) {
    console.log(i);
  }
  console.log(i)
}

loop()
loop2()

const prevents redeclaring the same variable

const x = 5
x = 8 //throws error
const obj = {
	firstName: 'Mihai',
	lastName: 'Gheorghe'
}

obj.firstName = 'Bogdan'
obj //doesn't throw an error due to difference between
//pass by value vs. pass by reference

=== vs ==

the 3 symbol comparison operator === or !== adds a type check between the two operands

let x = 5
x === '5' //evaluates to false
x === 5 // evaluares to true
x == '5' // evaluares to true
x == 5 // evaluares to true

You can find more about how comparison operators evaluate in various scenarios at the following link:

https://dorey.github.io/JavaScript-Equality-Table/

Arrow functions

Arrows functions are both syntactical sugar and have a structural impact on how the code is being executed.

An arrow function expression is a compact alternative to a traditional function expression, but is limited and can't be used in all situations.

The { } and ( ) and return are optional, but may be required.

For example, if you have multiple arguments or no arguments, you'll need to re-introduce parentheses around the arguments.

// Traditional Function
function simpleCalc(a){
  return a + 100;
}

// Arrow function
a => a + 100
const simpleCalc = b => b + 100 //named arrow functions
var sum = (a, b) => {
  let c = 40;
  return a + b + c;
}

An arrow function does not have its own bindings to this or super, and should not be used as methods.

var cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

cat.jumps()
cat.lives //returns 9

var cow = {
  lives: 1,
  jumps: function() {
    this.lives--;
  }
}

cow.jumps()
cow.lives //returns 0

Template literals

Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.

They were called "template strings" in prior editions of the ES2015 specification.

console.log(`string text line 1
string text line 2`);

They allow also simple evaluations using the ${ eval } syntax.

let a = 5;
let b = 10;
console.log(`Fifteen is ${a + b}`)

this keyword

In JavaScript this is a special keyword and it basically refers to the object it belongs to. It was used before ES6 too but the introduction of arrow functions changes its behavior. this is an implicit parameter, that is when every execution context is created, this is automatically added to the local scope as a parameter with the value of what is on the left-hand side of . - calling function. If the "dot" is missing when calling the function, it will default to the global object.

However, it has different values depending on it is used:

  • In a method, this refers to the owner object. If the method's syntax is written with an ES6 arrow function, then it refers to the enclosing scope of the owner object. In other words, in arrow functions, this is lexically scoped, meaning it refers to the object where the function was declared, not the called.

  • In the global scope or in a function, this refers to the global object. However, using strict mode, this is undefined.

  • In an event, such as a DOM onclick, it refers to the element that received the event.

  • Core function methods such as call(), apply() or bind() can refer this to any object passed as an argument.

var person = {
  firstName: "John",
  lastName : "Doe",
  id       : 5566,
  fullName : function() { //fullName is a method of person
    return this.firstName + " " + this.lastName;
  }
};

person.fullName() //returns "John Doe"
// In web browsers, the window object is also the global object:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

.call()

The call() method calls (executes) a function with a given this value and arguments provided. In practice, it is used to write methods that can be reused on different objects. Both this and additional arguments are optional.

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price); //the new Food object is called on
  this.category = 'food'; // a method of Product and args are passed as well
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"
let person = {
    age: 23,
    incrementAge: function() {
        const add1 = () => { this.age++ }
        add1.call(this) //using add1() would have set "this" to "global object"
        // this way "this" available in the incrementAge method is passed to 
        // the arrow function add1
    }
}

.apply()

This methods is similar to call(), the only difference is that the arguments are passed as an array. The method is quite useful even if this is not passed, in scenarios where we need to pass an unknown or large number of arguments.

const array = ['a', 'b'];
const elements = [0, 1, 2];
array.push.apply(array, elements); //push accepts a variable number of arguments
console.info(array); // ["a", "b", 0, 1, 2]

.bind()

This method is also similar, meaning it takes this and additional arguments but returns a new function, which is not executed at that point.

var person = {
    name: 'John'
    }
function sayTo(first, second){
    return first + ' ' + this.name  + second;
    }

var sayToPerson = sayTo.bind(person);

sayToPerson('Hi', '. How are you?') //Hi John. How are you?

Spread operator and Rest parameters

The spread operator ... allows an iterable variable or expression to be expanded for scenarios where more arguments are expected.

function sum(x, y, z) {
  return x + y + z;
}

const numbers = [1, 2, 3];

console.log(sum(...numbers));
// expected output: 6


// it basically replaces the following use of apply
console.log(sum.apply(null, numbers));
// expected output: 6
let arr = [1, 2, 3];
let arr2 = [...arr]; // like arr.slice()

arr2.push(4);
//  arr2 becomes [1, 2, 3, 4]
//  arr remains unaffected

let arr3 = [19, 15, -5];
arr = [...arr, ...arr3] //it can be used multiple times
// arr is now [1, 2, 3, 19, 15, -5]

ES6 Utility functions

ES6 introduced, among many other features, a set of utility functions that we'll find very useful for writing functional programming code. Here are some of them:

.forEach()

This is an array method, explicitly Array.prototype.forEach(), that executes a provided (callback) function once for each array element. The callback takes the following arguments in order: current value, index of the current value, and the whole array. The last two are optional.

forEach() returns undefined

const array1 = ['a', 'b', 'c'];

array1.forEach( (value, index, arr) => {
    console.log(`${value} pe pozitia ${index} din ${arr.length} pozitii`)
});

// expected output: "a pe pozitia 0 din 3 pozitii"
// expected output: "b pe pozitia 1 din 3 pozitii"
// expected output: "c pe pozitia 2 din 3 pozitii"

.map()

This is a method similar to .forEach() but instead, it returns a new array, of the same length as the one called upon, where each element is the result of the callback function.

let numbers = [1, 4, 9]
let roots = numbers.map(function(num) {
    return Math.sqrt(num)
})
// roots is now     [1, 2, 3]
// numbers is still [1, 4, 9]

Another shorthand example to create a new array containing the square of each element of the original array:

const originalArray = [1, 2, 3, 4, 5];

const squaredArray = originalArray.map(x => x * x);

console.log(squaredArray); // [1, 4, 9, 16, 25]

.filter()

Array.prototype.filter() also takes a callback function as an argument but this tests each element of the array. It returns a new array, possibly of smaller length, containing only the elements that passed the test.

function isBigEnough(value) {
  return value >= 10  //although the callback returns boolean,
                      //filter returns an array of elements 
}

let filtered = [12, 5, 8, 130, 44].filter(isBigEnough)
// filtered is [12, 130, 44]

.reduce()

This method is a bit more complex, but also very powerful. It accumulates the result of a callback function over each element of the array. In other words, it reduces that array to a single value.

The callback takes the following arguments: the accumulator, the current value being iterated, and optionally the index of the current value and the array itself.

The method takes, along the callback, an additional argument which will be considered the initial value of the accumulator.

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
//under the hood basic simulation of .reduce()
const reduce = function(collection, callback, initialValue) {
    let accumulator = initialValue
    for (let i = 0; i < collection.length; i++) {
        if (i === 0 && initialValue === undefined) {
            accumulator = collection[0]
        } else {
            accumulator = callback(collection[i], accumulator)
        }
    }
    return accumulator
}

reduce([1,2,4], (v, sum) => v + sum, 0)
//in this case the arrow function is the callback

More examples of ES6 utility functions

  • Array.from() converts an iterable object to an array.

  • Array.find() returns the first element in an array that satisfies a condition.

  • Array.findIndex() returns the index of the first element in an array that satisfies a condition.

  • Array.includes() checks if an array contains a specific element.

  • Array.some() checks if any element in an array satisfies a condition.

  • Object.assign() copies the properties of one object to another object.

  • Object.keys() returns an array containing the names of all of the properties of an object.

  • Object.values() returns an array containing the values of all of the properties of an object.

  • Object.entries() returns an array containing two-element arrays, where each element is a property name and value from the original object.

  • Math.max() returns the largest number of a given set of numbers.

  • Math.min() returns the smallest number of a given set of numbers.

  • Math.floor() rounds a number down to the nearest integer.

  • Math.ceil() rounds a number up to the nearest integer.

  • Math.round() rounds a number to the nearest integer.

PreviousRuntime Engine, Callstack, ScopeNextProgramming paradigms

Last updated 7 months ago

Was this helpful?