current position:Home>JavaScript advanced functions

JavaScript advanced functions

2022-04-29 08:09:10Chen Chen is trying

Two 、 Function advanced

1、 Prototype and prototype chain

Ⅰ- Prototype [prototype]

  1. Functional prototype attribute
  • Each function has one prototype attribute , By default, it points to a Object An empty object ( That is called : Prototype object )

  • There is an attribute in the prototype object constructor, It points to the function object

> * [ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-NJq3Dqwb-1650422408403)(.\JavaScript senior .assets\image-20210714201049312.png)]

  1. Add properties to prototype objects ( It's usually the method )
  • effect : All instance objects of the function automatically own the properties in the prototype ( Method )
  1. Code example
//  Each function has one prototype attribute ,  By default, it points to a Object An empty object ( That is called :  Prototype object )
console.log(Date.prototype, typeof Date.prototype)
function Fun () {
      }
console.log(Fun.prototype)  //  By default, it points to a Object An empty object ( Without our attributes )

//  There is an attribute in the prototype object constructor,  It points to the function object 
console.log(Date.prototype.constructor===Date)//true
console.log(Fun.prototype.constructor===Fun)//true

// Add properties to prototype objects ( Generally, it's the method ) ===> Instance objects can access 
Fun.prototype.test = function () {
      
    console.log('test()') 
}
var fun = new Fun()
fun.test()

Ⅱ- Explicit and implicit prototypes

  1. Each function function There is one. prototype, namely Explicit Prototype ( attribute )

  2. Each instance object has a [__ proto __], It can be called Implicit Prototype ( attribute )

  3. The value of the implicit prototype of the object is the value of the explicit prototype of its corresponding constructor

  4. Memory structure

>

  1. summary :
  • Functional [prototype] attribute : Automatically added when defining a function , The default value is an empty Object object

  • Object's [__ proto __] attribute : Automatically added when creating an object , The default value is... Of the constructor prototype Property value

  • Programmers can manipulate explicit prototypes directly , But you can't manipulate implicit prototypes directly (ES6 Before )

  1. Code example :
// Define the constructor 
function Fn() {
     
//  Internal default execution statement : this.prototype = {}
 }
// 1.  Each function function There is one. prototype, That is, explicit prototype properties ,  By default, it points to an empty Object object 
console.log(Fn.prototype)
// 2.  Each instance object has a __proto__, It's called an implicit prototype 
// Create instance object 
var fn = new Fn()  //  Internal default execution statement : this.__proto__ = Fn.prototype
console.log(fn.__proto__)
// 3.  The value of the implicit prototype of the object is the value of the explicit prototype of its corresponding constructor 
console.log(Fn.prototype===fn.__proto__) // true
// Add method to prototype 
Fn.prototype.test = function () {
     
 console.log('test()')
}
// Call the prototype's method through an instance 
fn.test()

Ⅲ- Prototype chain

Prototype chain

  1. Prototype chain
  • When accessing the properties of an object ,
  • First find in your own properties , Found return
  • without , Along a [__ proto __] This chain looks up , Found return
  • If you don't find it in the end , return undefined
    > * [ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-1PTA4HCC-1650422408405)(D:\Desktop\Font-end\ My front-end notes \JavaScript senior .assets\image-20220419131847309.png)]
  • Alias : Implicit prototype chain
  • effect : Find the properties of an object ( Method )

Constructors / Prototype / Relationship between instance objects ( The illustration )

var o1 = new Object();
var o2 = {
     };

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-xBK3xiwz-1650422408406)(D:\Desktop\Font-end\ My front-end notes \JavaScript senior .assets\image-20210714212928432.png)]

function Foo(){
       }
// amount to :var Foo = new Function();

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-aFAbDUYo-1650422408407)(.\JavaScript senior .assets\image-20210714212945164.png)]

ps: For all functions [__ proto __] It's all the same

// Add :
/* 1.  The object pointed to by the display prototype of the function is empty by default Object Instance object ( but Object dissatisfaction ) */
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
/* 2.  All functions are Function Example ( contain Function) */
console.log(Function.__proto__===Function.prototype)//true
/* 3. Object The prototype object is the end of the prototype chain  */
console.log(Object.prototype.__proto__) // null

Attribute problem

  • When reading the property value of an object : It will automatically find in the prototype chain

  • When setting the property value of an object : The prototype chain will not be found , If there is no such property in the current object , Add this property directly and set its value

  • Methods are generally defined in prototypes , Attributes are generally defined on the object itself through constructors

  • Code example

 function Fn() {
      }
 Fn.prototype.a = 'xxx'
 var fn1 = new Fn()
 console.log(fn1.a, fn1) //xxx Fn{}

 var fn2 = new Fn()
 fn2.a = 'yyy'
 console.log(fn1.a, fn2.a, fn2) //xxx yyy Fn{a: "yyy"}

 function Person(name, age) {
     
   this.name = name
   this.age = age
 }
 Person.prototype.setName = function (name) {
     
   this.name = name
 }
 var p1 = new Person('Tom', 12)
 p1.setName('Bob')
 console.log(p1)  //Person {name: "Bob", age: 12}

 var p2 = new Person('Jack', 12)
 p2.setName('Cat')
 console.log(p2) //Person {name: "Cat", age: 12}
 console.log(p1.__proto__===p2.__proto__) // true --> So methods are generally defined in prototypes 

Ⅳ-instanceof

  1. instanceof How to judge ?
  • expression : A instanceof B

  • If B The explicit prototype object of the function is in A Object's prototype chain , return true, Otherwise return to false

  1. Function It's through new Self generated examples
/*  Case study 1 */
function Foo() {
       }
var f1 = new Foo()
console.log(f1 instanceof Foo) // true
console.log(f1 instanceof Object) // true

/*  Case study 2 */
console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true

function Foo() {
     }
console.log(Object instanceof  Foo) // false

Ⅴ- Relevant interview questions

Test questions 1:

/*  Test questions 1 */
function A () {
     }
A.prototype.n = 1
let b = new A()
A.prototype = {
      n: 2, m: 3}
let c = new A()
console.log(b.n, b.m, c.n, c.m) // 1 undefined 2 3

Test questions 2: Principle Constructors / Prototype / Relationship between instance objects ( The illustration )

/*  Test questions 2 */
function F (){
     }
Object.prototype.a = function(){
     
console.log('a()')
}
Function.prototype.b = function(){
     
console.log('b()')
}

let f = new F()
f.a() //a()
f.b() //f.b is not a function --> Can't find 
F.a() //a()
F.b() //b()

console.log(f)//F{}
console.log(Object.prototype)//
console.log(Function.prototype)//

Result legend

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-xVSGbe3r-1650422408408)(.\JavaScript senior .assets\image-20210723173855550.png)]

2、 Execution context and execution context stack

When code is in JavaScript Middle runtime , The environment in which the code is executed is very important , It will be summarized as follows :

Global code —— Default environment for first code execution .

function code —— When the execution stream enters the function body .

(…) —— We regard Execution context Is an environment and scope of current code execution .

let me put it another way , When we start the program , We start with the global execution context . Some variables are declared in the context of global execution . We call it a global variable . When a program calls a function , What's going to happen ?

The following steps :

  • JavaScript Create a new execution context , We call it local execution context .
  • This local execution context will have its own set of variables , These variables will be local to the execution context .
  • New execution context pushed to execution stack . You can think of the execution stack as a container that holds the location of a program in its execution .

When does the function end ? When it meets a return Statement or an closing bracket }.

When a function ends , The following will happen :

  • This local execution context pops from the execution stack .
  • Function returns a value to the calling context . The call context is the local execution context , It can be a global execution context , It can also be another local execution context . It depends on the call execution context to handle the return value at this time , The returned value can be an object 、 An array 、 A function 、 A Boolean value, etc , If the function does not return sentence , Then return to undefined.
  • This local execution context is destroyed , Destruction is very important , All variables declared in this local execution context will be removed , No more variables , That's why It is called a variable owned in the local execution context .

Ⅰ- Variable promotion and function promotion

  1. Variable declaration promotion
  • adopt var Definition ( Statement ) The variable of , It can be accessed before the statement is defined

  • value :undefined

  1. Function declaration promotion
  • adopt function Declared function , You can call directly before

  • value : Function definition ( object )

  1. Lead to a question : How are variable promotion and function promotion generated ?
/*
 Interview questions  :  Output  undefined
*/
var a = 3
function fn () {
console.log(a)
var a = 4 // Variable Promotion 
}
fn()  //undefined
'--------------------------------------------'
console.log(b) //undefined   Variable Promotion 
fn2() // Callable    Function enhancement 
// fn3() // You can't    Variable Promotion 
var b = 3
function fn2() {  
  console.log('fn2()') 
}
var fn3 = function () { 
  console.log('fn3()') 
}

Ⅱ- Execution context

  1. Code classification ( Location )
  • Global code

  • function ( Local ) Code

  1. Global execution context
  • Before executing the global code window Determined as the global execution context

  • Preprocess global data

    • var Defined global variables ==>undefined, Added as window Properties of
    • function Declared global functions ==> assignment (fun), Added as window Methods
    • this==> assignment (window)
  • Start executing global code

  1. Function execution context
  • Calling function , Before preparing to execute the function body , Create the corresponding function execution context object ( Virtual , In the stack )

  • Preprocess local data

    • The shape parameter ==> assignment ( Actual parameters )==> Properties added as execution context
    • arguments==> assignment ( Argument list ), Properties added as execution context --> Students who don't understand look here
    • var Defined local variables ==>undefined, Properties added as execution context
    • function Declared function ==> assignment (fun), Method added as execution context
    • this==> assignment ( Object calling function )
  • Start executing function body code

Ⅲ- Execution context stack

  1. Before global code execution , JS The engine will create a stack to store and manage all execution context objects
  2. In the global execution context (window) after , Add it to the stack ( Pressing stack )–> So the bottom of the stack is 100% [window]
  3. After the function execution context is created , Add it to the stack ( Pressing stack )
  4. After the current function is executed , Remove the object at the top of the stack ( Out of the stack )
  5. When all the code is executed , There is only one left in the stack window
  6. Number of context stacks == Number of function calls +1
//1.  Enter the global execution context 
var a = 10
var bar = function (x) {
     
var b = 5
foo(x + b)   //3.  Get into foo Execution context  
}
var foo = function (y) {
     
var c = 5
console.log(a + c + y)
}
bar(10) //2.  Get into bar Function execution context 

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-nbkwGrGS-1650422408409)(.\JavaScript senior .assets\image-20210723183046182.png)]

Here we use a dynamic diagram to show :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-4p9JBLWU-1650422408411)(.\JavaScript senior .assets\ Execution stack and event queue .gif)]

Take a chestnut :

// chestnuts 
<!--
1.  Output what in turn ?
gb: undefined
fb: 1
fb: 2
fb: 3
fe: 3
fe: 2
fe: 1
ge: 1
2.  Several execution contexts are generated in the whole process ?  5
-->
<script type="text/javascript">
console.log('gb: '+ i)
var i = 1
foo(1)
function foo(i) {
     
if (i == 4) {
     
  return
}
console.log('fb:' + i)
foo(i + 1) // Recursively call :  Call yourself... Inside the function 
console.log('fe:' + i) // Out of the stack   So will  3 2 1 This is the result 
}
console.log('ge: ' + i)
</script>

Ⅳ- Relevant interview questions

Function promotion takes precedence over variable promotion , And will not be overridden by variable declaration , But it will be overridden by the variable assignment

/*  Test questions 1:  Do variable promotion first ,  Then perform the function promotion  */
function a() {
     }
var a
console.log(typeof a) // 'function'


/*  Test questions 2: */
if (!(b in window)) {
     
var b = 1
}
console.log(b) // undefined

/*  Test questions 3: */
var c = 1
function c(c) {
     
console.log(c)
var c = 3 // It has nothing to do with this trip 
}
c(2) //  Report errors  c is not a function

3、 Scope and scope chain

Ⅰ- Scope

  1. understand
  • It's just a piece of " turf ", The area where a code segment is located

  • It's static ( Relative to the context object ), When you write code, you determine

  1. classification
  • Global scope

  • Function scope

  • There is no block scope (ES6 With ) -->(java Language also has )

  1. effect
  • Isolate variables , There is no conflict between variables with the same name in different scopes
/* // No block scope  if(true) { var c = 3 } console.log(c) */
var a = 10,
b = 20
function fn(x) {
     
var a = 100, c = 300;
console.log('fn()', a, b, c, x) //100 20 300 10
function bar(x) {
     
  var a = 1000, d = 400
  console.log('bar()', a, b, c, d, x)
}
bar(100)//1000 20 300 400 100
bar(200)//1000 20 300 400 200
}
fn(10)

Ⅱ- The difference and relationship between scope and execution context

  1. difference 1:
  • Outside the global scope , Each function creates its own scope , The scope is already defined when the function is defined . Not when a function is called

  • The global execution context is after the global scope is determined , js Create... Before code execution

  • The function execution context is when the function is called , Before you create a function body

  1. difference 2:
  • The scope is static , As long as the function is defined, it will always exist , And will not change again

  • The execution context is dynamic , Create when calling a function , The function is automatically released at the end of the call

  1. contact :
  • Execution context ( object ) Is subordinate to the scope

  • Global context ==> Global scope

  • Function context ==> The corresponding function uses the field

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-W52FfElx-1650422408413)(.\JavaScript senior .assets\image-20210727141319410.png)]

Ⅲ- Scope chain

  1. understand
  • A chain formed by the scope of multiple parent-child relationships , Its direction is from bottom to top ( From the inside out )

  • When you look up variables, you look up them along the scope chain

  1. Search rules for finding a variable
  • Find the corresponding attribute in the execution context under the current scope , If there is a direct return , Otherwise enter 2

  • Find the corresponding attribute in the execution context of the upper level scope , If there is a direct return , Otherwise enter 3

  • Re execution 2 The same operation of , All the way to global scope , If you can't find it, throw an exception that you can't find

var a = 1
function fn1() {
     
var b = 2
function fn2() {
     
  var c = 3
  console.log(c)
  console.log(b)
  console.log(a)
  console.log(d)
}
fn2()
}
fn1()

Ⅳ- Relevant interview questions

The scope is already defined when the function is defined . Not when a function is called

Scope 1: The scope is already defined when the function is defined . Not when a function is called

var  = 10;
function fn() {
      console.log(x); }
function show(f) {
     
var x = 20;
f();
}
show(fn); // Output 10

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-eXVXHh1B-1650422408414)(.\JavaScript senior .assets\image-20210726192714660.png)]

② Object variables cannot produce local scopes

var fn = function () {
     
console.log(fn)
}
fn()

var obj = {
      // Object variables cannot produce local scopes , So I'll find the whole situation , Result in an error 
fn2: function () {
     
console.log(fn2)
//console.log(this.fn2)
}
}
obj.fn2()

4、 Sort out the preliminary knowledge points of closure

Before entering the closure , You should make sure that you can master the above knowledge points . You're not sure ? Oh, okay , Then follow me to see this part ( If you know how to skip directly )

Ⅰ- For example, chestnut analysis execution context

Before discussing closures , Let's look at the code below ( It is recommended to only look at the code brainstorming, and then look at the description in the notes ), It can also be regarded as combing and reviewing the above knowledge points :

1: let a = 3
2: function addTwo(x) {
     
3:  let ret = x + 2
4:   return ret
5:  }
6: let b = addTwo(a)
7: console.log(b)

In order to understand JavaScript How the engine works , Let's go into detail :

  1. In the 1 That's ok , We declare a new variable in the global execution context a, And assign to 3.
  2. And then it gets tricky , The first 2 Go to the first place 5 The line is actually together . What happened here ?
  • We declare a global execution context called addTwo New variables , What did we assign to it ? --> A function definition .

  • Two parentheses {} Everything between is assigned to addTwo, The code inside the function is not evaluated , Not implemented , Only stored in a variable for future use .

  1. Now we are in the 6 That's ok .
  • It looks simple , But there's a lot to break down . First , We declare a new variable in the context of global execution , And mark it as [b], Variable once declared , Its value is undefined.

  • Next , Still in the first place 6 That's ok , We see an assignment operator . We are going to give variables b Assign a new value , Next we see a function called . When you see a variable followed by a parenthesis (…) when , This is the signal to call the function , next , Each function returns something ( value 、 Object or undefined), Whatever is returned from the function , Are assigned to variables b.

  1. But first we need to call the tag addTwo Function of .JavaScript Will look up in its global execution context memory named addTwo The variable of . Oh , It found one , It's in [ step 2( Or the first 2 - 5 That's ok ) In the definition of ] Of . Variable [addTwo] Contains a function definition .
  • Be careful : Variable [a] Pass as parameter to function .

  • JavaScript Search variables in global execution context memory a, Find it , Found that its value is 3, And number 3 Pass as parameter to function , Ready to execute function .

  1. Execution context will now switch , A new local execution context was created , We named it [“addTwo Execution context ”, Execution context pushed to call stack . stay addTwo In execution context , What's the first thing we have to do ?
  • You might say ,“ stay addTwo A new variable is declared in the execution context ret”, It's not right .

  • The right answer is : We need to look at the parameters of the function first . stay addTwo Declare a new variable in the execution context [x], Because of the value 3 Passed as a parameter , So the variable x To be an assignment 3.

  • The next step is to addTwo Declare a new variable in the execution context ret. Its value is set to undefined( The third line ).

  1. Still the first 3 That's ok , An add operation is required .
  • First of all, we need x Value ,JavaScript Will look for a variable x, It will first addTwo Search in execution context , Found a value of 3. The second operand is a number 2. The sum of the two results is 5 It's assigned to variables ret.
  1. The first 4 That's ok , We return variables ret The content of , stay addTwo Find in context , Find the value for 5, return , End of the function .
  2. The first 4 - 5 That's ok , End of the function .
  • addTwo Execution context destroyed , Variable x and ret Has been eliminated. , They don't exist anymore .addTwo Execution context pop from call stack , Return value to call context , under these circumstances , Call context is global execution context , Because of the function addTwo Is called from the global execution context .
  1. Now let's move on 4 Content of step , Return value 5 Assigned to variable b, At this time, in fact, the program is still in the 6 That's ok ( The sense of space theft )
  2. In the 7 That's ok ,b Value 5 It's printed to the console .

For a very simple program , It's a very lengthy explanation , We haven't even talked about closures . But it's definitely going to involve , But first we have to take a turn or two .

Ⅱ- For example, chestnut analysis lexical scope

I want to explain , We have variables in the context of function execution , Variable in global execution context .JavaScript One of the complexities of is how it looks for variables , If the variable is not found in the function execution context , It will look for it in the context of the call , If not found in its invocation context , Just keep going up , Until it finds in the global execution context .( If you don't find it at the end , It is undefined).

1: let val1 = 2
2: function multiplyThis(n) {
     
3:   let ret = n * val1
4:    return ret
5: }
6: let multiplied = multiplyThis(6)
7: console.log('example of scope:', multiplied)

Here are the steps to explain ( If you're familiar , Please skip. ):

  1. Declare a new variable in the global execution context val1, And assign it as 2.
  2. That's ok 2 - 5, Declare a new variable multiplyThis, And assign it a function definition .
  3. Sixth elements , Declare a global execution context multiplied New variable .
  4. Find variables from global execution context memory multiplyThis, And execute it as a function , Transmit number 6 As a parameter .
  • New function call ( Create new execution context ), Create a new multiplyThis Function execution context .
  • stay multiplyThis In execution context , Declare a variable n And assign it as 6 --> After declaration, it will enter the function body and execute
  1. Execute the function back to the 3 That's ok .
  • stay multiplyThis In execution context , Declare a variable ret.
  • Continue to the first 3 That's ok . For two operands n and val1 Multiply . stay multiplyThis Find variables in execution context n.
    • We are in step 6 It is declared in , It's about numbers 6. stay multiplyThis Find variables in execution context val1.
    • multiplyThis No execution context is marked as val1 The variable of . We look up the call context , Call context is global execution context , In the context of global execution seek [val1]. Oh , Yes 、 There, , It is in step. 1 In the definition of , Values are 2.
  • Continue to the first 3 That's ok . Multiplies two operands and assigns them to ret Variable ,6 * 2 = 12,ret The value is now 12.
  1. return ret Variable , The destruction multiplyThis Execution context and its variables ret and n . Variable val1 Not destroyed , Because it's part of the global execution context .
  2. Back to the first 6 That's ok . In the call context , Numbers 12 Assign a value to multiplied The variable of .
  3. Last in the first place 7 That's ok , We print in the console multiplied The value of the variable

In this case , We need to remember that a function can access variables defined in its invocation context , This is Lexical scope (Lexical scope).

Ⅲ- Function of return function [ Higher order function ]

In the first example , function addTwo Return a number . please remember , Function can return anything . Let's look at a function example of a return function , Because this is very important for understanding closures below . Look at the chestnuts :

1: let val = 7
2: function createAdder() {
     
3:   function addNumbers(a, b) {
     
4:     let ret = a + b
5:     return ret
6:   }
7:   return addNumbers
8: }
9: let adder = createAdder()
10: let sum = adder(val, 8)
11: console.log('example of function returning a function: ', sum)

Let's go back to step-by-step decomposition :

  1. first line . We declare a variable in the global execution context val And assignment 7.
  2. That's ok 2 - 8. We declare a global execution context called createAdder The variable of , And a function definition is assigned to it .
  • The internal third 3 to 7 Line describes the above function definition , Same as before , At this point , We didn't talk about this function directly . We just store the function definition in [createAdder] variable .
  1. The first 9 That's ok .
  • We declare a global execution context called adder New variables , temporary , The value is undefined
  • We see brackets (), We need to execute or call a function , Find the memory of the global execution context and find the memory named createAdder The variable of , It's in step 2 Created in the . ok , We call it .
  1. When you call a function , Up to the third day 2 That's ok .
  • Create a new createAdder Execution context . We can do it in createAdder Create own variables in the execution context of .js The engine will be createAdder Add context for to call stack . This function has no arguments , Let us Jump directly to its main part .
  1. The first 3 - 6 That's ok ( Execute into the body function ).
  • We have a new function declaration , We are createAdder Create a variable in the execution context addNumbers. It's important ,addnumber Is only found in createAdder In execution context . We store function definitions in a file named addNumbers Of its own variables .
  • In the 7 That's ok , We return variables addNumbers The content of .js The engine looks for a addNumbers And find it , This is a function definition . well , Function can return anything , Include function definition . We return addNumbers The definition of . The first 4 Xing He 5 The contents between the line brackets constitute the function definition .
  1. [return addNumbers] when ,createAdder Execution context will be destroyed .addNumbers Variable no longer exists . but addNumbers Function definition still exists , Because it returns and assigns a value to adder Variable .
  • It's important here !!! At this time [adder=createAdder()] In fact, its value is [addNumbers] Function definition instead of [createAdder] 了 ,adder Now it's an anonymous function – It's a little winding here , Make sure you understand
  1. The first 10 That's ok . We define a new variable in the context of global execution sum, First assign the value to undefined;
  • Next we need to execute a function . Which function ?
    • It is called adder Functions defined in variables . We look for it in the context of global execution , I found it , This function has two arguments .
    • Let's look up these two parameters , The first is that we are in step 1 Variables defined in val, It represents a number 7, The second is numbers 8.
  • Now we're going to execute this function , Function definitions are outlined in section 3-5 That's ok , Because this function is anonymous , For ease of understanding , Let's call it adder Well . Create a adder Function execution context , stay adder Two new variables are created in the execution context a and b. They are assigned as 7 and 8, Because these are the parameters we passed to the function in the previous step .
  1. Go back to section 4 That's ok .
  • stay adder An execution context is declared with the name ret New variables ,
  • Put the variable a Content and variables for b The content of 15 And give it to ret Variable .
  1. ret Variable returned from this function . This anonymous function execution context is destroyed , Remove from call stack , Variable ab and ret No longer exist .
  2. The return value is assigned to us in step 9 As defined in sum Variable .
  3. We will sum The value of is printed to the console .

As expected , Console will print 15. We do have a lot of difficulties here , I would like to make a few points here . First , Function definitions can be stored in variables , Function definitions are not visible until the program is called . secondly , Every time a function is called , Metropolis ( temporary ) Create a local execution context . When the function is complete , Execution context will disappear . Function encountered return Right bracket } Execution completed at .

What is a higher-order function ?

So called higher order functions , That is, one function can receive another function as a parameter , Or return a function –> Common higher-order functions are map、reduce、filter、sort etc.

var ADD =function add(a) {
     
return function(b) {
     
return a+b
}
}
 call :ADD(2)(3) You can get results 
  1. map

//
map Takes a function as an argument , Don't change the original array , Just return a new array
var arr = [1,2,3,4,5]
var arr1 = arr.map(item => item = 2)
//arr Output [1,2,3,4,5]
//arr1 Output [2,2,2,2,2]


2. reduce

- ```js
//
reduce It also returns a new array .reduce Takes a function as an argument , This function has two formal parameters , The first two items in the array represent ,reduce The result of this function and the third item in the array will form the two formal parameters of this function again, and so on 
var arr = [1,2,3,4,5]
var arr2 = arr.reduce((a,b)=> a+b)
console.log(arr2) // 15
  1. filter

//
filter Return the filtered array .filter Receive as a function parameter , This function will act on each element in the array , Keep the result according to the Boolean value returned after each execution of the function , If it is true Just keep it , If it is false Just filter it out ( With this map Distinguish )
var arr = [1,2,3,4,5]
var arr3 = arr.filter(item => item % 2 == 0)
console.log(arr3)// [2,4]

5、 Closure

A function and its surrounding states (lexical environment, Lexical environment ) The references of the ( Or functions are surrounded by references ), Such a combination is Closure closure). in other words , Closures allow you to access the scope of an outer function in an inner function . stay JavaScript in , Every time you create a function , Closures are created at the same time as functions are created .

Originally, the closure part was to see Silicon Valley Teaching video of , At that time, the teacher's explanation in this part didn't make me feel particularly clear ( I didn't get to the point at the beginning , Make it difficult to understand , But if you mention it later ), So I read a lot of materials about closures for self-study , Then sort them out and integrate them, and record their feelings here

Ⅰ- Introduce the concept of closure

① Wrong scenario

demand : Click a button , Tips " Click on the n Button "

<button> test 1</button>
<button> test 2</button>
<button> test 3</button>
<!--  demand :  Click a button ,  Tips " Click on the n Button " -->
<script type="text/javascript"> var btns = document.getElementsByTagName('button') // Be careful [btns] It's not an array , It's a pseudo array  // Every time to get [btns.length] In fact, they all need to be calculated ( Because it's a pseudo array ) // So for better performance , Assign here , You only need to calculate once  for (var i = 0,length=btns.length; i < length; i++) {
        var btn = btns[i] btn.onclick = function () {
        // Traversal plus listening  alert(' The first '+(i+1)+' individual ') // result   Is full of [4] } } </script>    

The error here is , Use global variables and modify them directly [i], Lead to for At the end of the cycle , All pop-up values bound by clicking the button are [i+1]

Subsequent call time , Will find [i] This variable , But at this time i==3, So all the results are 4

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-2oSF81Kq-1650422408416)(.\JavaScript senior .assets\image-20210727143351376.png)]

② Mount the variable to itself to solve

Solution : take btn The corresponding subscript is saved in btn On

<button> test 1</button>
<button> test 2</button>
<button> test 3</button>
<!--
 demand :  Click a button ,  Tips " Click on the n Button "
-->
<script type="text/javascript">
var btns = document.getElementsByTagName('button')
for (var i = 0,length=btns.length; i < length; i++) {
     
var btn = btns[i]
// take btn The corresponding subscript is saved in btn On 
btn.index = i
btn.onclick = function () {
       // Traversal plus listening 
alert(' The first '+(i+1)+' individual ')     // result   Is full of [4]
}
}
</script>    

Put it on yourself , Get it yourself when you need it , That's how it works

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-nD1eXdjw-1650422408417)(.\JavaScript senior .assets\image-20210727143824641.png)]

③ Use closures

Use closure knowledge points to solve , Lead out the knowledge points below , If you don't understand, you can continue to look down with questions

<body>
<button> test 1</button>
<button> test 2</button>
<button> test 3</button>

<script type="text/javascript">
// Use closures 
for (var i = 0,length=btns.length; i < length; i++) {
     
// Here j It's partial , It will bring in [i] Deposited locally [j] in , In this way, the effect can be achieved  
(function (j) {
     
var btn = btns[j]
btn.onclick = function () {
     
alert(' The first '+(j+1)+' individual ')
}
})(i)
}
</script>  
</body>

20210727143824641

Ⅱ- Take a closure chestnut analysis to understand

According to the above [4] The code illustrates how to analyze the process To try to understand Closure Concept

Give a closure chestnut in advance for analysis , Let's see what happens , Then look at its concept and confirm it , believe me , You'll have the feeling of clearing the fog

① According to normal logic

First say , This part is not understood according to the closure mechanism , So I found something wrong ( There must be something wrong ) Don't drill into a bull's corner , It is mainly used as a rear control

1: function createCounter() {
     
2:   let counter = 0
3:   const myFunction = function() {
     
4:     counter = counter + 1
5:     return counter
6:   }
7:   return myFunction
8: }
9: const increment = createCounter()
10: const c1 = increment()
11: const c2 = increment()
12: const c3 = increment()
13: console.log('example increment', c1, c2, c3)

Now? , We've learned the trick from the previous examples , Let's do it as fast as we expect : ( Wrong process understanding , Deliberately follow the normal logical process , Make confirmation )

  1. That's ok 1 - 8. We create a new variable in the context of global execution createCounter, And assigned a function definition .
  2. The first 9 That's ok .
  • We declare a global execution context called increment New variables .
  • We need to call createCounter Function and assign its return value to the increment Variable .
  1. Return execution That's ok 1 - 8. Call function , Create a new local execution context .
  • The first 2 That's ok . In local execution context , Declare a counter And assign the 0;
  • That's ok 3 - 6. Declare a myFunction New variables , Variable declared in local execution context , The content of the variable is 4 Xing He 5 Line definition .
  • The first 7 That's ok . return myFunction Contents of variables , Delete local execution context . Variable myFunction and counter No longer exist . Control returns to the calling context .
  1. Back again The first 9 That's ok
  • In the call context ( Global execution context ) in ,createCounter The returned value is assigned to increment, Variable increment Now we have a function definition as createCounter Return function .
  • It is no longer marked as myFunction, But its definition is the same . In the global context , It is marked as labeledincrement.
  1. The first 10 That's ok . Declare a new variable (c1).
  • Continue to the first 10 That's ok . lookup increment Variable , It's a function and calls it . It contains the function definition returned previously , As the first 4-5 Line defined .
  • Create a new execution context . No parameters . Start function .
  1. go back to The first 4 That's ok .
  • counter=counter + 1. Find in local execution context counter Variable .
  • We just created that context , Never declare any local variables . Let's look at the global execution context . Not here either counter Variable .
  • Javascript It will be calculated as counter = undefined + 1, Declare a tag as counter New local variable of , And assign it as number 1, because undefined Treated as value 0. --> This is wrong , Don't be a bull , The correct understanding is below , Here is the wrong comparison
  1. The first 5 That's ok . Our variables counter Value (1), We destroy the local execution context and counter Variable .
  2. Back to the first 10 That's ok . Return value (1) Be assigned to c1.
  3. The first 11 That's ok . Repeat step 10-14,c2 Also assigned as 1.
  4. The first 12 That's ok . Repeat step 10-14,c3 Also assigned as 1.
  5. The first 13 That's ok . We print variables c1 c2 and c3 The content of .

Try it yourself , See what happens . You will notice , It's not as documented as I expected from the above explanation 1,1,1. It's a record. 1,2,3. Why is this ?

② Understand correctly

I don't know how ,increment Function remembers that cunter Value . What's going on ?

  1. counter Is it part of the global execution context ?
  • Try console.log(counter), obtain undefined Result , Obviously not .
  1. Maybe , When you call increment when , It will somehow return the function it created (createCounter)?
  • How could it be ? Variable increment Include function definition , Not the source of the function , Obviously not .
  1. So there must be another mechanism . Closure , We finally found it , The missing piece .
  • **- This is how it works , Whenever a new function is declared and assigned to a variable , Both function definitions and closures are stored . Closures contain all variables in the scope at function creation time , It's like a backpack . Function definition with a small backpack , Its package stores all variables in the scope when the function definition is created **

So our explanations are all wrong , Let's try once again , But this time it's right

1: function createCounter() {
     
2:   let counter = 0
3:   const myFunction = function() {
     
4:     counter = counter + 1
5:     return counter
6:   }
7:   return myFunction
8: }
9: const increment = createCounter()
10: const c1 = increment()
11: const c2 = increment()
12: const c3 = increment()
13: console.log('example increment', c1, c2, c3)
  1. ditto , The first 1-8 That's ok . We create a new variable in the context of global execution createCounter, It gets the specified function definition .
  2. ditto , The first 9 That's ok .
  • We declare a global execution context called increment New variables .
  • We need to call createCounter Function and assign its return value to the increment Variable .
  1. ditto , The first 1-8 That's ok . Call function , Create a new local execution context .
  • The first 2 That's ok . In local execution context , Declare a counter And assign the 0 .
  • The first 3-6 That's ok . Declare a myFunction New variables , Variable declared in local execution context , The content of a variable is another function definition . As the first 4 Xing He 5 Line definition , Now we also create a closure , As part of the function definition . Closure contains variables in scope , In this case, the variable counter( The value is 0).
  • The first 7 That's ok . return myFunction Contents of variables , Delete local execution context .myFunction and counter No longer exist . Control is given to the calling context , We return the function definition and its closure , The closure contains the variables in the scope when it was created .
  1. Back to the first 9 That's ok .
  • In the call context ( Global execution context ) in ,createCounter The returned value is specified as increment
  • Variable increment Now we have a function definition ( Closure ), from createCounter Function definition returned , It is no longer marked as myFunction, But its definition is the same , In the global context , be called increment.
  1. The first 10 That's ok . Declare a new variable c1.
  • Continue to the first 10 That's ok . Find variables increment, It's a function , Call it . It contains the function definition returned previously , As the first 4-5 Line defined .( It also has a closure with variables ).
  • Create a new execution context , No parameters , Start function .
  1. The first 4 That's ok .[counter = counter + 1], Finding variables [counter], Before finding local or global execution context , Let's check the closure , look , The closure contains a [counter] The variable of , Its value is 0. In the 4 After row expression , Its value is set to 1. It's stored in a closure again , The closure now contains a value of 1 The variable of [counter].
  2. The first 5 That's ok . We go back to counter Value , Destroy local execution context .
  3. Back to the first 10 That's ok . Return value 1 Assigned to variable c1.
  4. The first 11 That's ok . We repeat the steps 10-14. This time, , In the closure, the variable counter The value of is 1. It is in the first place. 12 Row set , Its value is incremented and 2 The form of is stored in the closure of the increasing function ,c2 To be an assignment 2.
  5. The first 12 That's ok . Repeat step 10-14 That's ok ,c3 To be an assignment 3.
  6. The first 13 That's ok . We print variables c1 c2 and c3 Value .

** You may ask at this point , Does any function have a closure , Even functions created globally ? **

The answer is yes . Functions created in global scope create closures , But because these functions are created in the global scope , So they can access all variables in the global scope , The concept of closure doesn't matter .

But when a function returns a function , The concept of closure becomes even more important . The returned function can access variables that are not part of the global scope , But they only exist in their closures .

  1. How to generate closure ?

    • When a nested interior ( Son ) The function references a nested external ( Father ) Variable of a function ( function ) when , There's a closure
  2. What exactly is a closure ?

    • Use chrome Debug view
    • Understand one : Closures are nested inner functions ( Most people )
    • Understanding two : Contains referenced variables ( function ) The object of ( Very few people )
    • Be careful : Closures exist in nested inner functions
  3. Conditions for generating closures ?

    • Nested function

    • The inner function refers to the data of the outer function ( Variable / function )

function fn1() {
     
    var a = 2
    var b = 'abc'

    function fn2() {
      // Executing the function definition will produce closures ( You don't have to call internal functions )
        console.log(a)
    }

    fn2()
}

fn1()

Ⅲ- Common closures

① Take the function as the return value of another function

// 1.  Take the function as the return value of another function 
function fun1() {
     
var a = 3;

function fun2() {
     
a++;            // Variables that reference external functions ---> Generating closures 
console.log(a);
}

return fun2;
}
var f = fun1();  // because f Referring to internal functions --> Neither internal functions nor closures have become garbage objects 

f();   // Indirectly operate the local variables inside the function 
f();

② Pass a function as an argument to another function call

// 2.  Pass a function as an argument to another function call 
function showDelay(msg, time) {
     
setTimeout(function () {
     
alert(msg)
}, time)
}
showDelay('atguigu', 2000)

③ Higher order functions and coriolisation

Sometimes closures appear when you don't even notice them , You may have seen an example of what we call a partial application

Of course, if you don't understand, you can , You can read the closure knowledge points of this note several times , Or combine with the top Ⅱ- Take a closure chestnut analysis to understand To understand

1、 from ES6 Higher order arrow functions understand function coriolisation ( Apply to closures )
  1. First of all, I saw such an example :
let add = a => b => a + b
  1. The above is a very simple addition function , Turn it into ES5 Let's write it as follows
function add(a) {
     
   return function(b) {
     
       return a + b
   }
}
var add3 = add(3) //add3 Represents a variable that points to a function   It can be used as a function call name 
add3(4) === 3 + 4 //true
  1. Simplify it a little bit , We can write it in the following form :
let add = function(a) {
     
 var param = a;
 var innerFun = function(b) {
     
     return param + b;
 }
 return innerFun;
}
  1. Although it doesn't seem to make any sense , But obviously, the above uses [ Closure ], And the return value of this function is a function . Actually , This is it. The definition of higher order function : A function that takes a function as a parameter or whose return value is a function .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-vFReWimd-1650422408420)(.\JavaScript senior .assets\image-20210415160945789.png)]

2、 currying
  1. legend :

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-BaFGXQhp-1650422408421)(.\JavaScript senior .assets\image-20210415161137977.png)]

  1. The key is Understand corellization , In fact, it can be understood as , After curry , Save the first parameter variable in the function ( Closure ), Then I needed to n A function with two arguments can become one that only needs to be left (n - 1 individual ) Parameters can call , such as
let add = x => y => x + y
let add2 = add(2)
-*----------------------------------
 Originally completed  add  This operation , It should be called like this 
let add = (x, y) => x + y
add(2,3)
----------------------------------
1.  And now  add2  The function only needs one parameter to complete the same operation , This is widely used in functional programming .
let add = x => y => x + y
let add2 = add(2)
2. Explain in detail , Namely  add2  function   Equivalent to   With  x  Of this closure variable  y => x + y  function , And at this point  x = 2, So call 
add2(3) === 2 + 3
4、 summary
  1. If it is a => b => c => {xxx} This multi coriolised , How to understand ?

understand : front n - 1 Secondary call , In fact, the parameter is passed in in advance , Did not call the innermost function body , The innermost function body will not be called until the last call , And return the return value of the innermost function body

  1. As can be seen from the above , Multiple continuous arrows here ( No matter two arrow functions, three or more ) Functions are linked together It's in Corey . So a continuous arrow function is a function of multiple Coriolis es6 How to write it .

  2. Call features :let test = a => b => c => {xxx}

For example, for the above test function , It has 3 An arrow , This function is to be called 3 Time test(a)(b)(c), The first two calls are just passing parameters , Only the last call in turn will return {xxx} The return value of the code segment , And in {xxx} In the code segment, you can call a,b,c

Ⅳ- The function of closures

  1. Use the variables inside the function after the function is executed , Still alive in memory ( Prolongs the life cycle of local variables )
  2. Let the function be manipulated externally ( Reading and writing ) To the data inside the function ( Variable / function )

problem :

1.  After the function is executed ,  Whether the local variables declared inside the function still exist ? 
   -   Generally, it doesn't exist ,  Only variables that exist in closed can exist 
2.  Can you directly access the local variables inside the function outside the function ? 
   -  You can't ,  But we can let the outside operate on it through closures 

Ⅴ- The life cycle of closure

  1. produce : When the nested inner function definition is executed, it produces ( Not calling )
  2. Death : When nested inner functions become garbage objects
  • That is, death when no one points to it , Usually set to [null], Of course, it's OK to point to others , But it's not safe. ( Easily contaminated variables )
// The life cycle of closure 
function fn1() {
     
 // At this point, the closure has been generated ( Function enhancement , actually [fn2] Promoted to the first line ,  The inner function object has been created )
 var a = 2
 function fn2 () {
      // If the time is [let fn2=function(){}], Then closures will occur in this line 
   a++
   console.log(a)
 }
 return fn2
}
var f = fn1()
f() // 3
f() // 4
f = null // Closure death ( Function objects containing closures become garbage objects )

Ⅵ- Application of closures

Application of closures : Definition JS modular

  • Having a specific function js file
  • Encapsulate all data and functions in one function ( Private )
  • Only one packet is exposed n Object or function of a method
  • Users of the module , We only need to call the method through the exposed object of the module to realize the corresponding function
  1. Module definition :
  • //myModule.js
    function myModule() {
           
      // Private data 
      var msg = 'My atguigu'
      // Functions that manipulate data 
      function doSomething() {
           
        console.log('doSomething() '+msg.toUpperCase())
      }
      function doOtherthing () {
           
        console.log('doOtherthing() '+msg.toLowerCase())
      }
    
      // Exposed objects ( Methods for external use )
      return {
           
        doSomething: doSomething,
        doOtherthing: doOtherthing
      }
    }
    
    -----------------------------------------------------------------
    // myModule2.js 
    (function () {
           
      // Private data 
      var msg = 'My atguigu'
      // Functions that manipulate data 
      function doSomething() {
           
        console.log('doSomething() '+msg.toUpperCase())
      }
      function doOtherthing () {
           
        console.log('doOtherthing() '+msg.toLowerCase())
      }
    
      // Exposed objects ( Methods for external use )
      window.myModule2 = {
           
        doSomething: doSomething,
        doOtherthing: doOtherthing
      }
    })()    
    
    
  1. Module call
  • // Invoke the sample 
    ------------   Module call 1 --------------------------------------------
    <script type="text/javascript" src="myModule.js"></script>
    <script type="text/javascript">
      var module = myModule()
      module.doSomething()
      module.doOtherthing()
    </script>
    ------------   Module call 2 --------------------------------------------
    <script type="text/javascript" src="myModule2.js"></script>
    <script type="text/javascript">
      myModule2.doSomething()
      myModule2.doOtherthing()
    </script>
    

Ⅶ- Shortcomings and solutions of closures

  1. shortcoming :
  • After the function is executed , The local variable in the function is not released , It takes longer to use memory

  • Easy to cause memory leaks

  1. solve :
  • No closure, no closure

  • Timely release

function fn1() {
var arr = new Array(100000)
function fn2() {
console.log(arr.length)
}
return fn2
}
var f = fn1()
f()
f = null // Make internal functions garbage objects –> Recycle closures


 I have another solution , Call directly `f()()` Just run the call directly --> Anonymous functions , It will be destroyed automatically 

![\[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-wj4wnfKj-1650422408422)(.\JavaScript senior .assets\image-20210727191229838.png)\]](https://img-blog.csdnimg.cn/7982d6e00322421faac65d74cdee66e4.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ZmI6ZmI5Zyo5Yqq5Yqb5LqG,size_20,color_FFFFFF,t_70,g_se,x_16)

Ⅷ- Memory overflow and memory leak

  1. out of memory
  • An error in the operation of a program

  • When the memory needed to run the program exceeds the remaining memory , Throw a memory overflow error

  1. Memory leak
  • The occupied memory is not released in time

  • Memory leaks accumulate too much, which can easily lead to memory overflow

  • Common memory leaks :

    • Unexpected global variables
      • There are no timers or callbacks to clean up in time
      • Closure
<script type="text/javascript">
// 1.  out of memory 
var obj = {
     }
for (var i = 0; i < 10000; i++) {
     
 obj[i] = new Array(10000000)
 console.log('-----')
}

// 2.  Memory leak 
 //  Unexpected global variables 
function fn() {
     
 a = new Array(10000000)  // Don't use var let const To undertake 
 console.log(a)
}
fn()

//  There are no timers or callbacks to clean up in time 
var intervalId = setInterval(function () {
      // Do not clean after starting the cycle timer 
 console.log('----')
}, 1000)

// clearInterval(intervalId)

 //  Closure 
function fn1() {
     
 var a = 4
 function fn2() {
     
   console.log(++a)
 }
 return fn2
}
var f = fn1()
f()
// f = null

</script>

 Don't use let const var Wait to make a statement , In fact, it is mounted to [] Upper , So it leads to memory leakage [ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-LjCuDbJl-1650422408424)(.\JavaScript senior .assets\image-20210727193110329.png)]

Ⅸ- Relevant interview questions 1

// Code snippet 1  --> No closure is generated : Because the internal function does not call the external variable 
   var name = "The Window";
   var object = {
     
       name: "My Object",
       getNameFunc: function () {
     
           return function () {
     
               return this.name;
           };
       }
   };
   console.log(object.getNameFunc()());  //? the window
// Function body this yes window

// Code snippet 2 
   var name2 = "The Window";
   var object2 = {
     
       name2: "My Object",
       getNameFunc: function () {
     
			// Here this The point is [getNameFunc], It is an attribute in the object , therefore this The point is object
           var that = this;
           return function () {
     
			// Here is a saved  that
               return that.name2;
           };
       }
   };
   console.log(object2.getNameFunc()()); //? my object
  1. Code snippet 1 :

    • Function body this The point is [window]

    • No closure is generated : Because the internal function does not call the external variable

  2. Why does code fragment 2 point to an object ?

    • this The point is to call it [getNameFunc], It is an attribute in the object , therefore this The point is object

    • Closure generated

Ⅹ- Relevant interview questions 2

function fun(n,o) {
     
console.log(o)
return {
     
fun:function(m){
     
return fun(m,n)
}
}
}
var a = fun(0) //undefined
a.fun(1)  //0
a.fun(2)  //0 
a.fun(3)  //0

var b = fun(0).fun(1).fun(2).fun(3) //undefined 0 1 2

var c = fun(0).fun(1) //undefined 0
c.fun(2)//1 --> After the above definition  n Fixed for 1
c.fun(3)//1 --> This is a trap !!!  It hasn't been changed to n, So it's always been 1

copyright notice
author[Chen Chen is trying],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/04/202204290809029044.html

Random recommended