preface

If your understanding of functions is somewhat vague, let’s eliminate it now

define

Anonymous functions

function (){
  return 1
}
Copy the code

Function statements require a Function name Function statements require a Function name

// It is an anonymous function but it has a name
let fn = function (){
  return 1
}
Copy the code

Fn records the address of the function in the stack. Fn records the address of the function in the stack

let fn2 = fn 
Copy the code

So fn and fn2 refer to that function, so the following print is fn, the name of the anonymous function which by default is the same as the name of your variable

A named function

A function with a name

// The name fn3 is a variable whose scope is that fn3 can be accessed anywhere
function fn3(){
  return 3
}

/ / for
**function fn4(){}** function fn4(){}**
let fn5 = function fn4(){}

// console.log(fn4) Beyond this section you cannot access Fn4
Copy the code

Arrow function

// There is only one argument
const$=s= > document.querySelector(s) 
$('div')

// Two parameters
let fn6 = (x, y) = > x+y

// If there are more than one sentence, use curly braces to enlarge them and make clear the value of return
let fn7 = (x, y) = > {
  console.log(1)
  return x+y  // There is no need to write return when there is only one sentence
}
Copy the code

Lexical scope (static scope)

 var global1 = 1
 function fn1(param1){
     var local1 = 'local1'
     var local2 = 'local2')
     function fn2(param2){
             var local2 = 'inner local2'  Row 6, this is local2
         console.log(local1)
         console.log(local2)
     }

     function fn3(){
         var local2 = 'fn3 local2'
         fn2(local2)
     }
 }
Copy the code

Code analysis aboveWhen we print local1 in fn2, it prints local1 as determined by the lexical tree

There’s no local1 in fn2, so I’m going to look for it in fn1, so I’m going to find local1

A lexical tree analysis shows that local2 is local2 in my sixth line above, and has nothing to do with executing the sequence

Note ⚠️ : the lexical tree is only used to analyze whether the printed variable local2 is the same variable local2 inside the scope. It has nothing to do with values, but semantics. Whether their values are equal is not my concern

The interview questions

var a = 1
function b(){
  console.log(a)  // Is this a outside of my A? Certainly by lexical tree analysis, but does the value of a in any case print out as 1?
}
Copy the code

Suppose I change it to the following code

var a = 1
function b(){
  console.log(a)
}
a = 2
b()  // Print out 2
Copy the code

Lexical scope, which determines the relationship between two variables, does not care about their values

Read the following article for more details

  • Javascript lexical scope
  • Static and dynamic scopes
  • Abstract Syntax Tree Introduction to Abstract Syntax Tree

Call Stack

The nested calls

recursive

The above two examples, last in, first out, completely show the execution timing of the function call stack

  • JS engine before calling a function
  • You need to push the function’s environment into an array
  • This array is called the call stack
  • When the function is done, it pops out the environment
  • Then return to the previous environment and continue with the subsequent code

this & arguments

This & arguments, for each function except the arrow function, arguments is a pseudo-array containing all arguments

  1. This is the first argument to be hidden and must be an object
  function f(){
      console.log(this)
      console.log(arguments)}// If you pass null or undefined, the default is to print window (in strict mode default is undefined).
  f.call() // window
  f.call({name:'hone'}) // {name: 'hone'}, []
  f.call({name:'hone'},1) // {name: 'hone'}, [1]
  f.call({name:'hone'},1.2) / / {name: 'hone'}, [1, 2]
Copy the code
  • This article explains why the first parameter is a hidden parameter
  • Why must it be an object

When I write f.call(10, 1), it’s the same thing as the new Number(10).

So why is that? Because this is the connection between the function and the object

If there is no this

let persion = {
  name: 'hone'.'sayHi':sayHi
}
let sayHI = function (){
  console.log('Hello, my name is.' + person.name)
}
Copy the code

Analysis of the

  • If Persion is renamed, the sayHi function is invalid
  • The sayHi function might even be in another file
  • It has strong coupling, so we don’t want persion references in sayHi
class Persion {
  constructor (name) {this.name = name  // This is mandatory for new
  }
  sayHi(){
    console.log('????? ')}}Copy the code

Analysis of the

  • There is only the class and no object has been created, so it is impossible to get a reference to the object
  • How do I get the name of the object? You need a way to get it, using parameters

The following are hypothetical objects

let persion = {
  name: 'hone'.sayHi: function(persion){
      console.log('Hi, I am ' + persion.name)
  }
}
persion.sayHi(persion)
Copy the code

class

class Persion{
  constructor(name){
    this.name = name
  }
  sayHi(p){
    console.log('Hello, my name is.'+ p.name)
  }
}
Copy the code

Python takes this approach

This is used to solve the problem of not passing a value. I also know what the current object is passing. That thing, no. That’s Window

// The following two are equivalent
persion.sayHi()
person.sayHi.call(person)  // Make it easy to tell the code reader what this is
Copy the code

aplay

let array = [1.2.3.4.5]
function sum(){
  let n = 0
  for(let i = 0; n < arguments.length; i++){
    n += arguments[i]
  }
}

// Arguments cannot be written if they are not sure how many arguments are used
// Hence the invention of apply
sum.apply(undefined, array)
Copy the code

Call and apply are almost exactly the same. You use apply when you are unsure of the number of arguments, or even if you know the length

bind

Introduction to bind

Call and apply call the function directly, while bind returns a new function (instead of calling the original function) that calls the original function with parameters specified by you

simulation

Var view = {element: ${'#div'), bindEvents: Function (){view.bindevevts (){function(){view.bindevevts (); This.element.onclick = function(){this.onclick () // how is this function called? OnClick: function(){}}Copy the code

When this element is clicked, this function should be called, it should be called by the browser, and the browser calls call. What is the first parameter of the browser call? Look at the document

The documentation tells me that the first argument to my call is the element that triggers the event

So the browser is callingfunction(){ this.onClick() }And it will call, and the first argument that call gives us is the element that was clicked on, which is the pseudocode div above,this.onClick()What if this is div? I can’t get this

// pseudo-code 2 // with this?? var view = { element: ${'#div'), var _this = this bindEvents: function(){ this.element.onclick = function(){ _this.onClick() // _this.onClick.call(_this) } }, onClick: Function (){}} var view = {element: ${'#div'), bindEvents: function(){ this.element.onclick = function(){ view.onClick() } }, onClick: function(){ } }Copy the code

The forgery of this is not recommended, so there is another way

Var view = {element: ${'#div'), bindEvents: Function (){this.element.onclick = this.onclick ().bind(this)}, onclick: function(){ this.element.addClass('active') } }Copy the code

You want to use onClick but you have to write a new function to call the onClick in the new function

Function (){this.onclick.call(this)} function(){this.onclick.call(this)}Copy the code

Bind’s job is to add a call to onClick when you call the new bind function

// bind this.onclick. bind = function(x, y, {this. OnClick return function(){oldFn. Call (x, y, z); }} this.element.onclick = this.onclick ().bind(this)Copy the code

When the user clicks on the div, the browser calls function(){oldFn. Call (x, y, z)}, which calls the previous function this.onClick followed by a call, whose argument is this

I saw a little dizzy = =, here I recommend a JavaScript in-depth bind implementation of Hu Yu

The following code is from Hu Yu's blog, the link is given at the top
var foo = {
    value: 1
}

function bar() {
    console.log(this.value);
}

// Returns a new function called bar.bind(foo) named bindFoo
var bindFoo = bar.bind(foo)   // bar.bind(foo)()

// The new function calls the old function
bindFoo() // 1 is equivalent to bar.call(foo), which I specify
Copy the code

Use.bind to keep this unchanged

function f1(p1, p2){
  console.log(this,p1,p2)
}
let f2 = f1.bind({name: 'hone'})
// f2 is the function that binds this to f1
f2() Call ({name: 'hone'})
Copy the code

.bind can also bind other parameters

let f3 = f1.bind({name: 'hone'}, 'hi')
f3() Call ({name: 'hone'}, 'hi')
Copy the code

The function is currified

What is corrification

Functions of x and y

G = f(x=1)(y) =1 + 2yCopy the code

G is called a Partial function of z. G is just a part of z

Corrification: to fix one of the parameters of a function, get a new function, reduce the number of functions, output a new function

🌰 example

// Before currization
function sum(x, y){
  return x+y
}

// After currization
function addOne(y){
  return sum(1, y) 
}

addOne(4) / / 5

function addTwo(){
  return sum(2, y)   
}

addTwo(4) / / 6
Copy the code

So addOne is to fix the x of sum to 1 and then add the rest

Currization can be used to do lazy evaluation, where when you call my first function, I don’t really do anything, and when I call my last function, I do it

Recommend the article

  1. www.yinwang.org/blog-cn/201…
  2. zhuanlan.zhihu.com/p/31271179

Higher-order functions

know

In mathematics and computer science, a higher-order function is one that satisfies at least one of the following conditions:

  1. Accepts one or more functions as input:forEach sort map filter reduce
  2. Output a function:lodash.curry
  3. But it can also satisfy both conditions:Function.prototype.bind

Function: can be arbitrary combination of functions

🌰 example

let sum = 0
let arr = [1.2.3.4.5.6]
for(let i = 0; i < arr.length; i++){
  if(arr[i] % 2= = =0){
    sum += array[i]
  }
}

// The above code can be written as
arr.filter(n= > n % 2= = =0)
   .reduce((sum, item) = > {return sum +item}, 0)

let arr1 = [1.4.6.2.3.8.7.9.5]
arr1.filter( n= > n % 2= = =1)
    .sort((a, b) = > {return a-b},0)
Copy the code

Callback and constructor

The callback

Noun form: A function taken as an argument is a callback

Verb form: To invoke this callback

Callbacks and asynchrony have nothing to do with it

The figure shows a synchronous callback

SetTimeout (fn,1000) This is an asynchronous callback

The constructor

The function that returns an object is a constructor, usually capitalized

Arrow function

👉 🏻 link