This article records my understanding of ES5 knowledge points

= = = = = = = = = = = = = = = = = = = = = = related articles and open source libraries = = = = = = = = = = = = = = = = = = = = = = =

series

1. Front-end knowledge sorting -HTML, CSS

2. Front-end knowledge sorting -ES5

3. Front-end knowledge sorting -ES6

4. Front-end knowledge sorting -VUE chapter

Personally maintained open source component library

1. Bin-ui, a VUe-based PC component library

2. Tree organizational structure components

3. Bin-admin: background management system integration solution based on bin-UI

4. Bin-data, a data visualization framework based on bin-UI and Echarts

5. Other ecological links

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =


1 How JS creates objects

There are three ways to create objects in ES5

// The first way, the literal var
o1 = {name: "o1"}var
o2 = new Object({name: "o2"})// The second way is through the constructor var
M = function(name){ this.name = name }var
o3 = new M("o3")Object.createvar p = {name: "p"}var
o4 = Object.create(p).create(p).create(pCopy the code

/ *

identifier

– All identifiers in JS that we can name ourselves can be called identifiers

– For example, variable names, function names, and attribute names are all identifiers

– Observe the following rules when naming an identifier:

1. The identifier can contain letters, digits, underscores (_), and $($)

2. The identifier cannot start with a digit

3. The identifier cannot be the keyword or reserved word in ES

4. Identifiers are generally hump nomenclature

-js is actually using Unicode encoding to save identifiers.

So in theory, all utF-8 contents can be used as identifiers

* /

If the attributes in the object do not conform to the identifier specification, what can I do? When the operator cannot get the property, for example var obj={1:1} console.log(obj.1)

Var obj={‘ 1 ‘:1} var obj={‘ 1’ :1} var obj={‘ 1 ‘:1} var obj={‘ 1’ :1

Var obj={name: ‘zhang3’}

Var obj={‘ 1 ‘:1} {obj[‘ 1’] = obj[‘ 1 ‘]

So what’s the difference between the two

Operator: The right side must be a simple identifier named after an attribute name, for example. Name

[]: The right-hand side must be an expression that evaluates to a string

Since [] is an expression that evaluates to a string, it gives [] powerful functions, such as string concatenation, ternary operators, and so on

let obj={'1':123, name:'Joe'}
console.log(obj['1'],obj.name,obj['name'] // output 123"Zhang" "Zhang"Copy the code

2 == and ===

Unlike Java comparisons, JS has these two ways of comparing, but how are they different

To put it simply: == equals the same, === equals strictly the same

If the two operand types are the same, compare them with ===; if they are different, compare them with ===; if the operand types are different, compare them with false.

Comparison process:

Double equals == :

(1) If the two values are of the same type, compare the three equal signs (===)

(2) If two values have different types, they may also be equal. Type conversion should be performed according to the following rules for comparison:

1) If one is null and one is undefined, then equal

2) If one is a string and one is a number, convert the string to a number and then compare

3 = = = = :

(1) If the types are different, they must not be equal

(2) If both values are the same, then they are equal; If at least one of them is a NaN, it is not equal. (To determine if a value is a NaN, use isNaN() only.)

(3) If both are strings, the characters in each position are the same, then equal, otherwise not equal.

(4) If both values are true or false, then they are equal

(5) If both values refer to the same object or function, they are equal; otherwise, they are not

(6) If both values are null, or undefined, then they are equal

So when do I use theta = theta and when do I use theta = theta, personally

Only in judging obj. A = = null when using double, is equivalent to obj. A = = = undefind | | obj. A = = = null

We use === (tri equals) for everything else because we usually have to determine the type of the two times when we’re trying to determine if it’s equal


3 为什么 0.1 + 0.2 != 0.3

Let’s start with a phenomenon. So why does this happen



Because JS uses IEEE 754 double precision version (64-bit), and as long as the IEEE 754 language has this problem.

We all know that computers represent the decimal system in binary, so 0.1 is represented in binary as

// (0011) indicates a loop

0.1 = 2^-4 * 1.10011(0011)

The problem is simply that the underlying representation of 0.1 and 0.2 is binary. In the double version, the binary sum is converted to decimal and the result is not equal to 0.3

So what do we do when we’re actually coding in this situation

The native solution is as follows

ParseFloat ((0.1 + 0.2).tofixed (10)) or convert to an integer and then convert to a decimal

4 What are prototypes and prototype chains

Every Function has a prototype attribute, except function.prototype.bind (), which points to the prototype.

Each object has a __proto__ attribute that points to the prototype of the constructor that created the object. [[prototype]] is an internal attribute that we can’t access, so use _proto_.

Objects can find properties that are not part of the object by __proto__, which links objects together to form a prototype chain.

The constructor

function Foo(name,age){
    this.name = name;
    this.age = age;
    //returnthis; } var f = new Foo('zhangshan', 20); Create a new object //2. Point this to the new object //3. Var a= new Object() var a= new Array() var a= new Array() var a= new Array() var a= new Array() var a= new Array() var a= new Array() var a= new Array() var a= new Array(function FooVar Foo = new Function() var Foo = new Function() var Foo = new Function()trueFoo. Prototype // f instanceof Object ==>trueCopy the code

Rules and examples of prototypes

// 1. All reference types (array, object, function) have object properties, that is, can extend attributes freely (except null).
    varobj={}; obj.a=100;
    vararr={}; arr.a=100;
    function fn(){} 
    fn.a=100;
All reference types (arrays, objects, functions) have a __proto__(implicit prototype) attribute whose value is an ordinary object
    console.log(obj.__proto__);
    console.log(arr.__proto__);
    console.log(fn.__proto__);
// 3. All functions have a prototype attribute whose value is an ordinary object
    console.log(fn.prototype);
For all reference types (arrays, objects, functions), the __proto__ attribute points to its constructor's Prototype attribute value
    console.log(obj.__proto__===Object.prototype);
// 5. When a view gets a property of an object, if the object itself does not have the property, thenGo to its __proto__(its constructor, prototype)function Foo(name,age){
        this.name = name;
    }
    Foo.prototype.alertName = function(){
        alert(this.name);
    }
    // Create an instance
    var f = new Foo('zhangsan');
    f.printName = function(){
        console.log(this.name);
    }
    f.printName();// You can get printName directly
    f.alertName();// Can't get the alertName attribute
Copy the code

Prototype chain

var f = new Foo('zhangsan');
f.toString();Copy the code

Analysis:

1. First look for the toString method in its properties, if not, look for the implicit __proto__

Prototype: Foo. Prototype: Foo. Prototype: Foo. Prototype: Foo. Prototype: Foo. Prototype: Foo

3.Foo. Prototype’s __proto__ refers to Object. Prototype’s explicit prototype, and then looks for its implicit __proto__

conclusion

Object is the father of all objects, all objects can be found by __proto__ Function is the father of all functions, Function. Prototype and Object. Prototype are two special objects created by the engine. The prototype object’s __proto__ refers to the prototype, and __proto__ connects the object to the prototype to form the prototype chain

What are scopes and closures

The issue of scopes and closures is an old one that comes up in interviews. Here’s a brief introduction,

Execution context

// Sample code:
    console.log(a);//undefined
    var a=100;
    fn('zhangsan');// zhangsan 20
    function fn(name){
        age=20;
        console.log(name,age);
        var age;
    }
/ / interpretation:
/ / range | a < script > tag or a function
/ / | global variable definition, the function declaration
/ / function | variable definitions, function declarations, this and the argumentsCopy the code

This point

This is checked at execution time, not at definition, and you must use function expressions when using bind

// Sample code:
    var a = {
        name:'A'.fn:function(){
            console.log(this.name);
        }
    }
    a.fn();//this===a
    a.fn.call({name:'B'});//this==={name:'B'}
    var fn1 = a.fn;
    fn1();//this===window
/ / analysis:
// 1. Execute as constructor
// 2. Execute as an object property
// 3. Execute as a normal function
// 4.call apply bind
    function fn1(name){
        alert(name);
        console.log(this);
    }
    fn1.call({x:100},'zhangsan');// the first argument to call is this
    {x:100}
    var fn2 = function (name){
        alert(name);
        console.log(this);
    }.bind({y:200})
    fn2('zhangsan');
    {y:200}Copy the code

scope

// 1. There is no block-level scopeif(true){
        var name = 'zhangsan'; } console.log(name); Var a = 100;function fn(){
        var a = 200;
        console.log('fn',a);
    }
    console.log('global',a); fn(); Var a = 100;function fn(){ var b = 200; console.log(a); // The variable not currently defined in scope is called the free variable console.log(b); } // the parent scope of the function is the same as that of the function at the time of its definition. Scope chain var a = 100;function F1(){
        var b = 200;
        function F2(){ var c = 300; console.log(a); // if a is a free variable, select a from F1's parent scope instead of console.log(b); // if b is a free variable, find b in F1 and print console.log(c); } F2(); } F1(); F2's parent scope is F1. F1's parent scope is global. This is the scope chainCopy the code

What is a closure

The definition of A closure is simple: if function A returns A function B, and function B uses A variable of function A, function B is called A closure.

function A() {
  let a = 1
  function B() {
      console.log(a)
  }
  return B
}Copy the code

Var defines a function using a closure in a loop

for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}Copy the code

First of all, because setTimeout is an asynchronous function, it will complete the loop first, at which point I will be 6, so it will output a bunch of 6’s.

for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}Copy the code

Here we insert two common problems to write the output result of the following program

var a = 6;
setTimeout(function () {
    console.log(a);
    a = Awesome!;
}, 1000); 
setTimeout(function () {
    console.log(a);
    a = 777;
}, 0);

a = 66;

/ / analysis
// 1. Execute the first line a=6
// 2. After executing setTimeout, the function passed in will be temporarily stored and will not be executed immediately
// 3. Run the last line a=66
// 4. Wait until all programs are executed and are in idle state to check whether there is a temporary execution queue
If there is no waiting time, execute immediately, i.e. Second setTimeout, output a=66, execute a=777
// 6. If the temporary execution function has a wait time, it will output a=777 after 1 second, and then assign 666 to a, so it will output 66 after 1 second and 777Copy the code

Please output the results of the following program and briefly analyze the process

Code 1:

var name = "The Window"; Var object = {name:"My Object", getNameFunc:function() {return function() {returnThis. The name; }; }}; console.log(object.getNameFunc()());Copy the code

Code 2:

var name = "The Window"; Var object = {name:"My Object", getNameFunc:function(){var that = this;return function() {returnThat. The name; }; }}; console.log(object.getNameFunc()());Copy the code

// Outputs The Window and My Object respectively

// 1.object.getNameFunc() returns a function whose context this is global.

// 2.object.getnameFunc () returns a function when that=this; That caches this of the context. Object, and the name of the object is printed when the () method is called

What is anti-shake and throttling

There is a need to do a complex calculation in a scrolling event or to implement a button against double clicking.

These requirements can be achieved through function jitter prevention. The first requirement, in particular, is that if you do complex calculations during frequent event callbacks, the page is likely to stall. It is better to combine multiple calculations into a single calculation and only do operations at a precise point.

PS: The purpose of both anti-shake and throttling is to prevent multiple calls to the function. The difference is that, if a user fires the function all the time, at intervals shorter than wait, the function will be called once in the case of stabilization, whereas the function will be called at intervals (wait) in the case of throttling.

Anti-jitter and throttling are different in nature. Anti-jitter means to turn multiple executions into the last one, and throttling means to turn multiple executions into periodic executions.

Understand the realization of anti – shake:

// func is the function that the user passes in to be buffedwaitConst debounce = (func,wait// Cache a timer IDletTimer = 0 // The function returned here is the anti-shake function actually called by the user // Empty the last timer if the timer has been set // Start a new timer, delay the execution of the method passed in by the userreturn function(... args) {if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, wait}} // It is not difficult to see if the user calls the function interval is less thanwaitIs cleared before the last time is up and does not execute the functionCopy the code

This is just a brief description of the concept, the implementation of the throttling function, if you are interested in trying to write your own.

7 Shallow copy

let a = {
    age: 1
}
let b = a
a.age = 2
console.log(b.age) / / 2
Copy the code

As we can see from the example above, if you assign an object to a variable, the value of both will be the same reference, and if one changes, the other will change.

Usually in development we don’t want to have this problem, we can use shallow copy to solve this problem.

Shallow copy

The first solution to this problem is object.assign.

let a = {
    age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
Copy the code

Of course we can also expand the operator (…) To solve the

let a = {
    age: 1
}
letb = {... a} a.age = 2 console.log(b.age) // 1Copy the code

Shallow copy usually solves most of the problems, but deep copy is needed when we encounter the following situations

let a = {
    age: 1,
    jobs: {
        first: 'FE'}}letb = {... a} a.jobs.first ='native'
console.log(b.jobs.first) // native
Copy the code

Shallow copies only solve the problem at the first level, if there are any objects in the following values, then we are back to the beginning

Deep copy

let a = {
    age: 1.jobs: {
        first: 'FE'}}let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FECopy the code

But there are limitations to this approach:

  • Ignores undefined
  • Ignore the symbol
  • Non-serializable function
  • Cannot resolve object referenced by loop

When a function, undefined, or symbol is encountered, the object does not serialize properly

let a = {
    age: undefined,
    sex: Symbol('male'),
    jobs: function() {},
    name: 'wb'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "wb"}
Copy the code

You’ll notice that the method ignores functions and undefined in the above cases.

But in general, complex data is serializable, so this function solves most of the problems, and it is the fastest deep-copy function among the built-in functions. Of course, if your data contains the above three cases, you can use recursion to implement a deep copy function (this section will be implemented later in vUE), but here is another general point to implement the deep copy function

8. How to accurately judge a type

We know that we can use typeof functions to determine a type, but typeof is not very accurate, as shown below

So what if I want to determine exactly whether a type is an object, an array, or a function?

Here, we can use the Object. The prototype. ToString. Call (obj) to accurately assess types

function typeOf (obj) {
  const  toString = Object.prototype.toString
  const  map = {
    '[object Boolean]': 'boolean'.'[object Number]': 'number'.'[object String]': 'string'.'[object Function]': 'function'.'[object Array]': 'array'.'[object Date]': 'date'.'[object RegExp]': 'regExp'.'[object Undefined]': 'undefined'.'[object Null]': 'null'.'[object Object]': 'object'
  }
  return map[toString.call(obj)]
}

Copy the code