This week’s interview questions:

  • What is a closure? What does a closure do?
  • Implement the promise.all method
  • What are the methods for loading JS scripts asynchronously?
  • Implement a flattening deep function that flattens a nested array
  • What are the characteristics of an iterable?

What is a closure? What does a closure do?

What is a closure?

A closure is a function that has access to variables in the scope of another function, and the most common way to create a closure is to create another function inside a function.

Create a closure

function foo() {
    var a = 2;
    return function fn() {
        console.log(a); }}let func = foo();
func(); 2 / / output
Copy the code

Closures allow functions to continue to access the lexical scope at definition time. Thanks to fn, foo’s inner scope is not destroyed after foo() is executed.

No matter how an inner function is passed outside its lexical scope, it holds a reference to the original definition scope and uses closures wherever the function is executed. Such as:

function foo() {
    var a = 2;
    function inner() {
        console.log(a);
    }
    outer(inner);
}
function outer(fn){
    fn(); / / closures
}
foo();
Copy the code

The role of closures

  1. The ability to access the lexical scope in which a function is defined (preventing it from being recycled).

  2. Privatization variable

function base() {
    let x = 10; // Private variables
    return {
        getX: function() {
            returnx; }}}let obj = base();
console.log(obj.getX()); / / 10
Copy the code
  1. Simulate block-level scopes
var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = (function(j){
        return function () {
            console.log(j);
        }
    })(i);
}
a[6] ();/ / 6
Copy the code
  1. Create a module
function coolModule() {
    let name = 'Yvette';
    let age = 20;
    function sayName() {
        console.log(name);
    }
    function sayAge() {
        console.log(age);
    }
    return {
        sayName,
        sayAge
    }
}
let info = coolModule();
info.sayName(); //'Yvette'
Copy the code

The module pattern has two prerequisites (from JavaScript you Don’t Know)

  • There must be an external enclosing function that must be called at least once (each call creates a new module instance)
  • Enclosing functions must return at least one inner function so that the inner function can form a closure in the private scope and can access or modify the private state.

Disadvantages of closures

Closures cause the variables of a function to remain in memory, and too many closures can cause memory leaks

16. Implement the promise.all method

Before implementing the promise.all method, we must first know the function and characteristics of promise.all, because in clear Promise. All function and characteristics of the case, we can further write implementation.

Promise. All functions

Promise.all(iterable) returns a new Promise instance. This example will be a big pity if all promises in the iterable parameter are fulfilled or if no promise is included in the parameter, the state will become a big pity. If the promise parameter has a failed promise, the instance callback fails because of the return result of the first failed promise.

let p = Promise.all([p1, p2, p3]);
Copy the code

The state of P is determined by P1, P2 and P3, which can be divided into the following: There are two cases:

(1) Only when the states of P1, P2 and P3 become depressing, the state of P will become depressing. At this time, the return values of P1, P2 and P3 will form an array and be passed to the callback function of P.

(2) As long as p1, P2 and P3 are rejected, P becomes rejected, and the return value of the first rejected instance is passed to p’s callback function.

The characteristics of the Promise. All

Promise.all returns an instance of Promise

  • If the argument passed is an empty iterable,Promise.allsynchronousReturns a completed statepromise
  • If the parameters passed in do not contain any promises,Promise.allasynchronousReturns a completed statepromise
  • In other cases,Promise.allReturns aPendingThe state of thepromise.

Promise.all Indicates the state of the returned Promise

  • If all the promises in the parameters passed in become completed,Promise.allThe returnedpromiseAsynchronously become complete.
  • If one of the parameters passed in ispromiseFailure,Promise.allAsynchronously give the failed result to the failed state callback, regardless of the restpromiseWhether or not complete
  • In any case,Promise.allThe returnedpromiseThe result of the completion state is an array

Promise. All implementations

Consider only the case where the argument passed is an array

/** Only consider promises to pass in arrays */
Promise.all = function (promises) {
    return new Promise((resolve, reject) = > {
        if (promises.length === 0) {
            resolve([]);
        } else {
            let result = [];
            let index = 0;
            for (let i = 0;  i < promises.length; i++ ) {
                // Consider that I may be a thenable object or a normal value
                Promise.resolve(promises[i]).then(data= > {
                    result[i] = data;
                    if (++index === promises.length) {
                        // This is a big pity. // All promises will become a big pity
                        resolve(result);
                    }
                }, err => {
                    reject(err);
                    return; }); }}}); }Copy the code

You can use the code on the MDN for testing

Consider iterable objects

Promise.all = function (promises) {
    /** Promises is an iterable, omit argument types */
    return new Promise((resolve, reject) = > {
        if (promises.length === 0) {
            // If the argument passed is an empty iterable
            return resolve([]);
        } else {
            let result = [];
            let index = 0;
            let j = 0;
            for (let value of promises) {
                (function (i) {
                    Promise.resolve(value).then(data= > {
                        result[i] = data; // Ensure the order
                        index++;
                        if (index === j) {
                            // where j is length.
                            resolve(result);
                        }
                    }, err => {
                        // A promise fails
                        reject(err);
                        return;
                    });
                })(j)
                j++; //length}}}); }Copy the code

Test code:

let p2 = Promise.all({
    a: 1[Symbol.iterator]() {
        let index = 0;
        return {
            next() {
                index++;
                if (index == 1) {
                    return {
                        value: new Promise((resolve, reject) = > {
                            setTimeout(resolve, 100.'foo');
                        }), done: false}}else if (index == 2) {
                    return {
                        value: new Promise((resolve, reject) = > {
                            resolve(222);
                        }), done: false}}else if(index === 3) {
                    return {
                        value: 3.done: false}}else {
                    return { done: true}}}}}}); setTimeout((a)= > {
    console.log(p2)
}, 200);
Copy the code

17. What are the methods for loading JS scripts asynchronously?

<script>Add to the tagasync(it) ordefer(html4) property, the script will load asynchronously.

<script src=".. /XXX.js" defer></script>
Copy the code

The difference between defer and Async is that:

  • deferWait until the entire page is properly rendered in memory (DOM structure is fully generated, and other scripts are executed), before window.onload;
  • asyncOnce the download is complete, the rendering engine interrupts the rendering, executes the script, and continues rendering.
  • If there are more than onedeferScripts are loaded in the order they appear on the page
  • multipleasyncThe script does not guarantee the load order

Dynamically createscriptThe label

A dynamically created script with SRC set will not be downloaded, but will be added to the document before the JS file is downloaded.

let script = document.createElement('script');
script.src = 'XXX.js';
// Add it to the HTML file to start the download
document.body.append(script);
Copy the code

XHR asynchronously loads JS

let xhr = new XMLHttpRequest();
xhr.open("get"."js/xxx.js".true);
xhr.send();
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        eval(xhr.responseText); }}Copy the code

18. Implement a flattening deep function that flattens a nested array

Using the Array. The prototype. Flat

ES6 added the flat method for array instances, which “flattens” nested arrays into one-dimensional arrays. This method returns a new array with no effect on the original array.

Flat flattens only one layer by default. If you want to “flatten” a nested array of multiple layers, you need to pass flat an integer indicating the number of layers you want to flatten.

function flattenDeep(arr, deepLength) {
    return arr.flat(deepLength);
}
console.log(flattenDeep([1[2[3[4]], 5]], 3));
Copy the code

When the integer passed is greater than the number of nested layers of the array, the array is flattened into a one-dimensional array. The maximum number that JS can represent is math.pow (2, 53) -1, so we can define a flattening deep function like this

function flattenDeep(arr) {
    // Of course, most of the time we don't have this many levels of nesting
    return arr.flat(Math.pow(2.53) - 1); 
}
console.log(flattenDeep([1[2[3[4]], 5]]));
Copy the code

Utilize reduce and concat

function flattenDeep(arr){
    return arr.reduce((acc, val) = > Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
console.log(flattenDeep([1[2[3[4]], 5]]));
Copy the code

Use Stack to unnest multiple layers of nested arrays indefinitely

function flattenDeep(input) {
    const stack = [...input];
    const res = [];
    while (stack.length) {
        // Use pop to fetch and remove values from the stack
        const next = stack.pop();
        if (Array.isArray(next)) {
            // Use push to send back elements in the inner array without changing the original inputstack.push(... next); }else{ res.push(next); }}// Use reverse to restore the order of the original array
    return res.reverse();
}
console.log(flattenDeep([1[2[3[4]], 5]]));
Copy the code

19. What are the characteristics of iterable

ES6 specifies that the default Iterator interface is deployed in the symbol. Iterator property of the data structure. Iterator a data structure is considered iterable as long as it has the symbol. iterator property (the Symbol. Iterator method corresponds to the iterator generator and returns an iterator object).

Characteristics of an iterable

  • withSymbol.iteratorProperties,Symbol.iterator()Returns an traverser object
  • You can usefor ... ofcycle
let arry = [1.2.3.4];
let iter = arry[Symbol.iterator]();
console.log(iter.next()); //{ value: 1, done: false }
console.log(iter.next()); //{ value: 2, done: false }
console.log(iter.next()); //{ value: 3, done: false }
Copy the code

The native hasIteratorInterface data structure:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • The arguments object for the function
  • The NodeList object

Define an iterable

An object is iterable only if it has the correct symbol. iterator property. Therefore, we can make the object iterable by adding symbol. iterator.

let obj = {
    name: "Yvette".age: 18.job: 'engineer', * [Symbol.iterator]() {
        const self = this;
        const keys = Object.keys(self);
        for (let index = 0; index < keys.length; index++) {
            yield self[keys[index]];Yield expressions can only be used in Generator functions}}};for (var key of obj) {
    console.log(key); //Yvette 18 engineer
}
Copy the code

Reference article:

[1] MDN Promise.all

[2] Promise

[3] Iterator

Thank you for your precious time to read this article. If this article gives you some help or inspiration, please do not spare your praise and Star. Your praise is definitely the biggest motivation for me to move forward. Github.com/YvetteLau/B…

Pay attention to the public number, join the technical exchange group