preface

The National Day holiday has passed half way, here is a piece of dry goods to calm the panic.

ES6, is not a new thing, ES7, ES8 have caught up. However, the thing is not new, but in the summary. Every preschooler must have Ben Nguyen’s Introduction to ES6 standards or his translation of Deep Understanding of ECMAScript6. This article mainly summarizes some common knowledge points of ES6. If you like my article, welcome to comment, welcome to Star~. Welcome to my Github blog

The body of the

We will take a closer look at the previous list.

New definitions of variables — let and const

Before the adoption of ES6, the variable definition method we would have used was var. In fact, VAR for a new contact with JS people say, perhaps not strange. But, for a developer, it might be tempting to attack it from the inside. Because it’s one of the failures of javascript, a weirdo in other languages. So let’s see where the blame lies.

  1. You can define it repeatedly. I don’t know if there will be code like this in your code, for example:

     var a = 10;
     var a = 11;Copy the code

    Maybe you’ll look at this and think it’s nothing, so you’re wei and xian. In fact, the disadvantages of this are self-evident. In large engineering developments, you define an “A”, I define an “A”, and thousands of you and me, and that’s when the CTO gets worried. So, that’s the first annoying thing about VAR, but if you say there are strict patterns. It is true that the strict pattern makes certain specifications, but we will not discuss them. After all, this is ES6 territory (^-^).

  2. Can be modified at will. What is changeable? I’m not talking about variables, I’m talking about constants. For example:

     var PI = 3.1415926
     PI = 4.1415926Copy the code

    From the example, we can see that PI is a constant that we use all the time, and it is universally acknowledged to be immutable. This is not the case in javascript. On that day, if your PI is changed by a new intern in your company, you may have to look for mistakes for a long time, but this is not the intern’s fault, and he may not know that this is a constant. However, this situation is also a joke (^_^).

  3. There is no block-level scope. If you don’t know anything about block-level scopes, please bookmark them and come back. For example:

     if(true) {var i = 10;
     }
     console.log(i);  / / 10Copy the code

    Trust us, this variable does not have a block-level scope to give us a lot of trouble. At some point, you’ll have to wrap a closure around a loop. Also, to non-JS developers, it may seem like a xiao point.

So let and const come to the rescue of var.

  1. No duplicate definitions are allowed within the same block-level scope. If you use the previous example, you will find that the browser reported an error, as shown in the following figure:

    let

  2. Variables defined by const are not allowed to be modified twice. Let’s go back to the previous example, as shown below:

    const

    You don’t have to worry about your old intern anymore. Yo!

  3. Variables defined by let and const have block-level scope:

    Block-level scope

  4. They define variables that do not have variable promotions and that have temporary dead zones

    I would like to give an example to illustrate this problem more conveniently. First, let’s look at a simple pen test:

    var a = 10;
    function hello(){
        console.log(a);
          var a = 11;
          console.log(a);
    }
    hello();Copy the code

    I think the answer is self-evident, undefined and 11. For the first console, the variable a defined below was promoted, so a became undefined. For the second console, it is easier to understand. This example, I think will bring no small trouble to beginners, and the original I ha.

    Let and const are different. They do not have variable promotion, as shown in the figure below:

    Variable ascension

Function changes – arrow function, remaining arguments, parameter defaults

What is an arrow function? Let’s start with an example:

export const addToCart = productId= > (dispatch, getState) => {
  if (getState().products.byId[productId].inventory > 0) {
    dispatch(addToCartUnsafe(productId))
  }
}Copy the code

This is a snippet I took from the Redux example. At first glance, the “code style is simple”, the overall code specification is good, after all, it is sample code. But it’s hard to understand. So, to avoid future awkwardness, let’s talk about this amazing thing.

In fact, this thing is similar to a Python lambda. However, it does suit the JS language very well, with one word “cool”. A few of its rules:

  • If there is only one variable, omit ()
  • If there is only one return statement, you can omit {return} directly
  • Because it is called arrow, it must be marked with the => symbol each time

If you can’t write at first, then you have to practice more so that you can really use it in your future work.

Sure, it has its benefits, but when you use it, you have to be careful where it’s off limits. Matters needing attention:

  1. Arrow functions cannot be constructors. As shown in figure:

    arrow

  2. The arrow function does not have its own this value; the this value inside the arrow function inherits from the enclosing scope. As shown in figure:

    arrow

  3. Arrow functions have no arguments. We can directly test this, as shown in the figure:

    arrow

What? No arguments, what if I just need to use them? How do you do that? Here’s another interesting change — the remaining parameters.

What do we mean by residual parameters? Don’t worry, just look at an example.

const restParam = function(a, ... args){
    console.log(args);
};
restParam(1.2.3.4);   / / [2, 3, 4]Copy the code

Here you can see that the args variable seems to contain all the parameters entered after that, except a. So, this is what’s called a residual parameter. Among them, a… This notation. In fact, this symbol is so useful that it can be called an extension in ES6. So, let’s look at the use of the arrow function.

rest param

Of course, one thing to be aware of when using the remaining parameters is where the remaining parameters are set. Let’s start with a picture:

Parameters of the position

So, when using the remaining parameters, it is important to place this part at the end of all parameters. In fact, ES6 also introduced another parameter change — the default parameter. Maybe we can start by looking at the problem of default parameters, what we’ve done before. Scenario: There is always a default value of time when setting the delay, to prevent users from using it without setting it, take a look at the following example:

function defaultParam(time){
    let wait = time || 1000;
      setTimeout((a)= > {
        / /...
    }, wait);
}Copy the code

This should be very common and widely used. However, using the ES6 syntax, it looks like this:

function defaultParam(time = 1000){
    setTimeout((a)= > {
        / /...
    }, time);
}Copy the code

It looks like writing it this way, it makes the function a little bit cleaner.

Arrays – Deconstructed assignments, binary arrays

What about deconstructing assignment? Don’t mistake this for a property of arrays. No, objects can be satisfied. I just thought it would be nice to write it over here

Destruct assignment is a new feature that works really well, to be honest. Let’s start with a more complicated example:

let [a, b , {name, age}, ...args ] = [1.2, {name: 'zimo'.age: 24}, 3.4];
console.log(a, b, name, age, args); //1, 2, 'zimo', 24, [3, 4]Copy the code

You’ll notice that in the example, there’s one feature — neat alignment.

This is the condition that you have to satisfy when you deconstruct an assignment — the content of what you want to deconstruct is consistent. That’s how you get the perfect deconstruction. For deconstruction, the length of content on the left and right is not the same, and that’s fine. For example, when you have a bit more content on the right, there’s nothing really wrong, you just need to make sure that part of the structure on your left is what you want, for example:

let [a, b, c] = [1.2.3.4.5];
console.log(a, b, c); / / 1, 2, 3Copy the code

This is called partial deconstruction, and it’s the same thing on the left, for multiple parts, it’s undefined. For example:

let [a,b,c] = [1.2];
console.log(a, b, c);  //1 2 undefinedCopy the code

There are also some important aspects to destruct assignment:

  1. You must ensure that there is an assignment process. Here’s an example:

    Deconstruction assignment

    You can see the example in the figure where a and B are identified separately, but there is no assignment and an error is reported.

  2. The structure of the content section on the left must be the same as that on the right. As shown in figure:

    Deconstruction assignment

    There is no congruent structure between the two sides, and if it were Foo,bar, it would be normal to deconstruct. But the intent of this example might be to deconstruct the value in Foo, but the writing is a bit problematic.

In fact, there are many ways to deconstruct:

  1. Use of default values. Because of the partial deconstruction mentioned earlier, we can use the form of default values when we deconstruct.

     let [a, b = 10] = [1];
     console.log(a, b);  / / 1 and 10Copy the code

    In this case b was originally undefined, but with a default value, the variable of undefined will be assigned the default value

  2. Use destructions in function variables. For a function, its arguments can also be arrays or objects, which is how we can use deconstructed assignment

    function destructuring({name, age}){
        console.log(name, age);
    }
    destructuring({name: 'zimo'.age: 21}); // zimo 21Copy the code

Deconstruction assignment is used so much these days that it is necessary to get a good grasp of it.

Later on, we can talk about the concept of binary arrays.

What is a binary array? In fact, we can look at javascript arrays first. Familiar with JS people know, in fact, js array performance is not high, its essence is an object. The reason why you can see arrays working ok now is because the JS engine has made a different optimization. The V8 engine, for example, uses a C compiler to compile and run arrays of the same internal element type. If the internal element type is different, it separates the array and then compiles it. Check out the deep JavaScript array: Evolution and Performance

So, we can look directly at the use of binary arrays. Binary arrays can be composed of Int8Array, Int16Array, Int32Array, etc. In terms of integers, the availability is strong.

const buffer = new Buffer(100000000);
const arr = new Int8Array(buffer);
console.time('test time');
for(let i = 0; i < arr.length; i++){
    arr[i] = i;
}
console.timeEnd('test time');Copy the code

In fact, binary arrays are not used much at present, ES6 is only proposed, and arrays will be further improved in more detail.

Strings – template strings, startsWith, endsWidth

Strings have also been improved in ES6. Let’s start with our new friend, template strings. In fact, strings can be represented in a variety of ways in a language: single, double, and backquotes. In javascript, double and single quotes are the same, unlike in some static languages. However, sometimes concatenation of strings can be annoying to developers. How to solve it?

ES6 comes with a solution — template strings. What is a template string? Enclose ‘ ‘with back quotes, and then use ${} to wrap the variable. So let’s try it out

const name="zimo";
const str = `My name is ${name}`;
console.log(str);  //My name is zimoCopy the code

This way, we can easily add variables to it. Perhaps, you will feel that such splicing, the use of ordinary way can also be very good to complete. However, during development, we might encounter more complex situations, such as creating a DOM element and its internal elements. In this case, there is usually an expression.

const width = 100;
const height = 200;
const src = "http://www.example.com/example.png";
const html = `<div class="block" width="The ${0.5 * width}px" height="${height}"><img src="${src}" /></div>`;Copy the code

The manual concatenation of elements like this often leads to errors, so using template strings is an “efficient” and “compact” way to do this.

With template strings, you can solve very tricky problems. So what about startsWith and endsWith in the title? If you use regular expressions, chances are you won’t use either API.

As usual, we need to introduce these two apis.

StartsWith: Returns a Boolean and matches the beginning of the string, for example:

const str = "start in the head";
console.log(str.startsWith('start'));  //true
console.log(str.startsWith('head'));  //falseCopy the code

In fact, regular expressions can be used for this purpose. Example of reduction:

const str = "start in the head";
console.log(/^start/.test(str));   //true
console.log(/^head/.test(str));   //falseCopy the code

In fact, there is almost no difference between the two methods, but regular expressions are much better. This API is only convenient in a few scenarios. For example, when we need to match the protocol header of a URL, we often use this method. Example:

const url = "http://www.example.com";
if(url.startsWith('http')) {console.log('this is http');
}else if(url.startsWith('https')) {console.log('this is https');
}else if(url.startsWith('ws')) {console.log('this is websocket');
}    //this is httpCopy the code

Similarly, endWith works the same way.

EndsWith: Returns a Boolean value and matches the end of the string. Here’s an example:

const str = "something in the end";
console.log(str.endsWith('end'));   //true
console.log(str.endsWith('something'));  //falseCopy the code

Again, it can be implemented using regular expressions:

const str = "something in the end";
console.log(/end$/.test(str));   //true
console.log(/something$/.test(str));   //falseCopy the code

In this case, often we need to prepare ICONS for uploaded files, so we can determine the ICONS based on the suffix.

const filename = "upload.jpg";
if(filename.endsWith('.jpg')) {console.log('this is jpg file');
}else if(filename.endsWith('.png')) {console.log('this is png file');
}else if(filename.endsWith('.webp')) {console.log('this is webp file');
}   //this is jpg fileCopy the code

At the same time, strings also added a lot of things, interested, you can go to the book to understand in detail

The Iterator and for… of

Iterator is an Iterator. In ES6, this attribute was finally officially added. Iterators, primarily a traversal mechanism for collection class elements. What is a set-like element? The most common ones are arrays, and objects. Iterators can help developers complete the process of walking through collections. Originally javascript didn’t set up interfaces to customize iterators, but starting with ES6, we can customize iterators. Before we customize iterators, we need to understand what iterators do:

  • Provide a unified and easy access interface for various data structures
  • Allows the members of a data structure to be arranged in some order
  • In ES6, iterators are used primarily for… Of service

An iterator, usually a pointer object, is called over and over and over again, pointing to the next object, until the end. In ES6, we can create a pointer object and then call next’s function to move the pointer object down. At the same time, the next function returns value and done to determine if the end has been reached.

ES6 also provides the Iterator interface — symbol. Iterator. First, let’s look at the collection classes that have native interfaces — arrays, array-like objects, sets, and Maps. So we can call its interface directly to loop:

let arr = ['my'.'name'.'is'.'iterator'];
let iter = arr[Symbol.iterator]();
console.log(iter.next());   //{ value: 'my', done: false}
console.log(iter.next());   //{ value: 'name', done: false}
console.log(iter.next());   //{ value: 'is', done: false}Copy the code

At the same time, the data structures that define the Iterator interface can be easily used for… Of traverses the values

let arr = ['I'.'has'.'iterator'];
for(let item of arr){
    console.log(item);
}   //'I', 'has', 'iterator'Copy the code

However, there is no way to iterate this way without defining the data structure of the Iterator interface, as shown:

iterator

What should we do then? In fact, we can customize iterators for some iterable data structures, for example:

let iteratorObj = {
    0: 'a'.1: 'b'.2: 'c'.length: 3[Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for(let item of iteratorObj){
    console.log(item);
}  // 'a', 'b', 'c'Copy the code

Iterators are a very useful thing to try and improve your code as well.

The Generator and Promise

In fact, these two things are more difficult to understand. There are a lot of new things if you just scratch the surface. In ES6, the concepts of Generator and Promise were introduced. You’ve probably already used it before, through some other class library. Well, the new concepts in ES6 are pretty much the same, just standardized.

A generator is called a generator. It is similar to iterator in that it is executed step by step through the next function. Also, it is defined using the identifier of function*. You also have the yield operator, which allows you to execute step by step down. Let’s look at an example:

function* generator(){
  yield 1;
  yield 2;
  yield 3;
};

let generate = generator();

console.log(generate.next());  //{value: 1, done: false}
console.log(generate.next());  //{value: 2, done: false}
console.log(generate.next());  //{value: 3, done: true}
console.log(generate.next());  //{value: undefined, done: true}Copy the code

This looks like the steps of an iterator. In fact, the interface of iterator can be defined like this. However, the Generator does more than that. It is like a state machine that can switch from one state to the next. Once the yield part is encountered, it can indicate that the current step is paused. You need to wait until the next method is called to proceed to the next step. At the same time, we can also use the result value of the previous step to carry out the next operation. Example:

function* generator(){
  yield 1;
  let value = yield 2;
  yield 3 + value;
};

let generate = generator();

let value1 = generate.next();
let value2 = generate.next();
let value3 = generate.next(value2.value);
console.log(value1);  //{value: 1, done: false}
console.log(value2);  //{value: 2, done: false}
console.log(value3);  //{value: 5, done: true}Copy the code

In this case, you can use value as your parameter value for step 3.

As mentioned earlier, the next of the generator needs to be called itself. But how do we make it call itself automatically? We can use for… Of automatically calls next, just like the iterator. Example:

function* generator(){
  yield 1;
  yield 2;
  yield 3;
};
for(let value of generator()){
  console.log(value);
}   / / 1, 2, 3Copy the code

In fact, this is just the basic use of generator. Generator is mainly used in asynchronous programming. Because the features we talked about earlier are ideal for asynchronous programming. Of course, we also need to mention promise, the asynchronous programming champion.

Promise is translated as a Promise. We can think of it as a convention. We all know that when we’re doing asynchronous programming, we’re going to use callback functions. However, the problems that callback functions can cause are also very obvious. Example:

callback1(function(data){
    / /...
      callback2(function(data1){
        const prevData = data;
          / /...
          callback3(function(){
            / /...
              callback4(function(){
                / /...
            });
        });
    });
});Copy the code

Callbacks, as we write more and more, we’ll see that the inverted pyramid gets deeper and deeper, and it gets harder and harder to manage.

Here, maybe promise will help. Consider why each of these callbacks can be executed outside of another callback. Main reasons:

  1. For each callback, there is no way to determine when the other callback will be called, because the control is not in the current program.
  2. Each callback function depends more or less on the time and data of the last callback function

Based on these two points, we can see that once you write code this way, you have to make sure that your last callback goes before the next callback. We can also see that they lack a convention to notify the corresponding callback function whenever the last one happened, whether it was correct or wrong.

Promise may play one such role. It has three states: Pending, Resolved, and Rejected. They correspond to three results: ongoing, resolved and rejected. A callback will start from the pending state, and it will transition to resolved and Rejected. And this transition is immutable, so once you switch from pending to Resolved, you can’t switch to rejected.

The promise then has a then function that passes down the value returned by the previous callback function. We could write a promise example:

new Promise((resolved, rejected) = > {
  resolved(1);
}).then(data= > {
  console.log(data);
}, err => {
  console.log(err);
}).catch(err= > {
  console.log(err);
});  / / 1Copy the code

In fact, you only need to remember one of these forms to write promises. Promise is an easy thing to write. Because of its relatively simple form, there are now many well-wrapped asynchronous request libraries with Promise attributes, such as Axios.

Promise comes with other apis, one of which we used above.

  • Catch: Used to specify the callback function when an error occurs. The main point is that we mentioned earlier that promises have an immutable feature, so if an error occurs in one process, the state cannot be changed and the error must be caught in the next process. Therefore, to prevent errors in the last process, you need to use a catch at the end to catch errors in the last process.
  • All: Used to wrap multiple Promise instances into a new Promise instance.
    • This function needs all of its Promise instances to become a big pity before the results are wrapped up in an array and passed to the next Promise.
    • If one of the Promise instances becomes Rejected, the result of the first Promise is passed to the next Promise
  • Race: Is also used to wrap multiple Promise instances into a new Promise instance. But this function is different
    • If one Promise in this function becomes a pity, it will pass the result to the next Promise
  • Resolve: This converts a current object into a Promise object
  • Reject: Returns an error Promise object

Promise can be used with the Generator described earlier, so let’s look at a scenario:

The process is managed through Generator functions, and asynchronous operations are handled using Promises.

function usePromise(){
  return new Promise(resolve= > {
    resolve('my name is promise');
  });
}

function* generator(){
  try{
    let item = yield usePromise();
    console.log(item);
  }catch(err){
    console.log(err); }}let generate = generator();
generate.next().value.then(data= > {
  console.log(data);
}, err => {
  console.log(err);
}).catch(err= > {
  console.log(err);
});   //my name is promiseCopy the code

Perhaps you can write more complex programs.

The Class and extends

The last topic to talk about is class. There are plenty of complaints about javascript’s classless features. At the same time, we also need to understand the concept of JS class inheritance. So, ES6 also brings our favorite class Module section. We won’t go over how we built objects (like constructors).

So, let’s take a look at the new changes that ES6 brings to me:

class Animal{
  constructor(name){
      this.name = name;
  }

  sayName(){
      return this.name; }}const animal = new Animal('dog');
console.log(animal.sayName());  // 'dog'Copy the code

It seems that this form is better than the previous constructor. We can understand this structure:

  • Its internal constructor: points to the constructor of the entire class
  • Internal functions: These functions are defined on the prototype of the class

So, the one above can actually be written as the original:

function Animal(name){
    this.name = name;
}
Animal.prototype.sayName = function(){
    return this.name;
}Copy the code

In fact, class has been encapsulated in ES6 to make the current approach more elegant.

After that, let’s look briefly at the concept of inheritance.

Everything is inherited. Because we can’t all write this class from scratch. It is often a refinement of an existing class. Prior to ES6, we might have done combinatorial inheritance on constructors. Example:

function Animal(name){
  this.name = name;
}
Animal.prototype.sayName = function(){
  return this.name;
}
function Dog(name, barking){
  Animal.call(this, name);
  this.barking = barking;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.makeBarking = function(){
  return this.barking;
}
const dog = new Dog('zimo'.Woof woof woof);
console.log(dog.makeBarking());   / / auf
console.log(dog.sayName());  //zimoCopy the code

Such combinatorial inheritance is cumbersome to write, requiring resetting each element and then redefining the prototype of the new class. So, let’s look at the encapsulation of inheritance in ES6:

class Animal{
    constructor(name){
        this.name = name;
    }

      sayName(){
        return this.name; }}class Dog extends Animal{
    constructor(name, barking){
        super(name);
          this.barking = barking;
    }

      makeBarking(){
        return this.barking; }}Copy the code

In this way, you can easily complete the previous composite inheritance step. If you’re interested in encapsulating extends, take a look at this article on Mock Class inheritance in javascript

conclusion

Here, the content of ES6 is only a summary, which can be roughly divided into the following parts:

  • Variable definitions — let and const
  • Function changes – arrow functions, remaining arguments
  • Array changes – deconstruction, expansion
  • Strings — template strings, startsWith, endsWith
  • The Iterator and for… of
  • The Generator and Promise
  • The Class and extends

Hopefully, this will give you a little more insight into ES6, and if you want to dig deeper into ES6, the most direct way is to read a book. I hope your code gets more and more elegant.

If you have any questions about what I wrote, you can comment on it. If I wrote something wrong, you are welcome to correct it. You like my blog, please follow me Star~ yo. We summarize and make progress together. Welcome to my Github blog