preface
This chapter to share common Js core knowledge, development will be necessary, interview
directory
- Deep copy, shallow copy
- Scope, scope chain, execution context
- This keyword
- Higher-order functions – closures
- Prototype, prototype chain
- Js object-oriented – encapsulation – inheritance
- Execution mechanism – Event Loop – Event Loop
- Function anti – shake and throttling
- The function is currified
One, deep copy, shallow copy
What about deep copy and shallow copy
Deep copy creates a new memory address to hold the value; Shallow copies are references to properties of the object, not the object itself; Shallow copy only copies one layer, if there are many layers, it will still affect the original object
Shallow copy, reference to value, result can be found to change the value of obj2 property, obj also changed accordingly;
var obj ={a:1.b:2}
var obj2 = obj
obj2.a = 2
// obj2 {a: 2, b: 2}
// obj {a: 2, b: 2}
Copy the code
Deep copy creates a new memory address and stores a copy of obj2, which does not affect each other. Similarly, if we use code to do this, we can find that obj and obj2 print completely different.
function clone(source) {
var target = {};
for(var i in source) {
if(source.hasOwnProperty(i)) { target[i] = source[i]; }}return target;
}
var obj = {a:1.b:2}
var obj2 = clone(obj)
obj2.a = 2
// obj2 {a: 2, b: 2}
// obj {a: 1, b: 2}
Copy the code
The above two examples are just the realization of single-layer data format, in fact, multi-layer is the same, there are many ways to achieve deep copy, here I list several common examples of multi-layer deep copy for children’s reference, take the object to practice;
Json.stringify (), by formatting the object, assigning the value, and then going back Disadvantage: object no containing a new Date or function
var obj = {a:1.b:2.c:3}
var obj2 = JSON.stringify(obj)
obj2 = JSON.parse(obj2)
// Create a copy of obj
Copy the code
Handwritten recursion
function clone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) { // hasOwnProperty determines whether the object contains I;
if (typeof source[i] === 'object') {
target[i] = clone(source[i]); // Notice here, recursive operation
} else{ target[i] = source[i]; }}}return target;
}
var obj = {a:1.b:2.c:3}
var obj2 = clone(obj)
Copy the code
Scope, scope chain, execution context
Scope, chain of scope
JavaScript has global scope, function scope, and block-level scope (new in ES6). We can think of a scope as a separate domain with its own properties, variables, and methods
- Global scope: Needless to say, variables that can be accessed anywhere
- Function scope: variables that can be accessed within the body of a function; Closures can be used to access local scopes across functions
- Block-level scope: new in ES6, with the let command added block-level scope, private scope, will not be polluted
Let’s use a small example to illustrate the specific scope scenario
var a = 100
function F1() {
var a = 200;return function () {consoleThe (a)}}function F2(f1) {var a = 300
console.log(f1())
}
var f1 = F1()
F2(f1) / / 200
/ / parsing
Var f1 = f1 ();
// F1() returns an anonymous function function () {console.log(a); } that is, an anonymous function is passed in
// Then execute F2(f1), the variable f1 is an anonymous function
// F2 executes the code body and prints f1(). Where is the scope of f1()?
Copy the code
In the above code, the value of variable A is found in function F1 instead of F2, because global variables are found in the scope chain (that is, up where anonymous functions are defined), not when the function is executed; So it’s 200. What if I had this code down here?
var a = 100
function F1() {return function () {consoleThe (a)}}function F2(f1) {var a = 300
console.log(f1())
}
var f1 = F1()
F2(f1) / / 100
Copy the code
If we find the scope of the function F1, if we don’t find it, we will search up one level, so the output is 100
What if the next level isn’t there? If you look up and down until you find the global scope and you don’t find it, you say game over. This layer by layer relationship is the scope chain
Execution context
Speaking of execution in the afternoon, may be a lot of friends are more meng force, to be honest, I was also a face meng force, after a wake up, now share to you the execution context is an abstract concept, Js any code action is carried out in the execution context
Execution context: An object automatically created by the Js engine that contains the execution stack of all variable properties in the corresponding scope: used to manage the resulting execution context
Performs context creation and initialization
global
- Identify the window as a global execution context before executing global code
- Preprocessing global data
- The global variable defined by var ==>undefined is added as the property of window
- Function declared global function ==> assignment (fun), added as window method
- This ==> Assigns (window) to this
- Start executing global code
function
- Create the corresponding function execution context object (virtual, on the stack) before calling the function and preparing to execute the function body
- Local data is preprocessed
- Parameter ==> Assignment (argument)==> added as an attribute of the execution context
- Arguments ==> Assign (argument list) to add as an attribute for the execution context
- The local variable defined by var ==>undefined, added as an attribute of the execution context, declared in advance
- Function declared function ==> assignment (fun), added as an execution context method, declared earlier
- This ==> assigns (the object calling the function) and determines this
- Start executing the function body code
Then what is the execution stack, we through a network diagram (MOOC notes) to understandAt a glance, you can see that the execution stack is advanced and then out, all the function environment is finished, the global environment will be out of the stack, which means the end, we use code to implement this process
// Use the illustration of moOCs notes as an example:
console.log(1);
function pFn() {
console.log(2);
(function cFn() {
console.log(3); } ());console.log(4);
}
pFn();
console.log(5);
// Output: 1 2 3 4 5
Copy the code
Resolution: First go to the window.onload global environment page to load the event print 1, The global environment is pushed to the bottom of the stack and then the implementation function pFn enters the execution stack printing 2 and then the closure function cFn enters the execution stack printing 3. When the cFn function body is executed, the printing 4 is followed by the printing 4. When the pFn function body is executed, the printing 5 is finally printed, and the global environment is pushed out of the stack
Conclusion: JavaScript is single-threaded and all code is executed from the top down. When the browser executes global code, it first creates the global execution context, pushing it down the execution stack. Each time a function is entered, an execution context is created for that function, and it is pushed to the top of the stack. When it is finished, it is removed from the stack, waiting for garbage collection, and finally, there is only one global execution context
This keyword
What is this?
This is a JavaScript keyword that represents an internal object generated automatically when a function is run. The value of this can change depending on the situation in which the function is used. But there is a general rule that this always refers to the object on which the function is called. (Js everything is object emmm ~~~)
It is important to understand that the value of this is checked at execution time, not at definition. Why? – Because this is part of the execution context, and the execution context needs to be determined before the code executes, not when it is defined; The other thing is that this cannot be assigned; Here are a few examples to illustrate
In the constructor
var x = 1;
function test() {
console.log(this.x);
}
test(); / / 1
// Conclusion: This refers to the global window
Copy the code
In a normal object
var x = 0 ;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;
obj.m(); / / 1
// Conclusion: this points to obj
Copy the code
New A New constructor
var x = 1;
function test() {this.x = 2;
}
var obj = new test();
obj.x / / 2
x / / 1
// Conclusion This refers to the instance object of the constructor that comes out of new, namely obj
Copy the code
This in the closure
var x = 1;
var object = {
x: 2.getX: function() {
return function() {
return this.x;
};
}
}
conosole.log( object.getX()() ); / / 1
// Parse: object.getx (), which calls the function getX() in object.
// This should refer to the object
Object.getx ()(); Let me break it down
// var fun = object.getX(); Return An anonymous function assigned to the variable fun
// The anonymous fun() function is called when the execution environment is global and all points to window
// So the execution result is 1
Copy the code
We can see that the direction of this is regular, and also verify the statement I said above:
**this always refers to the object calling the function **
So just to conclude
- This is a keyword in the Js language
- This is determined at function execution time, because this is part of the execution context, which needs to be determined before the function body code is executed, not when it is defined
- This always refers to the object calling the function
- Note: The strict mode is slightly different
In fact, this can also be changed, through the bind, call, apply, specific use of your own baidu
Higher-order functions – closures
Closures are a difficult and characteristic feature of Javascript, and many advanced applications rely on closures.
What is a closure?
A closure is a function that reads variables inside other functions. In javascript, only child functions inside a function can read local variables, so closures can be understood as “functions defined inside a function.” In essence, closures are Bridges that connect the inside and outside of a function.
To put it simply: a function defined inside a function forms a closure; To look at the comments, consider an example: the inner function needs to reference the variables of the outer function and fire in order to actually form a closure
function f1(){var n=999;return function (){alert (n); }}varResult = f1 (); result();/ / 999
// function f1 internally defines an anonymous function that forms a closure
// Suppose we need to use the function f1 in the outer scope and the inner variable n
// Then we need to return an inner function via f1. This inner function returns the local variable n of f1
// This is how we access the variables inside the function
Copy the code
I don’t know if you can understand this, but closures use a lot of scenarios and functionality;
The purpose of closures
2. These variables are always stored in memory (disguised storage, not polluted) to extend the life cycle of local variables.
Pros and cons of closures:
Advantages: You can access variables inside a function, and they are not polluted, and are always stored in memory disadvantages: closures will cause variables in a function to be stored in memory, memory consumption is high, so do not abuse closures, otherwise it will cause page performance problems, in IE may lead to memory leaks. The solution is to clear all unused local variables before exiting the function. Variable = null
Memory overflow and memory leak
Memory overflow A program error that throws a memory overflow when the program runs on more memory than is available
Common memory leaks 1, unexpected global variables 2, timers or callback functions not cleaned up in time 3, closures
Prototype, prototype chain
Prototype: In JavaScript, a prototype is a Prototype object that represents relationships between types. Prototype chain: Everything in JavaScript is an Object, and there is an inheritance relationship between objects. The prototype points to the parent Object through prototype until Object, thus forming a chain, which is called prototype chain in professional terms
Let’s talk about it in detail
Prototype Indicates the explicit prototype
A prototype property is automatically created for each function. Subclasses inherit this property, such as:
// The prototype property is a function property
function Person() {} // constructor Person
Person.prototype.name = 'Hisen'; // The constructor prototype mounts a property named with the value Hisen
var person = new Person(); // Create an instance object person based on the constructor
console.log(person.name) // Hisen
Copy the code
Let’s use a diagram to show the constructor’s relationship to Prototype
So how do we represent the relationship between instances and constructor prototypes, namely Person and Person.prototype?
__proto__ Implicit prototype
Every JavaScript object has a property called __proto__, which points to the display prototype of the instance object’s constructor
function Person() {}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true indicates that the display stereotype === implicit stereotype
// The instance object is related to the constructor
console.log(prson.constructor === Person) // true
Copy the code
So let’s update the diagram:Since both the instance object and the constructor can point to the stereotype, does the stereotype have properties pointing to the constructor? Of course there is;
constructor
Each stereotype has a constructor property pointing to the associated constructor
function Person() {}
console.log(Person === Person.prototype.constructor); //true
Copy the code
So update the diagram:Through the above examples, we understand the relationship between prototypes, constructors, and instance objects; Where is the prototype chain? Don’t worry, let’s read on:
Prototype chain
When reading the attribute of the instance Object, if it cannot be found, it will look for the attribute in the prototype associated with the instance Object. If it still cannot be found, it will look for the prototype of the prototype, until it finds the top-level Object, or fails to find it, it announces to give up and returns NULL.
Let’s look at an example
function Person() {}
Person.prototype.name = 'Hisen';
var person = new Person(); // new a subclass
person.name = 'Hisen child'; // Add the attribute name to the subclass and assign the value
console.log(person.name) // Hisen child
delete person.name; // Delete person.name;
console.log(person.name) // Hisen will look for the name in the prototype, which is the name of the parent Person prototype
Copy the code
As you can see, after deleting the person.name, it will look up one level, i.e. person.__proto__. (Person._proto_ == person.prototype) (Person.prototype) Print Hisen but what if there is no Person. Prototype in the parent class? What is the archetype of the archetype?
In the previous section, we said that a prototype is also an object, and since it is an object, we can create it in the most primitive way, which is:
var obj = new Object(a); obj.name ='Hisen'
console.log(obj.name) // Hisen
Copy the code
So the prototype Object is generated by the Object constructor, in combination with the instance__proto__
Object pointing to the constructorprototype
, so let’s update the diagram again:
How about the Object. Prototype?Null,
isnull
“, which is whyObject.prototype
I can stop looking so the last diagram is going to be Finally, the blue line in the picture is the prototype chain.
Sources of prototype and prototype chain diagram, author: sea row boat in the https://github.com/ljianshu/Blog/issues/18
Js object-oriented – encapsulation – inheritance
encapsulation
Object orientation has three main features: encapsulation, inheritance and polymorphism. For ES5, there is no concept of class, and due to the functional scope of JS (variables inside a function can not be accessed outside the function), so we can simulate the concept of class. In ES5, a class actually stores the variable of a function, which has its own properties and methods; The process of putting attributes and methods together as a class is called encapsulation, and we won’t do much analysis here. Let’s talk about inheritance
inheritance
In Js, it can be said that there are many ways to inherit, of course, each has advantages and disadvantages, below we list several common analysis:
Prototype inheritance
// Create the parent constructor
function SuperClass(name){
this.name = name;
this.showName = function(){
alert(this.name); }}// Sets the parent constructor's prototype object property age
SuperClass.prototype.age= '18';
// Create a child constructor
function SubClass(){}
// Sets the prototype of the child constructor to equal the prototype of the parent constructor
SubClass.prototype = SuperClass.prototype; // Prototype inheritance key points
// Generate an instance
var child = new SubClass()
child.age/ / 123
child.name // undefined
Copy the code
Note:
- The prototype of the child constructor = the prototype of the parent constructor implements prototype inheritance
- A new instance object, based on the child constructor new, indirectly inherits the stereotype properties of the parent constructor
- So print: child.age // 18
- The child constructor inherits only the parent constructor’s properties and methods. It does not inherit the parent constructor’s properties and methods, so undefined. Is there a way to inherit the parent constructor’s own properties and methods as well? The answer, of course, is yes. Keep reading
Prototype chain inheritance
Prototype = new parent constructor ()
// Create the parent constructor
function SuperClass(){
this.name = 'HiSen';
this.age = 25;
this.showName = function(){
console.log(this.name); }}// Set the parent constructor's prototype property friends and method showAge
SuperClass.prototype.friends = ['js'.'css'];
SuperClass.prototype.showAge = function(){
console.log(this.age);
}
// Create a child constructor
function SubClass(){}
// Implement inheritance - child constructor prototype = new a parent constructor
SubClass.prototype = new SuperClass();
// Modify the constructor properties of the child constructor's prototype, since the parent constructor points to the SuperClass; So we have to modify it.
SubClass.prototype.constructor = SubClass;
// Generate an instance
var child = new SubClass();
console.log(child.name); // HiSen
console.log(child.age);/ / 25
child.showName();// HiSen
child.showAge();/ / 25
console.log(child.friends); // ['js','css']
// When we change friends, the parent constructor's prototype object also changes
child.friends.push('html');
console.log(child.friends);// ["js", "css", "html"]
var father = new SuperClass();
console.log(father.friends);// ["js", "css", "html"]
Copy the code
In this example, we can see that the child constructor not only inherits the attributes and methods of the parent constructor prototype, but also inherits its own attributes and methods of the parent constructor. If you are careful, you may already see the pain point. When we modify the inherited properties of the child constructor, the prototype object of the parent constructor is also affected. Is there a way to fix this pain point? The emMM ~~ method must have, for example:
Object.create
ECMAScript 5 introduced a new method: Object.create(). You can call this method to create a new object. The prototype of the new object is the first argument passed when the create method is called:
var obj = {a:1.b:2.c:3}
var obj2 = Object.create(obj)
Obj2.__proto__ returns {a:1,b:2,c:3}
// obj2.a // 1
Copy the code
The object.create () method takes two arguments :Object.create(obj,propertiesObject); Obj: An object, which should be the prototype of the newly created object. PropertiesObject: Optional. The parameter Object is a set of properties and values whose property names will be the property names of the newly created Object and whose values will be property descriptors (these property descriptors have the same structure as the second argument to Object.defineProperties()). Note: this parameter object cannot be undefined, and only enumerable properties that the object owns are valid, that is, properties on the prototype chain of the object are invalid.
Of course, there are other ways to implement inheritance, such as using deep copy full copy, Object.assign(), ES6 class classes, etc. Here is not an example.
Js execution mechanism – Event Loop – Event Loop
Extension: single thread
Single threading of Javascript – One of the language features of Javascript (which is at the heart of the language) is, to quote Seffo, single threading. What is a single thread? To put it simply, you can only do one thing at a time. When there are multiple tasks, you can only perform the next one after completing it in one order.
Extension: Why is JS single threaded
JS was originally designed to be used in browsers. As a browser scripting language, JavaScript is mainly used to interact with users and operate DOM. If JS in browsers is multi-threaded, it will bring complicated synchronization problems
For example, if there are two threads of JavaScript at the same time, one thread adds content to a DOM node, and the other thread removes that node, which thread should the browser use?
Therefore, in order to avoid complexity, JavaScript is a single thread since its birth. In order to improve CPU utilization, HTML5 proposes the Web Worker standard, which allows JavaScript scripts to create multiple threads, but the sub-threads are completely controlled by the main thread and cannot operate DOM. So this standard doesn’t change the single-threaded nature of JavaScript;
Event loop
In Js execution, synchronous tasks and asynchronous tasks enter different threads respectively, synchronous tasks enter the main thread, asynchronous tasks enter the Event Table (Event list) and register functions. When the specified asynchronous task completes, the Event Table moves this function to the Event Queue. When the main thread is empty, the Event Queue reads the corresponding function and enters the main thread for execution. This process is repeated over and over again, known as an Event Loop. Let’s look at a pictureLet’s put this into practice with a code example:
setTimeout(function(){
console.log('1')});new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3')});console.log('4');
Copy the code
SetTimeout is asynchronously queued, and then promise’s THEN is asynchronously queued.
The result is 2, 4, 1, 3, and the result is 2, 4, 1, 3. Is this the case? Read on:
The setTimeout is placed in the Event Queue, and the promise’s then function is placed in the Event Queue. Unfortunately, the two queues are not one;
— — — — — — — — — — — — — — important start — — — — — — — — — — — — — — — in Js Event Loop mechanism of Promise actuator code will be in step with thread synchronization, But promise’s callback is based on the fact that the macro task takes precedence over the micro task and if you look at the details, the micro task takes precedence over the macro task, Below two sentences Each macro task execution must be present before completion of the task queue to empty So can also be understood as a micro task priority is higher than the macro task emmmm ~ ~ — — — — — — — — — — — — — — important end — — — — — — — — — — — — — — — –
Macro tasks and micro tasks in Js – briefly note
Macro-task: includes the whole code script, setTimeout, setInterval Micro-task: Promise, process.nexttick
Now let’s go back to the example above, because setTimeout is a macro task, even though it was executed first, it was placed in the macro task event queue, and the code continues to check for microtasks. The then function that detects the Promise puts it in the microtask queue. Wait until all the code in the main process has finished executing. Get the callback function from the microtask queue, and then get the callback function from the macro task queue when the microtask queue is empty.
So the correct result is of course: 2,4,3,1;
Function anti – shake and throttling
In fact, function anti – shake and throttling are the optimization of Web performance, mainly on the web page frequently triggered, the frequency of a fast event for an optimization. For example: scroll bar event, input box input event, mouse movement event and so on.
Image stabilization
Function anti – shake is in fact within a specified time, frequently trigger this event, the last trigger shall prevail; This is done by creating a timer. Each time it is executed, the old timer is cleared and a new timer is created to record the time again
// Parameters: the number of milliseconds for the function and interval to execute
function debounce(fn, time) {
var timer = null; / / declare the timer
return function() {
clearTimeout(timer) // Clear the timer
timer = setTimeout(function() { // Create a timer assigned to the local variable timer
fn.apply(this)
}, time)
}
}
// Trigger multiple times within the specified time, depending on the last time,
// Because each time the timer is triggered, the old timer is cleared without execution and a new timer is created
Copy the code
The throttle
Function throttling is an event that is triggered only once in a specified period of time; The implementation method is through the timestamp, the current timestamp – the last time to execute the timestamp > set the specified time, it takes effect once; That is, if the event is fired frequently, the event will fire less frequently.
// Parameters: the function to execute and the number of milliseconds
function throttle(fn, time) {
var lastTime = 0; // Initialize the last execution time
return function() {
var nowTime = Date.now(); // Get the current time in milliseconds
if (nowTime - lastTime > time) { // Current time ms - last execution time ms > Set time
fn.call(this);
lastTime = nowTime; // Update the last word execution time in milliseconds}}}// For each execution, the current time is subtracted from the last execution time
// If the time is longer than the set time, the event will be triggered once, effectively saving the event trigger frequency.
Copy the code
The function is currified
A simple way to think about it is: a chain call that converts multiple arguments to a single argument. In fact, it is a bit like a segmented return. Let’s look at a simple example
// Common mode
function add (x, y, z) {
return x + y + z;
}
add(1.2.3) / / 6
// Currization
function currying (x) {
console.log("x = " + x) // do something
return function(y) {
console.log("y = " + y) // do something
return function(z) {
return x + y + z
}
}
}
currying(1) (2) (3) / / 6
// x = 1
// y = 2
/ / 6
Copy the code
So this is a very simple example where you can see the benefits of currization when I print the values in different places, and it’s pretty obvious that I’m going to return the current result in segments, so what can I do? For example, we need to use the result of the first two parameters to do one thing, and then need to use the result of the last one to do another thing, so we can trigger the corresponding function respectively.
Welcome to praise, a little encouragement, great growth