Block-level scope
ES5 has no block-level scope, only global scope and function scope. Due to this, the scope of variables is very wide, so you have to create it immediately as soon as you enter the function. This causes the so-called variable increase.
The "variable improvement" feature of ES5 often causes an error if you are not careful:
1. The inner variable covers the outer variable
var tmp = new Date();function f() {console.log(tmp);if (false) { //Execute undefinedvar tmp = "hello world";}}2. Variable leaks into global variables
var s = 'hello';for (var i = 0; i < s.length; i++) {console.log(s[i]);}console.log(i); // 5In the past we often use closures to solve this problem (such as self-executing functions). Now, based on this problem, ES6 has added block-level scope, so there is no need to execute functions by itself.
let and const
ES6 is backward compatible, and maintaining backward compatibility means never changing the behavior of JS code on the web platform, so the scope of variables created by var will still be global scope and function scope. In this way, even if you have a block-level scope, it cannot solve the "variable improvement" problem of ES5. Therefore, here ES6 has added two new keywords: let and const.
1.let
"Let is a more perfect var", it has better scope rules.
2.const
const declares a read-only constant. Once declared, the value of the constant cannot be changed, but the object declared by const can have property changes (object freeze Object.freeze)
const a = [];a.push('Hello'); // Executable a = ['Dave']; // Report an errorYou can also use Object.freeze to freeze the object
const foo = Object.freeze({});// In normal mode, the following line does not work; // In strict mode, the line will report an error foo.prop = 123;//Use let and const:
•Variables are only valid within the block-level scope where the declaration is located
•Variable declaration can only be used (temporary dead zone)
•Variables cannot be defined repeatedly
• The declared global variable, attributes that do not belong to global objects
var a = 1;window.a // 1let b = 1;window.b // undefined
This keyword
We know that this in the ES5 function points to the scope where the runtime is located. for example
function foo() {setTimeout(function(){console.log('id:', this.id);}, 100);}var id = 21;foo.call({id:42});//id: 21Here I declare a function foo, which is internally a delay function setTimeout, printing a this.id every 100ms. We call it through foo.call({id:42}) and set the scope for this function. It takes 100 milliseconds to actually execute. Since this points to the scope where the runtime is located, this here points to the global object window, not the function foo. here:
• Use call to change the execution context of foo so that the execution context of the function is no longer window, so as to distinguish this pointer in setTimeout
•The setTimeout method is hung under the window object, so this points to the scope of the execution - the window object.
The code called timeout is executed in the global scope, so the value of this in the function points to the window object in non-strict mode, and is undefined in strict mode --《javascript Advanced Programming》
To solve this problem, our usual practice is to assign this to other variables:
function foo() {var that = this;setTimeout(function(){console.log('id:', that.id);}, 100);}var id = 21;foo.call({id:42});//id: 42Now ES6 has launched the arrow function to solve this problem.
Arrow function
Identifier => Expression
var sum = (num1, num2) => { return num1 + num2; }// equivalent to var sum = function(num1, num2) {return num1 + num2;};• If the function has only one parameter, parentheses can be omitted
• If the function has only one return statement, braces and return can be omitted
•If the function returns an object directly, parentheses must be added outside the object. (Because an empty object {} and an empty block {} look exactly the same. So you need to wrap the object literals in brackets.)
In response to the problem of this keyword, ES6 specifies the scope where this binding is defined in the arrow function, rather than pointing to the scope where the runtime is located. Since this point, this point has been fixed, which is conducive to encapsulating callback functions.
function foo() {var that = this;setTimeout(()=>{console.log('id:', that.id);}, 100);} var id = 21;foo.call({id:42});//id: 42Note: The fixation pointing to the arrow function this is not because there is a mechanism to bind this inside the arrow function. The actual reason is that the arrow function does not have this of its own at all. The arrow function does not have its own this at all, and the internal this is this in the outer code block. This leads to:
• Cannot be used as a constructor
•You cannot use call(), apply(), bind() and other methods to change the direction of this
Classes and Inheritance
Traditional ECMAScript does not have the concept of classes. It describes the concept of prototype chains and uses prototype chains as the main method to implement inheritance. The basic idea is to use prototypes to allow one reference type to inherit the properties and methods of another reference type. The traditional way to achieve this behavior is through the constructor:
function Point(x, y) {this.x = x;this.y = y;}Point.prototype.toString = function () {return '(' + this.x + ', ' + this.y + ')';};var p = new Point(1, 2);Here, the constructor Point will have a prototype object (prototype), which contains a pointer to Point (constructor), and instance p contains an internal pointer to the prototype object (prop). So the entire inheritance is implemented through the prototype chain. For details, see this article of my: prototype and constructor in javascript
class
ES6 provides a writing style that is closer to traditional languages, introducing the concept of Class as a template for objects. Through the class keyword, you can define a class. But classes are just syntactic sugar for the prototype-based object-oriented pattern. There are mixed reviews about the introduction of class, and many people think it is a major flaw, but for me, it is a good syntax sugar, because the usual way of inheriting prototype chains can often wrap me around for a while.
//Define the class class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return '(' + this.x + ', ' + this.y + ')';}}var p = new Point(1, 2);•There is a constructor method in the class, which is the default method of the class. This method is automatically called when generating an object instance through the new command. A class must have a constructor method. If not explicitly defined, an empty constructor method will be added by default.
•The this keyword in the constructor method represents an instance object.
• When defining the method of "class" (such as toString in the example above), you do not need to add the keyword function before it, just put the function definition in. In addition, there is no comma separation between methods, as an error will be reported if added.
•When using it, you also use the new command directly on the class, which is exactly the same as the usage of the constructor.
•All methods of a class are defined on the prototype property of the class
Inheritance of class - extend
Inheritance between Class can be achieved through extends keyword, which is much clearer and more convenient than ES5's inheritance by modifying the prototype chain.
class ColorPoint extends Point {constructor(x, y, color) {super(x, y); // Call the constructor(x, y) of the parent class (x, y)this.color = color;}toString() {return this.color + ' ' + super.toString(); // Call the toString() of the parent class}}•The super keyword, when called as a function (i.e. super(...args)), represents the constructor of the parent class; when called as an object (i.e. super.prop or super.method()), represents the parent class. Here, it represents the constructor of the parent class and is used to create this object of the parent class.
• The subclass must call the super method in the constructor method, otherwise an error will be reported when creating a new instance. This is because the subclass does not have its own this object, but inherits this object of the parent class and then processes it. If the super method is not called, the subclass will not get this object.
Modular
Historically, JavaScript has never had a module system, and it is impossible to split a large program into small interdependent files and then assemble them in a simple way, which has created a huge obstacle to the development of large and complex projects. In order to adapt to the development of large modules, the community has formulated some module loading solutions, such as CMD and AMD.
Modular writing of ES6:
import { stat, exists, readFile } from 'fs';The essence of the above code is to load 3 methods from the fs module, and the other methods are not loaded. This kind of loading is called "compilation-time loading", that is, ES6 can complete module loading at compile time, which is more efficient than the loading method of CommonJS module. Of course, this also leads to the inability to reference the ES6 module itself, because it is not an object.
The module function is mainly composed of two commands:
•export
The external interface used to specify the module and the external interface must establish a one-to-one correspondence relationship with the variables inside the module.
// Write method one export var m = 1;//Error export 1;// Write method two var m = 1;export {m};//Error export m;// Write method three naming var n = 1;export {n as m};•import
Used to enter the functions provided by other modules. It accepts an object (represented in braces) that specifies the variable name to be imported from other modules (can also be loaded using * in total)
String interpolation
In JavaScript development, we often need to output templates like this:
function saysHello(name){return "hello,my name is "+name+" I am "+getAge(18);}function getAge(age){return age;}sayHello("brand") //"hello,my name is brand I am 18"We need to use + to concatenate strings and variables (or expressions). The examples are relatively simple, so they seem innocuous, but once they are more complicated, they will appear quite cumbersome and inconvenient, and this usage also makes us tiresome. In this regard, ES6 introduces template strings, which can easily and gracefully insert JS values into strings.
Template string
For template strings, it:
•Pack with backticks ``;
•Use ${} to output values;
•The content in ${} can be any JavaScript expression, so function calls and arithmetic operations are legal;
•If a value is not a string, it will be converted to a string;
• Keep all spaces, newlines and indents and output them to the result string (multiple-line strings can be written)
• Use backticks and braces internally to escape, and use backslashes/
For the example above, the template string is written as follows:
function saysHello(name){return `hello,my name is ${name} I am ${getAge(18)}`;}function getAge(age){return age;}sayHello("brand") //"hello,my name is brandI am 18"Strict mode
One of the goals of strict mode is to allow faster debugging of errors. The best way to help developers debug is to throw errors when certain patterns occur instead of failing silently or showing strange behavior (often happening in non-strict mode). Code in strict mode will throw more error messages, which can help developers quickly notice some issues that must be solved immediately. In ES5, strict mode is optional, but in ES6, many features require the use of strict mode, which helps us write better JavaScript.
The above is the "defect" problem of ES6 improved javascript that the editor introduced to you. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!