[Step-By-Step] Deep Analysis of High Frequency Interview Questions/Weekly 04

  Front end, html5, javascript, node.js, Programmer

This week’s interview questions list:

  • What is closure? What is the function of closures?
  • Implement Promise.all method
  • What are the ways to load js scripts asynchronously?
  • Please implement a Flattened Deep function to flatten nested arrays
  • What are the characteristics of iterated objects?

More quality articles to stamp on: https://github.com/YvetteLau/ …

15. What is closure? What is the function of closures?

What is closure?

Closures are functions that have access to variables in the scope of another function. The most common way to create closures is to create another function within a function.

Create a closure

function foo() {
    var a = 2;
    return function fn() {
        console.log(a);
    }
}
let func = foo();
func(); //输出2

Closures allow functions to continue to access the lexical scope at the time of definition. Thanks to fn, the scope inside foo will not be destroyed after foo () is executed.

No matter by what means the internal function is passed outside its lexical scope, it will hold a reference to the original definition scope and will use closures wherever it is executed. For example:

function foo() {
    var a = 2;
    function inner() {
        console.log(a);
    }
    outer(inner);
}
function outer(fn){
    fn(); //闭包
}
foo();

The Function of Closure

  1. Can access the lexical scope of the function definition (prevent it from being recycled).
  2. Privatization variable
function base() {
    let x = 10; //私有变量
    return {
        getX: function() {
            return x;
        }
    }
}
let obj = base();
console.log(obj.getX()); //10
  1. Simulate block-level scope
var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = (function(j){
        return function () {
            console.log(j);
        }
    })(i);
}
a[6](); // 6
  1. Create 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'

Module mode 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)
  • Closed functions must return at leastOneInternal functions, so that internal functions can form closures in private scopes and can access or modify private states.

Disadvantages of Closures

Closures cause variables of functions to be kept in memory all the time, and too many closures may cause memory leaks.

16. implement Promise.all method

Before implementing the Promise.all method, we must first know the functions and characteristics of Promise.all, because we can write the implementation further only when the functions and characteristics of Promise.all are clear.

Promise.all function

Promise.all(iterable)Returns a new Promise instance. This instance is found initerableAll within the parameterpromiseAllfulfilledOr the parameter does not containpromise, the state changes tofulfilled; If one of the parameterspromiseThere is one failurerejectedThis instance callback failed because of the first failurepromiseReturns the result of the.

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

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

(1) Only p1, p2 and p3 becomefulfilled, the state of p will becomefulfilledIn this case, the return values of p1, p2 and p3 form an array and are passed to the callback function of p.

(2) As long as one of p1, p2, p3 isrejected, the state of p becomesrejectedThe return value of the first reject instance is passed to the callback function of p.

Features of Promise.all

The return value of Promise.all is a promise instance

  • If the passed-in parameter is an empty iterated object,Promise.allMeetingSynchronizationA that returns a completed statepromise
  • If the parameter passed in does not contain any promise,Promise.allMeetingAsynchronousA that returns a completed statepromise
  • In other cases,Promise.allReturn onePendingState ofpromise.

The status of promise returned by Promise.all

  • If promise in the passed-in parameters all become complete,Promise.allReturnedpromiseBecome completed asynchronously.
  • If one of the parameters passed inpromiseFailure,Promise.allThe result of the failure is asynchronously given to the callback function of the failed state, regardless of the others.promiseIs it complete
  • In any case,Promise.allReturnedpromiseThe result of the completion status of is an array

Promise.all implementation

Consider only the case where the passed-in parameters are arrays

/** 仅考虑 promises 传入的是数组的情况时 */
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++ ) {
                //考虑到 i 可能是 thenable 对象也可能是普通值
                Promise.resolve(promises[i]).then(data => {
                    result[i] = data;
                    if (++index === promises.length) {
                        //所有的 promises 状态都是 fulfilled,promise.all返回的实例才变成 fulfilled 态
                        resolve(result);
                    }
                }, err => {
                    reject(err);
                    return;
                });
            }
        }
    });
}

The code on MDN can be used for testing

Consider the iterable object

Promise.all = function (promises) {
    /** promises 是一个可迭代对象,省略对参数类型的判断 */
    return new Promise((resolve, reject) => {
        if (promises.length === 0) {
            //如果传入的参数是空的可迭代对象
            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; //保证顺序
                        index++;
                        if (index === j) {
                            //此时的j是length.
                            resolve(result);
                        }
                    }, err => {
                        //某个promise失败
                        reject(err);
                        return;
                    });
                })(j)
                j++; //length
            }
        }
    });
}

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(() => {
    console.log(p2)
}, 200);

17. What are the ways to load js scripts asynchronously?

<script>Added to labelasync(html5) ordefer(html4) attribute, the script will be loaded asynchronously.

<script src="../XXX.js" defer></script>

deferAndasyncThe difference lies in:

  • deferWhen the normal rendering of the whole page in memory is finished (DOM structure is fully generated and other scripts are executed), it is executed before window.onload;
  • asyncOnce the download is complete, the rendering engine will stop rendering and continue rendering after executing this script.
  • If there are multipledeferScripts are loaded in the order in which they appear on the page
  • MultipleasyncScripts cannot guarantee the loading order

Dynamic creationscriptLabel

Dynamically createdscript, settingssrcThe JS file will not start downloading until it is added to the document.

let script = document.createElement('script');
script.src = 'XXX.js';
// 添加到html文件中才会开始下载
document.body.append(script);

XHR asynchronous loading 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);
    }
}

18. Please implement a Flattened Deep function to flatten nested arrays

Using Array.prototype.flat

ES6 added to array instancesflatMethod, used to “flatten” nested arrays into one-dimensional arrays. This method returns a new array and has no effect on the original array.

flatThe default is to “flatten” only one layer. If you want to “flatten” multi-layer nested arrays, you need to giveflatPass 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));

When the passed integer is greater than the number of nested layers of the array, the array will be flattened into a one-dimensional array, and the maximum number JS can represent isMath.pow(2, 53) - 1So we can define it this wayflattenDeepFunction

function flattenDeep(arr) {
    //当然,大多时候我们并不会有这么多层级的嵌套
    return arr.flat(Math.pow(2,53) - 1); 
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));

Leveraging 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]]));

Using stack to Infinitely Anti-nest Multi-level Nested Arrays

function flattenDeep(input) {
    const stack = [...input];
    const res = [];
    while (stack.length) {
        // 使用 pop 从 stack 中取出并移除值
        const next = stack.pop();
        if (Array.isArray(next)) {
            // 使用 push 送回内层数组中的元素,不会改动原始输入 original input
            stack.push(...next);
        } else {
            res.push(next);
        }
    }
    // 使用 reverse 恢复原数组的顺序
    return res.reverse();
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));

19. What are the characteristics of iterated objects

ES6 stipulates that the defaultIteratorThe interface is deployed in the of the data structureSymbol.iteratorAttribute, in other words, a data structure can be considered as long as it hasSymbol.iteratorProperties (Symbol.iteratorThe method corresponds to a traverser generation function and returns a traverser object), then it can be considered iterated.

Characteristics of Iterative Objects

  • HaveSymbol.iteratorAttributes,Symbol.iterator()Returns a traverser object
  • Can be usedfor ... ofCycle through
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 }

Native toIteratorThe data structure of the interface:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • Arguments object for function
  • NodeList object

Customize an Iterative Object

As we said above, an object only has the correctSymbol.iteratorProperty, then it is iterated, so we can addSymbol.iteratorMake it iterative.

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表达式仅能使用在 Generator 函数中
        }
    }
};

for (var key of obj) {
    console.log(key); //Yvette 18 engineer
}

Reference articles:

[1]MDN Promise.all

[2]Promise

[3]Iterator

Thank you for your friends’ willingness to spend precious time reading this article. If this article gives you some help or inspiration, please don’t be stingy with your praise and Star. Your affirmation is my greatest motivation to move forward.https://github.com/YvetteLau/ …

Recommend to pay attention to my public number:

clipboard.png