Regular study notes, including ES6, Promise, Node.js, Webpack, HTTP Principles, Vue buckets, and possibly more Typescript, Vue3, and common interview questions.

Higher-order functions

Higher order functions

  • The argument to a function is a function (a callback is a higher-order function).
  • A function returns a function

We usually use reduce, map and other methods are higher-order functions.

Before method

Suppose we have a scenario where we have written a business code, and now we need to extend the current business code.

function say() {
  // todo something...
  console.log("say");
}
Copy the code

We need to deal with business code before it does, but if we deal with the encapsulation of business code, the whole code becomes difficult to deal with and reuse.

So we need to bind a before method to the function. prototype prototype chain so that the business code calls this method before it is called. Realize the unified management of the extension code.

Function.prototype.before = function (callback) {
  return () = > {
    callback();
    this(a);// The arrow function looks for the this pointer in its parent scope
  };
};
Copy the code

(Note: we need to use the arrow function here because the arrow function does not point to this, it will look up the parent scopeThis points to the)

This way we can call the callback function of the business code directly before using it.

let beforeSay = say.before(function () {
  console.log("before say");
});
beforeSay(); // before say say
Copy the code

This is a higher-order function because it satisfies both of the characteristics of higher-order functions.

The result is a separation of the business code from the extension code.

At the same time, we can also pass parameters.

function say(a, b) {
  // todo something...
  console.log("say", a, b);
}
Function.prototype.before = function (callback) {
  return (. args) = > {
    // Arrow functions don't have arguments attributes, so we use residual operators for argument passing
    callback();
    this(... args); }; };let beforeSay = say.before(function () {
  console.log("before say");
});
beforeSay("hello"."world"); // before say say
Copy the code

After methods

Suppose we now have a string of code where we need to determine when to execute the function based on the arguments passed.

let newFn = after(3.function () {
  console.log("after");
});
newFn(); // ...
newFn(); // ...
newFn(); // after
Copy the code

Above we passed in a 3 and passed in a custom function. On the third time, we execute our custom function.

Next we complete the after function.

function after(times, callback) {
  return function () {
    // Customize the content
    if (--times === 0) { callback(); }}; }Copy the code

It also uses the idea of closure to complete the function encapsulation.

The above code also conforms to the characteristics of higher-order functions, so this is also a higher-order function.

Function chemistry

First, we can look at a requirement case like this.

Suppose we now need to sum a few numbers, which we might normally encapsulate with the following function.

function sum(a, b, c, d, e) {
  return a + b + c + d + e;
}
sum(1.2.3.4.5);
Copy the code

What if we passed the parameters separately?

sum(1.2) (3) (4.5);
Copy the code

At this point, we can no longer use the function above.

We need to use a new higher order function, function keratology.

const curring = (fn, arr = []) = > {
  let len = fn.length;
  return function (. args) {
    let concatVal = [...arr, ...args];
    if (arr.length < len) {
      return curring(fn, arr);
    } else {
      return fn(...concatVal);
    }
  };
};
console.log(curring(sum)(1.2) (3) (4.5)); / / 15
Copy the code

In fact, the whole idea is to splice all the subsequent parameters into a complete set of parameters, and finally realize the function.

Asynchronous concurrency problem

Suppose we now have multiple asynchronous concurrent requests, how do we get the end result at the same time?

Here we will use the FS module in Node.

let fs = require("fs"); // file System
Copy the code

This is a module for manipulating files.

We can then create two.txt files in their subdirectories and write whatever we want to test them.

Then we’ll use readFile to manipulate the file directly.

fs.readFile("./name.txt"."utf8".function (err, data) {
  console.log(data); // zhangsan
});
fs.readFile("./test.txt"."utf8".function (err, data) {
  console.log(data); // test
});
Copy the code

Thus we simulate two asynchronous operations.

Now we want to put these two results directly into a variable.

let allVal = {};
fs.readFile("./name.txt"."utf8".function (err, data) {
  allVal.name = data;
});
fs.readFile("./test.txt"."utf8".function (err, data) {
  allVal.test = data;
});
console.log(allVal); / / {}
Copy the code

We can see that the output is empty because the two reads are asynchronous.

So how do we get this result?

We have several solutions as follows

  1. To simulate acbMethod and create a count variableindex, after each execution of an asynchronous methodindexAnd add 1 to it.
let index = 0;
const cb = () = > {
  if (++index === 2) {
    console.log(allVal); }}; fs.readFile("./name.txt"."utf8".function (err, data) {
  allVal.name = data;
  cb();
});
fs.readFile("./test.txt"."utf8".function (err, data) {
  allVal.test = data;
  cb();
});
Copy the code

The problem with writing this way is that it becomes very difficult when we need to call too many asynchronous methods, and we need to create an extra global variable.

  1. Use the idea of the after method above

    function after(times, callback) {
      return function () {
        if (--times === 0) { callback(); }}; }let cb = after(2.function () {
      console.log(allVal);
    });
    Copy the code

    Use the closure idea to store callback functions in heap memory. Output results until triggered.

Now that we’re done with the asynchronous concurrency problem, the best option is to use closures, the second option above.

Two design patterns

Publish and subscribe model

First of all, the publish subscribe pattern is split into two parts, on and EMIT, and we also include a storage attribute, ARR.

  • On is to maintain some of the functions you need in an array
  • Emit is the execution of the functions in the array
  • Arr is used to store functions
let event = {
  arr: [].// as a storage property
  on(fn) {
    this.arr.push(fn);
  },
  emit() {
    this.arr.forEach((fn) = >fn()); }};Copy the code

Thus, we can use this design pattern for asynchronous operations.

Let’s use the asynchronous operation example above.

let fs = require("fs"); // file System
let allVal = {};
fs.readFile("./name.txt"."utf8".function (err, data) {
  allVal.name = data;
});
fs.readFile("./test.txt"."utf8".function (err, data) {
  allVal.test = data;
});
console.log(allVal);
Copy the code

Now let’s do an asynchronous storage operation and output the desired results in turn.

// bind the output function to on so that we can observe the result
event.on(function () {
  console.log("Read one");
});
event.on(function () {
  // Output result after all the user-defined asynchronous operations are executed
  if (Object.keys(allVal).length === 2) {
    console.log(allVal); }});// Bind emit under each asynchronous function
fs.readFile("./name.txt"."utf8".function (err, data) {
  allVal.name = data;
  event.emit();
});
fs.readFile("./test.txt"."utf8".function (err, data) {
  allVal.test = data;
  event.emit();
});
{name: 'zhangsan', test: 'test'}
Copy the code

We can use the development thought of this design mode to complete the development of a variety of requirements.

Observer model

First, since this design pattern is called the observer pattern, there must be one observer and one observed. The observer needs to be placed in the observed, and the observer will be notified when the state of the observed changes. (Note: Vue’s bidirectional binding is implemented using observer mode)

It is also internally implemented on a publish-subscribe basis, so the observer model and the publish-subscribe model are usually understood together.

We can further understand this design pattern by simulating an example of the state relationship between a pet and its owner.

// Observer mode
class Subject {
  // Observed
  constructor(name) {
    this.name = name;
    this.observers = [];
    this.state = "Happy";
  }
  attach(o) {
    this.observers.push(o);
  }
  setState(newState) {
    this.state = newState;
    this.observers.forEach((fn) = > fn.update(this)); }}class Observer {
  / / observer
  constructor(name) {
    this.name = name;
  }
  update(pets) {
    console.log(this.name + "Got it." + pets.name + "The mood is very good."+ pets.state); }}let cat = new Subject("Flower");
let master1 = new Observer("White");
let master2 = new Observer("White");
cat.attach(master1);
cat.attach(master2);
cat.setState("Sad");
// Baymax is very sad to know huahua
// Small white know flower flower mood very sad
Copy the code

This article was created by Mo Xiaoshang. If there are any problems or omissions in the article, welcome your correction and communication. You can also follow my personal site, blog park and nuggets, AND I will upload the article to these platforms after it is produced. Thank you for your support!