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:
|
Code 2:
|
// 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