Hooks by Example: Convert a Tesla Battery Range Calculator to Functional Components

In this tutorial, we started with an existing React-app with which we can calculate how much range the Tesla has under different circumstances. The range of a battery depends on the speed, the outside temperature, the climate and the wheel size.

In order to learn React hooks more thoroughly I converted this existing React-app from React Class Components to one with just React Functional Components. That is the goal of this tutorial!

Immutability in JavaScript — When and Why Should You Use It

The concept of immutability is nothing new because it’s been around for a long time in functional and object-oriented programming languages. The idea wasn’t much prevalent in JavaScript, but it has slowly grown into the programming community recently. React is a strong proponent of keeping the state immutable and Facebook has contributed a library called Immutable.js to help this cause.

In this tutorial, we’ll answer the following questions:

Latest Features of Angular.js

The latest version of Angular was slated to release in March-April 2019. But, it eventually happened in 2019. Yes, we are talking about Angular 8 — the latest version of Angular.js. 

However, Angular 7.0 is supported until April 2022. So, it becomes imperative for organizations to explore the new features incorporated in Angular 8 and decide on embracing Angular 8 whether or not they should upgrade from Angular 7.0. 

Builder Pattern in Javascript

For those who don't care about code readability: step on a lego

Suppose we go to a store and want to buy a product. Let’s say a PC. We have two options; either buy a ready-made PC of any particular brand, or we customize and assemble it.

In this scenario, we go for the second option — we will collect different parts and construct a new PC.

JavaScript Generators and How They Work

What Are Generators?

  • Generators in ES6 are a new way of working with functions and iterators.
  • They appear to be a function but behaves like an iterator which simplifies the task of writing iterators.
  • They are different from a normal function, as they can stop mid-execution and then continue from where they stopped.
  • In layman’s terms, they are similar to the way we put a marker/bookmark in a page of the book we are reading. Then later we resume reading the book from that particular page instead of starting all over again. Here we acted as a generator function.
  • They can generate a series of results instead of a single value.

Generator Syntax

  • Creating a generator is similar to a normal function, with the difference that it requires a * between the function keyword and function name.
  • It allows any number of spaces or no spaces in between.
  • It uses the yield keyword to pause and resume execution.
  • Since it is just a function, we can use it anywhere just like we would with normal function, i.e. inside objects and class methods.
  • Basic syntax:
// All below formats are valid with spaces/no spaces in between function keyword, * and function name.
function * functionName() {
    // Your generator related codes here.
}

// OR below format.
function *functionName() {
    // Your generator related codes here.
}

// OR below format.
function* functionName() {
    // Your generator related codes here.
}

// OR below format.
function  *  functionName() {
    // Your generator related codes here.
}

// OR below format.

function*functionName() {
    // Your generator related codes here.
}

// Inside Class method.
class testClass {
    *functionName() {}
}

// Inside object
var testObject = {
    *functionName() {}
}

Yield Keyword

  • The yield keyword is used to return data and pause the execution of the generator.
  • Every time the generator encounters yield, it halts the execution at that point and returns the specified value. It then resumes the execution upon calling the next() method on the Generator object until it finds the next yield.
  • In the context of generators, we do not say that it returned a value. We say that it has yielded the value.
  • Using return inside a generator will set the done property to true, after which it cannot generate any more values. All the code after the return statement will not execute.
  • Syntax:
// Generator with yield. 
function * generator() {
    console.log('First execution.');
    yield 'Yield First execution, saved the state and exit';
    console.log('Second execution will be on next() call.');  
    yield 'Yield second execution, saved the state and exit';
}

const generatorObj = generator();

next() in Generators

  • The generator returns an object on which we can call next().
  • Every invocation of next() will return an object containing the returned value and the status of the generator's execution.
  • The value property will contain the value and the done property will return true or false for the generator’s execution status.
  • When done becomes true, the generator stops and won’t generate any more values.
{
    value: Any,
    done: true|false
}
function * generator() {
    console.log('First execution.');
    yield 'Yield First execution, saved the state and exit';
    console.log('Second execution will be on next() call.');  
    yield 'Yield second execution, saved the state and exit';
}

const generatorObj = generator();

// After below execution, generator will yield value, return below object and pause execution.
// {value: 'Yield First execution, saved the state and exit', done: false}
setTimeout(() => console.log(generatorObj.next()), 1000);

// After below execution, generator will yield value, return below object and pause execution.
// {value: 'Yield First execution, saved the state and exit', done: false} 
setTimeout(() => console.log(generatorObj.next()), 3000);

// After below execution, generator will yield value, return below object and close execution.
// {value: undefined, done: true}
setTimeout(() => console.log(generatorObj.next()), 5000);
  • The below screenshot shows the different states of a generator during its execution of how it gets "suspended" when it encounters the yield keyword, resumes when next() is called, and then gets closed after the execution is complete:JavaScript generators
  • If we use return then it will not execute any code present after the return statement. Sample code (JSFiddle link: generator with return statement):
  • function * generator() {
        console.log('First execution.');
        yield 'Yield First execution, saved the state and exit';
        return 'Execution ends here due to return and will not execute rest of the codes.';  
        // All below codes will not get executed.
        yield 'Yield second execution, saved the state and exit';
    }
    
    const generatorObj = generator();
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false}
    setTimeout(() => console.log(generatorObj.next()), 1000);
    
    // After below execution, generator will yield value, return below object and completes the execution.
    // {value: 'Execution ends here due to return and will not execute rest of the codes.', done: true}
    setTimeout(() => console.log(generatorObj.next()), 3000);
    
    // generator execution is already completed so it will just return value as undefined and done as true.
    // {value: undefined, done: true}
    setTimeout(() => console.log(generatorObj.next()), 5000);
  • We can also pass values to next().
    Sample code (JSFiddle link: next() with value passed):
  • function * generator() {
        console.log('First execution.');
        yield 'Yield First execution, saved the state and exit';
        console.log('Second execution will be on next() call.');  
        let passedArgument = yield 'Yield second execution, saved the state and exit';
        yield passedArgument;
    }
    
    const generatorObj = generator();
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false}
    setTimeout(() => console.log(generatorObj.next()), 1000);
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: 'Yield First execution, saved the state and exit', done: false} 
    setTimeout(() => console.log(generatorObj.next()), 3000);
    
    // After below execution, generator will yield value, return below object and pause execution.
    // {value: "This is the passed value", done: false}
    setTimeout(() => console.log(generatorObj.next('This is the passed value')), 5000);
    
    // After below execution, generator will yield value, return below object and close execution.
    // {value: undefined, done: true}
    setTimeout(() => console.log(generatorObj.next()), 7000);

    Why Use Generators

    • Implementing Iterables:
      • Implementation of an iterator in JavaScript requires things to be done manually, like:
        • Creating an iterator object.
        • Implemeting the next() method.
        • Making a return object for next() in the proper format: { value: Any, done: true | false }
        • Saving the state.
      • The below sample code shows how hard it is to manually implement everything in an iterator.
      const iterableObj = {
          [Symbol.iterator]() {
              var counter = 0;
              return {
                  next() {
                      counter++;
                          if (counter === 1) {
                              return { value: 'step one', done: false};
                          } else if (counter === 2) {
                              return { value: 'step two', done: false};
                          } else if (counter === 3) {
                              return { value: 'step three', done: false};
                          }
                      return { value: '', done: true };
                  }
              }
          },
      }
      
      for (const val of iterableObj) {
          console.log(val);
      }
      • The below sample code shows how easy it is with a generator which handles most of the things on its own.
      function * iterableObj() {
          yield 'step one';
          yield 'step two';
          yield 'step three';
      }
      
      for (const val of iterableObj()) {
        console.log(val);
      }
    • Lazy execution: Generator helps to delay the evaluation of an expression until its value is required. So, if we don’t need a value, it won’t exist and is calculated only when we need it.
    • Memory efficient: It is memory efficient because we generate only the values that are required. We need to pre-generate all the values in case of normal functions and keep them in case we can use them later. But generators can defer the computation of any expressions/code until we need it.

    Limitations

    • Generators are one-time access only. Once you’ve exhausted all the values, you can’t iterate over it again. To generate the values again, you need to make a new generator object.
    • Generators do not allow random access with arrays. 

    I hope this post has helped you get a better grasp on  JavaScript generators and their basic functionalities.

    Happy coding!

    Differential Serving

    There is "futuristic" JavaScript that we can write. "Stage 0" refers to ideas for the JavaScript language that are still proposals. Still, someone might turn that idea into a Babel plugin and it could compile into code that can ship to any browser. For some of these lucky proposals, Stage 0 becomes 1, 2, 3, and, eventually, an official part of the language.

    There used to be a point where even the basic features of ES6 were rather experimental. You'd never ship an arrow function to production ‐ you'd compile it to ES5 and ship that instead. But ES6 (aka ES2015, four years ago!) isn't experimental anymore. Its features aren't proposals, drafts, or candidates. They are finished parts of the language, with widespread support.

    The main sticking points with browser support are IE <= 11 and Safari <= 9. It's entirely possible you don't support those browsers. In that case, you're free to ship ES6 features to production, and you probably should, as your code will be smaller and more efficient than if you compiled it to ES5. Philip ran some tests and his results suggest both file sizes and parse/eval times can cut in half or better by adopting the new features. However, if you do need to support browsers that lack support, you'll need to compile to ES5, but it doesn't mean you need to ship ES5 to all browsers. That's what "differential serving" is all about.

    How do you pull it off? One way, which is enticingly clever, is this pattern I first saw Philip Walton write about:

    <!-- Browsers with ES module support load this file. -->
    <script type="module" src="main.mjs"></script>
    
    <!-- Older browsers load this file (and module-supporting -->
    <!-- browsers know *not* to load this file). -->
    <script nomodule src="main.es5.js"></script>

    Don't let that .mjs stuff confuse you; it's just a made-up file extension that means, "This is a JavaScript file that supports importing ES6 modules" and it is entirely optional. I probably wouldn't even use it.

    The concept is great though. We don't have to write fancy JavaScript feature tests and then kick off a network request for the proper bundle ourselves. We can have that split right at the HTML level. I've even seen little libraries use this to scope themselves specifically to modern browsers.

    John Stewart recently did some testing on this to see if it did the job we think it's doing and, if so, whether it's doing it well. First, he covers how you can actually make the two bundles, which takes some webpack configuration. Then he tested to see if it actually worked.

    The good news is that most browsers — particularly newer ones — behave perfectly well with differential serving. But there are some that don't. Safari 10 (2016) is a particularly bad offender in that it downloads and executes both versions. Firefox 59 (2018) and IE 11 download both (but execute the correct one) and Edge 18 somehow downloads both versions, then downloads the modules version again. All browsers that are going away rather quickly, but not to be ignored. Still worth doing? Probably. I'd be interested in looking at alternate techniques that fight against these pitfalls.

    The post Differential Serving appeared first on CSS-Tricks.

    ES6 const Is Neither Constant Nor Immutable

    I gave a quick talk on JS a while ago on hoisting in JS and while discussing how hoisting applies to variable declarations, we imminently reached ES6’s let and const. We thus began talking about the difference between var, let and const, and how const is not really a constant or immutable.

    What Is const?

    Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through reassignment, and it can’t be redeclared. - MDN