Use setTimeout instead of setInterval for intermittent calls

var executeTimes = 0;
var intervalTime = 500;
var intervalId = null;

// Release the following comments and run setInterval Demo
intervalId = setInterval(intervalFun,intervalTime);
// Release the comments below to run setTimeout Demo
// setTimeout(timeOutFun,intervalTime);

function intervalFun(){
    executeTimes++;
    console.log("doIntervalFun——"+executeTimes);
    if(executeTimes==5){ clearInterval(intervalId); }}function timeOutFun(){
    executeTimes++;
    console.log("doTimeOutFun——"+executeTimes);
    if(executeTimes<5){
        setTimeout(arguments.callee,intervalTime); }}Copy the code

The code is relatively simple, we just call setTimeout again in the setTimeout method, can achieve the purpose of intermittent call.

Why does the author suggest using setTimeout instead of setInterval? What is the difference between a setTimeout type intermittent call and a traditional setInterval intermittent call?

The difference is that setInterval interval calls are timed before the execution of the previous method. For example, if the interval is 500ms, the later method will be added to the execution sequence regardless of whether the previous method has completed execution at that time. The problem is that if the former method takes more than 500ms to execute and the addition is 1000ms, it means that the latter method will execute as soon as the former method completes because the interval is already more than 500ms.

var executeTimes = 0;
var intervalTime = 500;
var intervalId = null;
var oriTime = new Date().getTime();

// Release the following comments and run setInterval Demo
// intervalId = setInterval(intervalFun,intervalTime);
// Release the comments below to run setTimeout Demo
setTimeout(timeOutFun,intervalTime);

function intervalFun(){
    executeTimes++;
    var nowExecuteTimes = executeTimes;
    var timeDiff = new Date().getTime() - oriTime;
    console.log("doIntervalFun——"+nowExecuteTimes+", after " + timeDiff + "ms");
    var delayParam = 0;
    sleep(1000);
    console.log("doIntervalFun——"+nowExecuteTimes+" finish !");
    if(executeTimes==5){ clearInterval(intervalId); }}function timeOutFun(){
    executeTimes++;
    var nowExecuteTimes = executeTimes;
    var timeDiff = new Date().getTime() - oriTime;
    console.log("doTimeOutFun——"+nowExecuteTimes+", after " + timeDiff + "ms");
    var delayParam = 0;
    sleep(1000);
    console.log("doTimeOutFun——"+nowExecuteTimes+" finish !");
    if(executeTimes<5){
        setTimeout(arguments.callee,intervalTime); }}function sleep(sleepTime){
    var start=new Date().getTime();
    while(true) {if(new Date().getTime()-start>sleepTime){
            break; }}}Copy the code

To execute the setInterval Demo method, see the console

DoIntervalFun -1, after 500ms
VM2854:19DoIntervalFun -1 finish !
VM2854:16DoIntervalFun -2, after 1503ms
VM2854:19DoIntervalFun -2 finish !
VM2854:16DoIntervalFun -3, after 2507ms
VM2854:19DoIntervalFun -3 finish !
VM2854:16DoIntervalFun -4, after 3510ms
VM2854:19DoIntervalFun -4 finish !
VM2854:16DoIntervalFun -5, after 4512ms
VM2854:19DoIntervalFun -5 finish !
Copy the code

It can be found that the interval between fun2 and fun1 is close to 1000ms, which is exactly the execution time of fun1, which means that fun2 will be executed immediately after fun1 is executed, contrary to the original intention of intermittent call.

So let’s comment out setInterval’s Demo method, let go of setTimeout’s Demo method, run it, look at the console

DoTimeOutFun -1, after 500ms
VM2621:32DoTimeOutFun -1 finish !
VM2621:29DoTimeOutFun -2, after 2001ms
VM2621:32DoTimeOutFun -2 finish !
VM2621:29DoTimeOutFun -3, after 3503ms
VM2621:32DoTimeOutFun -3 finish !
VM2621:29DoTimeOutFun -4, after 5004ms
VM2621:32DoTimeOutFun -4 finish !
VM2621:29DoTimeOutFun -5, after 6505ms
VM2621:32DoTimeOutFun -5 finish !
Copy the code

The difference between fun1 and fun2 is 1500ms = 1000 + 500. Fun2 is executed 500ms after fun1.

closure

  1. So if we write a function that has a name value in it, and we can allow anyone to access the name property, but only a few people can modify the name property, then we can use closures, and we can write in the setName value who has the permission to modify it.
var person = function(){   
    // The scope of a variable is inside the function, so it cannot be accessed externally
    var name = "FE";      
    return {
      // Manage private variables
       getName : function(){   
           return name;   
       },   
       setName : function(newName){ name = newName; }}};Copy the code
  1. Data cache If we perform a large amount of calculation function and return a value, and the value in the other functions, and application of this kind of circumstance using closures, the data can be stored in the memory, for the use of the other functions (this is seen in other blog, concrete is not very clear, if you are interested, can consult relevant literature).

Disadvantages: Excessive memory consumption, if not handled properly, may cause memory leakage

The difference between forEach and map in an array

Most of the time, we’re going to iterate through an array, and the two methods that we use most often are the forEach and map methods. Let’s start with what they have in common

  • ForEach and Map support three parameters each time the anonymous function is executed: item (current item), index (index), The arR anonymous function this refers to the window and can only iterate through the array without changing the array
  • Differentiating map methods

1. The map method returns a new array whose elements are the values of the original array. 2. The map method does not detect empty arrays. The map method does not change the original array. 3. Browser support: chrome, Safari1.5+, opera support, IE9+,

array.map(function(item,index,arr){},thisValue)

var arr = [0.2.4.6.8];
var str = arr.map(function(item,index,arr){
    console.log(this); //window
    console.log(Original array arr:,arr); // Note that this is executed 5 times
    return item/2;
},this);
console.log(str);/ /,1,2,3,4 [0]
Copy the code

If arR is an empty array, the map method returns an empty array.

The forEach method

  1. The forEach method is used to call each element of the array, passing the element to the callback function. 2. ForEach does not call the callback function for an empty array.
Array.forEach(function(item,index,arr){},this)
var arr = [0.2.4.6.8];
var sum = 0;
var str = arr.forEach(function(item,index,arr){
    sum += item;
    console.log("The value of sum is:",sum); //0 2 6 12 20
    console.log(this); //window
},this)
console.log(sum);/ / 20
console.log(str); //undefined
Copy the code

ForEach returns undefined whether arR is an empty array or not. This method simply executes each item in the array as an argument to the callback once.

The difference between for in and for of

ForEach can also be used in ES5. ES5 has the function of traversing number groups, such as Map, filter, some, every, reduce, reduceRight, etc., but their return results are different. With foreach, however, you can’t break the loop using break, and you can’t return to the outer function using return.

Array.prototype.method=function(){ &emsp; &emsp;console.log(this.length);
}
var myArray=[1.2.4.5.6.7]
myArray.name="Array"
for (var index in myArray) {
  console.log(myArray[index]);
}
Copy the code

It is also possible to iterate over groups of numbers using for in, but there are the following problems:

  1. Index The index is a string number and cannot be directly used for geometric operations

  2. The traversal order may not be in the internal order of the actual array

  3. Using for in iterates through all the enumerable properties of the array, including stereotypes. For example, chestnut’s prototype method and name attributes

So for in is better for traversing objects, not for in groups.

So instead of using the for loop, how do we make it easier to correctly iterate over a set of numbers to the desired value (i.e., without iterating through method and name)? For of in ES6 does a better job.

Array.prototype.method=function(){ &emsp; &emsp;console.log(this.length);
}
var myArray=[1.2.4.5.6.7]
myArray.name="Array";
for (var value of myArray) {
  console.log(value);
}
Copy the code

Remember, for in iterates over the array index (that is, the key name), while for of iterates over the array element value.

For of traverses only the elements of the array, excluding the array’s prototype property Method and index name

Iterating over an object is usually done by iterating over the object’s key name with for in

Object.prototype.method=function(){ &emsp; &emsp;console.log(this);
}
varmyObject={ &emsp; &emsp; a:1, &emsp; &emsp; b:2, &emsp; &emsp; c:3
}
for (var key in myObject) {
  console.log(key);
}
Copy the code

The hasOwnPropery method can determine if a property is an instance property of the object if you don’t want to iterate through the prototype methods and properties of myObject

for (var key inmyObject) { &emsp; &emsp;if(myObject. HasOwnProperty (key)) {& emsp; &emsp; &emsp; &emsp;console.log(key); &emsp; &emsp; }}Copy the code

Keys (myObject) can also be used in ES5 to obtain an array of instance properties of an Object, excluding prototype methods and properties.

Object.prototype.method=function(){ &emsp; &emsp;console.log(this);
}
varmyObject={ &emsp; &emsp; a:1, &emsp; &emsp; b:2, &emsp; &emsp; c:3
}
Object.keys(myObject).forEach(function(key,index){&emsp; &emsp;console.log(key,myObject[key])
})
Copy the code

Implement an EventEmitter method

The core of EventEmitter is the encapsulation of event triggering and event listener functions. Be careful when replying to vue using EMIT to communicate. EventEmitter methods mainly include on,emit,once, and off methods.

class Event {
    constructor() {
          this.events = Object.create(null);
      }
      on(name, fn) {
        if (!this.events[name]) {
            this.events[name] = []
          }
          this.events[name].push(fn);
          return this; } emit(name, ... args) {if (!this.events[name]) {
            return this;
        }
        const fns = this.events[name]
        fns.forEach(fn= > fn.call(this. args))return this;
      }
      off(name,fn) {
        if (!this.events[name]) {
            return this;
        }
          if(! fn) {this.events[name] = null
            return this
          }
          const index = this.events[name].indexOf(fn);
          this.events[name].splice(index, 1);
        return this;
      }
      once(name,fn) {
        const only = (a)= > {
          fn.apply(this.arguments);
          this.off(name, only);
        };
        this.on(name, only);
        return this; }}Copy the code

Let, var, const

Var is not a block-level scope, but a function scope. Here’s an example:

function runTowerExperiment(tower, startTime) {
  var t = startTime;

  tower.on("tick".function () {... code that uses t ... }); . more code ... }Copy the code

This is fine, because the callback has access to the variable T, but what if we rename the variable t in the callback?

function runTowerExperiment(tower, startTime) {
  var t = startTime;

  tower.on("tick".function () {... code that uses t ... if (bowlingBall.altitude() <=0) {
      vart = readTachymeter(); . }}); . more code ... }Copy the code

The latter will cover the former.

The second is the problem of circulation. Look at the following example:

var messages = ["Meow!"."I'm a talking cat!"."Callbacks are fun!"];

for (var i = 0; i < messages.length; i++) {
    setTimeout(function () {
        document.write(messages[i]);
    },i*1500);
}
Copy the code

Undefined because after the for loop, I is set to 3, so I cannot access its value.

Let To address these issues, ES6 introduced the LET syntax. Let can be declared in {},if, or for. It is used in the same way as var, but only at the block level. But isn’t there no block-level scope in javascript? We’ll talk about that in a second. It is also important to note that variables defined by let do not have variable promotion.

Variable promotion just a little bit about what variable promotion is.

var v='Hello World'; 
(function(){ 
    alert(v); 
    var v='I love you'; }) ()Copy the code

The output of the code above is undefined.

Why is that? This is because of variable promotion, which is to raise the declaration of a variable to the top of a function, for example:

(function(){ 
    var a='One'; 
    var b='Two'; 
    var c='Three'; }) ()Copy the code

In effect:

(function(){ 
    var a,b,c; 
    a='One'; 
    b='Two'; 
    c='Three'; }) ()Copy the code

So our example is actually:

var v='Hello World'; 
(function(){ 
    var v;
    alert(v); 
    v='I love you'; }) ()Copy the code

So it’s going to return undefined.

This is also a problem with VAR that we don’t have with let. Because it will report syntax errors:

{     
    console.log( a );   // undefined
    console.log( b );   // ReferenceError!      
    var a;
    let b;     
}
Copy the code

Let’s look at the block-level scope.

function getVal(boo) {
    if (boo) {
        var val = 'red'
        // ...
        return val
    } else {
        // You can access val here
        return null
    }
    // You can also access val here
}
Copy the code

With let:

function getVal(boo) {
    if (boo) {
        let val = 'red'
        // ...
        return val
    } else {
        // There is no access to val
        return null
    }
    // There is no access to val
}
Copy the code

Also in the for loop:

function func(arr) {
    for (var i = 0; i < arr.length; i++) {
        // i ...
    }
    // this access gets I
}
Copy the code

After using let:

function func(arr) {
    for (let i = 0; i < arr.length; i++) {
        // i ...
    }
    // there is no access to I
}
Copy the code

That is, let can only work inside curly braces.

Const again, const represents a constant index of a value.

const aa = 11;
alert(aa) / / 11
aa = 22;
alert(aa) / / an error
Copy the code

But the value of a constant can never be changed until garbage collection, so use it with caution.

Another thing to note is that constants must be declared with initial values, as in other languages. Even if we want a constant of undefined, we need to declare:

const a = undefined;
Copy the code

Finally, I’ll mention the block-level scope.

Previously, javascript had no block-level scope, and we modeled block-level scope through ().

(function(){
 // Here is the block-level scope}) ();Copy the code

In ES6, however, {} can be used directly to code block-level scopes. So the contents of {} are not accessible outside {}.

We can look at the following code:

if (true) {
    function foo() {
        console.log("1"); }}else {
    function foo() {
        console.log("2" );
    }
}

foo();      / / 1
Copy the code

In javascript as we know it, the output of this code is 1. This is called a function declaration upgrade, which not only improves the function name, but also the function definition.

In ES6, however, this code may throw ReferenceErroe errors. Foo () cannot be accessed outside the block-level scope of {}, which means that function declarations, like let definition variables, are restricted to the block-level scope.

Event loop

Start with Promise, process.nextTick, and setTimeout to talk about the Job queue in Event Loop

Brief introduction: talk about promise. Resove, setTimeout, setImmediate, process. NextTick EvenLoop queue in the execution sequence

The event loop refers to the main thread reading tasks from the “task queue”, for example

Case 1:

setTimeout(function(){console.log(1)},0);

console.log(2)

/ / output 2, 1
Copy the code

In the example above, we know that the synchronization task in the main thread is executed first, and when the main thread is finished, the task is read from the Event loop, so we print 2 and then 1.

Event loop The sequence of read tasks depends on the read rules of different tasks in the Job queue. Here’s an example:

Example 2:

setTimeout(function () {
  console.log(3);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});
console.log(1);
// The output is 1, 2, 3
Copy the code

Print 1 first, no problem, because the synchronization task is executed first in the main thread. The problem here is how to define the execution priority of setTimeout and promise. then tasks.

There are two types of queues in the Job queue: Macro-task and microTask. Let’s take an example of the order of execution. Let’s say

The macro-task queue contains tasks a1, A2, and A3. The micro-task queue contains tasks B1, B2, and B3

First, execute the task at the beginning of the Marco-Task queue, that is, task A1. After the task is executed, execute all tasks in the Micro-Task queue, that is, execute B1, B2, and B3 in sequence. Then clear the tasks in the Micro-Task. The second task in Marco-Task is then executed and the cycle continues.

Now that we know the execution order of the macro-task and micro-Task queues, let’s take a look at the actual tasks contained in the two types of queues in the real world (let’s take Node V8 as an example). In Node V8, the real order of the two types of tasks is as follows:

The macro-task queue actually contains tasks: Script,setTimeout, setInterval, setImmediate, I/O, UI rendering

The micro-task queue actually contains tasks: Process. nextTick, Promises, Object.observe, MutationObserver

Thus, the execution order we get should be:

Script — > Process. nextTick — >Promises… – > setTimeout – > setInterval – > setImmediate – > I/O – > UI rendering

In ES6, macro-task queues are called ScriptJobs, while micro-tasks are called PromiseJobs

3. Examples of execution sequence in the real environment

(1) setTimeout and promise

Example 3:

setTimeout(function () {
  console.log(3);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});

console.log(1);
Copy the code

Let’s start with the example in section 1, which follows the following order:

Script (main program code) — > Promise — >setTimeout: 1 — >2————>3 (2) process.nextTick and Promise, setTimeout

Example 4:

setTimeout(function(){console.log(1)},0);

new Promise(function(resolve,reject){
   console.log(2);
   resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);
/ / output 2,6,5,3,4,1
Copy the code

This example is a little more complicated, but one thing to note here is that when you define a promise, the promise construction part is executed synchronously, so that the problem is solved.

The execution order of the Job queue is as follows:

Script (main program code) — >process.nextTick — > Promise — >setTimeout

I) Body part: The construction part that defines the promise is synchronous, so 2 is printed first, and then 6 is printed from the body part (in the synchronous case, strictly in the order defined)

II) process. NextTick: output 5

III) promise: where the promise part, strictly speaking, is actually a promise. Then part, output is 3,4

IV) setTimeout: output 1

The order of execution is 2 — >6 — >5 — >3 — >4 — >1

(3) More complex examples

setTimeout(function(){console.log(1)},0);

new Promise(function(resolve,reject){
   console.log(2);
   setTimeout(function(){resolve()},0)
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);

// Outputs 2, 6, 5, 1, 3, 4
Copy the code

The difference between this case and our example in (2) is that there is no synchronous resolve in the construction of the promise. Therefore, the promise. Then does not exist in the current execution queue, and only the then method will exist when the promise is transferred from pending to resolve. Resolve is done in a setTimout time, so 3,4 is output.

Typeof and instanceof

ECMAScript is loosely typed, requiring a means to detect the data typeof a given variable at a time, typeof operators (note not functions!). It’s the person who provides that information

Typeof can be used to detect both base and reference data types.

The syntax is as follows:

typeof variable
Copy the code

Returns six String results:

  • “Undefined” – if the value is undefined
  • “Boolean” – If the value is a Boolean
  • “String” – if the value is a string
  • “Number” – if the value is numerical
  • “Object” – If the value is an object or null
  • “Function” – If this value is a function example:
console.log(typeof 'hello'); // "string"
console.log(typeof null); // "object"
console.log(typeof (new Object())); // "object"
console.log(typeof(function(){})); // "function"
Copy the code

Typeof is mainly used to detect basic data types: Value, string, Boolean, undefined, because when Typeof is used to detect reference type values, typeOF returns “Object” values for any Object instance (including NULL). There is no way to tell which Object is the Object, and it is not useful for actual encoding.

Instanceof is used to determine whether a variable is an instanceof an object

Typeof is a great aid for detecting primitive data types, but this operator is of little use when detecting values of reference types. In general, we don’t want to know that a value is an object, but rather what kind of object it is. At this point we can use the instanceof operator provided by ECMAScript.

The syntax is as follows:

result = variable instanceof constructor
Copy the code

Returns a Boolean value:

  • True – the instanceof operator returns true if the variable is an instanceof the given reference type
  • False – the instanceof operator returns false if the variable is not an instanceof the given reference type:
function Person(){}
function Animal(){}
var person1 = new Person();
var animal1 = new Animal();
console.log(person1 instanceof Person); // true
console.log(animal1 instanceof Person); // false
console.log(animal1 instanceof Object); // true
console.log(1 instanceof Person);   //false


var oStr =  new String("hello world");
console.log(typeof(oStr));  	// object
console.log(oStr instanceof String);
console.log(oStr instanceof Object);

// Determine if foo is an instance of class foo

function Foo(){}
var foo = new Foo();
console.log(foo instanceof Foo);

// Instanceof in relation to inheritance
console.log('Instanceof in relation to inheritance');


function Aoo(){}
function Foo(){}

Foo.prototype = new Aoo();
var fo = new Foo();

console.log(fo instanceof Foo);
console.log(fo instanceof Aoo)
Copy the code

By convention, all values of reference types are instances of Object. Therefore, the instanceof operator always returns true when detecting a reference type value and the Object constructor. If you use the instanceof operator to detect a primitive type value, it will always return false because the primitive type is not an object.

console.log(Object.prototype.toString.call(null));
// [object Null]
undefined
console.log(Object.prototype.toString.call([1.2.3]));
//[object Array]
undefined
console.log(Object.prototype.toString.call({}));
// [object Object]
Copy the code

Common methods of inheritance

Prototype chain inheritance

Defines property and method code that uses stereotypes to make one reference type inherit from another

function SuperType(){
    this.property = 'true';
}

SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subProperty = 'false';
}

SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
    return this.subProperty;
}

var instance = new SubType();
alert(instance.getSuperValue());//true
Copy the code
  • Advantages of simple and clear, easy to implement, in the parent class new prototype attributes and methods, subclasses can access.
  • The disadvantage of a function that contains a reference type value is that all instances point to the same reference address. If you change one, all the others will change. Arguments cannot be passed like supertype constructors

Constructor inheritance defines a constructor that calls a supertype inside a subtype constructor

code

function SuperType(){
    this.colors = ['red'.'yellow'];
}

function SubType(){
    SuperType.call(this);
}

var instance1 = new SubType();
instance1.colors.push('black');


var instance2 = new SubType();
instance2.colors.push('white');

alert(instance1.colors);//'red','yellow','black'

alert(instance2.colors);//'red','yellow','white'
Copy the code
  • The advantages are straightforward, directly inheriting the properties and methods of the supertype constructor
  • The disadvantage is that methods are defined in constructors, so function reuse is out of the question, and the properties and methods of archetypes in supertypes are invisible to subtypes, so all types can only use the constructor pattern.

Combination of inheritance

Defines inheritance of multiple stereotype properties and methods using stereotype chains and instance inheritance using constructors

code

function SuperType(name){
    this.name = name;
    this.colors = ['red'.'black'];
}

SuperType.prototype.sayName = function()
{
   alert(this.name); 
}


function SubType(name,age){
    SuperType.call(this,name);
    this.age = age;
}

SubType.protptype = new SuperType();
SubType.protptype.sayAge = function(){
    alert(this.age);
    
}
Copy the code
  • Advantages solve two problems in constructor and stereotype inheritance
  • Disadvantages: Whenever a supertype constructor is called twice