Function knowledge involved

  • Be familiar with multiple definitions and calls of functions.
  • Be able to understand and change the orientation of this inside functions.
  • Understand the characteristics of strict patterns.
  • You can skillfully pass functions as arguments and return values.
  • Understand what closures do.
  • Be able to name two conditions for recursion.
  • Understand the difference between deep copy and shallow copy.

Function definition and call

1.1 Definition of functions

Function keyword (named function)

Function fn1() {console.log('hello javascript')} fn1(Copy the code

2. Function expression (anonymous function)

Let fn2 = function(){console.log('hello javascript')} fn2(Copy the code

3. Use new Function() to define functions

Note: The above two abbreviations are recommended because they are inefficient and the code is not easy to view. All functions are instances of Function (or objects).
// use new Function(' parameter ',' parameter 2', 'Function body ') let fn3 = new Function('a','b','console.log(a + b)') fn3('hello ', 'javascript') // Output: Hello javascriptCopy the code

The conclusion is that javascript functions are also objects, and we can draw a diagram of them using the previous constructor, object instance, and prototype object.

1.2 How to call functions

1. Ordinary functions

Function fn(){console.log('hello')} fn(){hello.call ()Copy the code

2. Object methods

Class Fun{fn(){console.log('hello')}} let obj = new Fun() obj.fn() Function (){console.log('hello')}} fun2.fn (Copy the code

constructor

Function Fun3(){this.fn = function(){console.log('hello')}} Fun3 = new Fun3() fun3.fn(Copy the code

4. Bind event functions

<button id=" BTN "> call fn</button> javascript const BTN = document.querySelector('# BTN ') // click Btn.onclick = function(){console.log('hello')}Copy the code

5. Timer function

setInterval(function () {
    console.log('hello')
}, 1000)
Copy the code

6. Execute the function immediately

(function (){console.log('hello')})()Copy the code

2.this

2.1 Reference to this in functions

2.2 Change the this pointer inside the function

The bind () method

let o = { name: 'Andy'} function fn(a, b){console.log(a + b) console.log(this)} let f = fn.bind(o,1,2) f() result 3 object oCopy the code
  • Bind () doesn’t change the original function.
  • Bind () does not call the function.
  • Bind () returns a function that changes the new copy to which this points.
  • Bind () can pass values
  • There are many cases where we don’t need to call a function immediately (timers, for example), but want to change the this pointer inside the function.

Example: We have a button, and when I click it, I look at the disable button, and then turn it on after 3 seconds.

Let BTN = document.querySelector('# BTN ') btn.onclick = fn function fn() {this.disabled = true  setTimeout(() => { // this.disabled = false // console.log(this) // }, SetTimeout (function () {this.disabled = false}. Bind (this), 3000) console.log(' call ')}Copy the code

Call () method

Function Father(uname) {this.name = uname} Father. Prototype = {sing(){console.log(' sing ')}} Father.prototype.constructor = Father function Son(uname) { Father.call(this, Function (){console.log(this) console.log()}} Son. Prototype = new Father() Son. The prototype. The constructor = Son let LDH = new Son (' Andy lau) console. The log (LDH) name) LDH. SonSing (LDH), sing ()Copy the code

When the parent constructor is called, refer this in the parent constructor to the child constructor, so that the constructor can use the attributes of the parent constructor.

The apply () method

let o = { name: 'Andy'} function fn(arr){console.log(this)} fn() // prints window fn.apply() // prints window fn.apply(o) // prints o objects // The pass argument must be an array (pseudo-array) fn.apply(o, ['Hello']) // Prints HelloCopy the code
  • You can call functions.
  • You can change this to point to the problem inside the function.
  • But its arguments must be arrays (pseudo-arrays)
  • The array arguments passed by apply() print out a string.

Example: Maximize and minimize values with the help of built-in objects in Math using apply().

let numArr = [10, 5, 100, 200]
let max = Math.max.apply(Math, numArr)
let min = Math.min.apply(Math, numArr)
console.log(max, min);
Copy the code

conclusion

Similarities:

  • You can change the this pointer inside the function.

The mark:

  • Call and Apply both call functions and change the function’s this reference.
  • Call does not pass the same parameters as apply. Call passes aru1, aru2… Apply must be an array.
  • Bind will not be called directly; you can change the this reference inside the function.

Application Scenarios:

  • Call often does inheritance.
  • Apply is often associated with arrays, such as getting maximum and minimum values based on the Math object implementation.
  • Bind does not call a function, but needs to change the this pointer inside the function, such as the this pointer inside a timer.

3. Strict mode

3.1 What is strict mode

  • JS provides strict mode after ES5.
  • IE10 and later versions are supported. Older browsers are ignored.
  • Eliminates some of the irrationality and rigor in Javascript, and reduces some of the quirks.
  • Improve compiler efficiency and speed.
  • Disabled some syntax that might be defined in future versions of ECMAScript, paving the way for future versions of Javascript. For example, reserved words such as class, enum, export, extends, import, and super cannot be used as variable names.

Grammar:

use strict
Copy the code

Add strict mode to the script:

<script> 'use strict' // The following code will execute in strict mode </script>Copy the code

Add strict mode for immediately executing functions:

<script> (function(){'use strict' // the following code will be executed in strict mode})() </script>Copy the code

To add a strict mode to a function:

<script> function fn(){'use strict'} function fn2(){Copy the code

3.2 Changes in strict mode

1. Provisions of variables
  • In normal mode, if a variable is assigned without being declared, the default is global. In strict mode, this is refined. Variables must be declared with var or let or const before being used.

Print successfully without declaring:

  num = 10
  console.log(num)  // 10
Copy the code

In strict mode (must be declared before use):

'use strict'
num = 10
console.log(num)  // num is not defined
Copy the code

Do not delete variables in strict mode

 'use strict'
  let num = 10
  delete num
  console.log(num)  // Delete of an unqualified identifier in strict
  
Copy the code
2. In strict mode, this refers to the problem
  • Previously in the global scope this referred to the window object.

    function fn() {
        console.log(this)
    }
    fn() //Window
      
    Copy the code
  • Point to undefined in strict mode.

    'use strict'
    function fn() {
        console.log(this)
    }
    fn() //undefined
    Copy the code
  • Previously, constructors could be called without new, as in normal functions, this refers to the global.

    Function Star(uname, age) {this.name = uname this.age = age} Star(' Andy Lau ', 33) console.log(window.name) // Andy Lau console.log(window.age) // 33Copy the code

Using constructors in strict mode:

Function Star(uname, age){this.name = uanme this.age = age} let LDH = new Star(' dev ', 33) console.log(ldh.name) // Andy Lau console.log(ldh.age) // 33Copy the code
  • The timer this points to the window, and that doesn’t change.
  • The events and objects are still pointing to the caller, that hasn’t changed.
2. Function changes in strict mode
  • Strict schemas can have two parameters that are the same and can be parsed.

    Function fn(a, a) {console.log(a + a)} fn(1, 2) // First call the function 1 to a and then 2 to a, so that the duplicate is overwritten // so that the result is 4Copy the code
  • Duplicate parameters in strict mode will cause an error.

    'use strict'
    function fn(a, a) {
        console.log(a + a)
    }
    fn(1, 1) //Duplicate parameter name not allowed in this context
    Copy the code
  • Functions must be declared at the top level, and new versions of Javascript introduce “block-level scope” (introduced in ES6). To keep up with the new version. Not allowed in the function function declared in a block of code (roughly meaning is not allowed to declare variables in {}, for example, if statement, for statement with {}, and of course the function () {} here is allowed (function in the nested function is allowed)).

  • Octal is not allowed in strict mode.

4. Higher-order functions

Higher-order functions are not very advanced functions. They can be called higher-order functions as long as the following two conditions are met:

  • It can take functions as arguments.
  • It can output a function as a return finger.

Example: taking a function as an argument (typically using a callback function)

Function fn(data, callback) {console.log(data) callback && callback(); } fn1('javascript', function () { console.log('hello') })Copy the code

JQuery higher-order functions

<button id=" BTN "> </button> <script> // $(' # BTN) on (' click ', function () {the console. The log (' clicked ')}) < / script >Copy the code

For example, using a function as a return value

Function fn() {function fnChild() {console.log('hello')} return fnChild()} fn() //helloCopy the code

5. The closure

5.1 Variable scope

Variables can be divided into two types depending on their scope: global variables and local variables.

  • Is a global variable outside a function.
  • Inside the function are local variables.
  • Global variables can also be used in functions.
  • Local variables are not available outside the function.
  • However, local variables in the scope are also destroyed after the function completes execution.

5.2 What is a Closure

A closure is a function that has access to a variable in the scope of another function.

Simply put, a scope can access local variables inside an exception function

Closure examples:

function fn() {
    var num = 10

    function fn1() {
        console.log(num)
    }
    fn1()
}
fn()
Copy the code

Closures can be understood as a phenomenon

  • I print the variables declared by FN in the scope of fn1, that is, variables belonging to different scopes, and then fn generates closure phenomena (the function of the accessed variable is a closure function).

5.3 The role of closures

Local variables can be used in a global scope, extending the scope of a variable.

Example:

function fn(){
    let num = 11

    function fn1(){
        console.log(num)
    }

    return fn1
}
let f = fn()
f()
Copy the code

F = function fn1(){console.log(num)}, f = function fn1(){console.log(num)}, f = function fn1(){console.log(num)} Note that fn1 is a nested function of FN and all fn1 has access to fn’s num variable, so it prints normally.

A function that returns a function is also a higher-order function. A closure is a typical higher-order function.

function fn(){
    let num = 190
    return function (){
        let num2 =10
        console.log(num + num2)
    }
}
let fns = fn()
fns()
Copy the code

Closure example: Click li to print the current LI index

  • HTML (this will also be used in future examples)

    Apple < ul > < li > < / li > < li > watermelon < / li > < li > peach < / li > < li > cantaloupe < / li > < / ul >Copy the code
  • Make use of dynamically adding attributes

    let lis = document.querySelector('ul').querySelectorAll('li')
    for (var i = 0; i < lis.length; i++){
      lis[i].index = i
      lis[i].onclick = function (){
      console.log(this.index)
      }
    }
    Copy the code
  • Use closure to get the current li index

The bound anonymous function here uses the value of the immediately executing function, so executing the function immediately creates a closure phenomenon.

let lis = document.querySelector('ul').querySelectorAll('li')
for (var i = 0; i < lis.length; i++){
    (function (ii){
        lis[ii].onclick = function (){
            console.log(ii)
        }
    })(i)
}
Copy the code

Timer example: print li after 3 seconds

let lis = document.querySelector('ul').querySelectorAll('li')
for (var i = 0; i < lis.length; i++){
    setTimeout(function (i){
        console.log(lis[i].innerText) //undefined
    },3000)
}
Copy the code

The reason for undefined is mainly because timers are asynchronous tasks, while for loops are synchronous applications. Even if the timer event delay is 0, the timer task will be put into the task queue during the execution of the FOR loop and will not be executed immediately.

  • The correct way to write it (again using a closure, passing the value changed by var as an argument to the closure function) :

      let lis = document.querySelector('ul').querySelectorAll('li')
    for (var i = 0; i < lis.length; i++){
        (function (i){
            setTimeout(function (){
                console.log(i)
                console.log(lis[i])
                console.log(lis[i].innerText)
            },3000)
        })(i)
    }
    Copy the code

Closure summary:

  • A closure is a function.
  • Closures extend the scope of variables.

6. Recursion

6.1 What is recursion

A function is recursive if it can call itself internally. Simple to understand: the inside of a function calls itself, this function is recursive function. Recursive functions are somewhat similar to loops.

Recursion is prone to stack overflow errors, so an exit conditional return must be added.

Typical examples of dead recursion:

function fn(){
    fn()
}
fn()
Copy the code

Examples of correct recursion:

Let num = 1 function fn(){console.log() if(num == 6){num++ fn()} fn()Copy the code

Results:

Note that the recursion must include an exit condition return, otherwise it will become dead recursion.

6.2 Solving Mathematical problems by recursion:

  1. 1 * 2 * 3… Times n factorial.

     function fn(n){
         if(n == 1){
             return  1
         }
         return n * fn(n - 1)
     }
     console.log(fn(3));
    Copy the code

Recursion does not start to return until the return exit condition is triggered, otherwise it continues, creating new stacks to create functions.

  1. Fibonacci sequence (rabbit sequence) 1, 1, 2, 3, 5, 8, 13, 21… , the user can input a number N to figure out the corresponding rabbit sequence value.

// (Fibonacci sequence) we just need to know that the NTH term entered by the user is the sum of the previous two terms, and then return the value of the user’s input.

function fb(n){ if(n == 1 || n == 2){ return 1 } return fb( n-1 ) + fb(n - 2) } console.log(fb(6)); // Print the result 8.Copy the code

6.4 Traverse data by recursion

Example: The user enters an ID to query the corresponding element

Let data = [{id: 1, name: 'home appliance, goods: [{id: 11, name:' fridge, goods: [{id: 111, name: 'haier refrigerators'}, {id: 111, name: }, {id: 12, name: 'washing machine'}]}, {id:2, name: 'clothes'}] // We want to do the input id number to return the data object. Function getId(json, id){// Declare an object to store let o = {}; json.forEach(function (item, Index,arr){if(item.id == id){// Save found data to assignment to oo = item}else if(item.goods && item.goods.length > 0){// iterate through goods // It must be assigned again, because the recursive function finally returns an O, simple description (here is the recursion once it is at layer 2, your final output is at layer 0, wait for it to return to layer 1, O = getId(item.goods,id)}}) return o} console.log(getId(data, 1).name); console.log(getId(data, 12).name); console.log(getId(data, 111).name);Copy the code

6.5 Shallow Copy and Deep Copy

6.5.1 shallow copy

Shallow copy copies only one layer, and deeper object level copies only reference addresses.

Example: the for… In traversal copy (shallow copy)

let obj = { id: 1, name: 'andy', msg: { age: 18 } } let o = {}; / / use the for... For (let key in obj){// O [key] = obj[key]} obj.name = 'my' obj.msg.age = '20' Console. log(' I am layer 1: ',obj.name) console.log(' I am layer 2: ',obj.msg.age) console.log(' I am layer 1: ', O.name) console.log(' I am layer 2: ',obj.msg. ',o.msg.age)Copy the code

As you can see from the result, the shallow copy can only copy the attributes and values of the objects in the first layer, not the objects in the second layercopyBut rather quote (prove: Because when we try to modify the name attribute of the original object for the first time, the name attribute of the copied object does not change, because they are independent. However, when we modify the value of the age attribute under the MSG of the second layer, the age value under the MSG of the copied object will be affected. Because they are copied is referenced address).

There is a new syntax sugar in ES6 that allows shallow copying directly

// (target object copied) // (... Source Copied Object) object.assign (target,... sources)Copy the code

Example: Shallow copy (using ES6 syntactic sugar)

let obj = { id: 1, name: 'andy', msg: { age: 18 } } let o = {}; // (target object copied) // (... Source copied Object) object. assign(O, obj) console.log(o) // result {id: 1, name: "Andy ", MSG: {... }}Copy the code
Tactical fix packs for 6.5.2 deep copy

Deep copy copies multiple layers of data at each level.

Example: Using function recursion to implement deep copy

let obj = { id: 1, name: 'andy', msg: { age: 18 }, color: ['pink','red'] } let o = {}; function deepCopy (new_obj, Old_obj){for (let key in old_obj){let item = old_obj[key]; New_obj [key] = [] new_obj[key] = [] Then we can continue to copy deepCopy(new_obj[key], item) }else if(item instanceof Object){ new_obj[key] = {} deepCopy(new_obj[key], Item)}else{new_obj[key] = item} deepCopy(o, obj) console.log(o)Copy the code

Note: it is important to judge arrays before objects, because arrays in js are also objects

let arr = [1, 2, 3]
console.log(arr instanceof Object) //true
Copy the code

It can be seen that using the method of deep copy, then change the value of the original copy object property, the second layer of the copy object property is still the value of the copy.