成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Step-By-Step】高頻面試題深入解析 / 周刊04

youkede / 3352人閱讀

摘要:關(guān)于點擊進入項目是我于開始的一個項目,每個工作日發(fā)布一道面試題。的狀態(tài)由決定,分成以下兩種情況只有的狀態(tài)都變成,的狀態(tài)才會變成,此時的返回值組成一個數(shù)組,傳遞給的回調(diào)函數(shù)。

關(guān)于【Step-By-Step】
Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發(fā)布一道面試題。

每個周末我會仔細閱讀大家的答案,整理最一份較優(yōu)答案出來,因本人水平有限,有誤的地方,大家及時指正。

如果想 加群 學(xué)習(xí),可以通過文末的公眾號,添加我為好友。

更多優(yōu)質(zhì)文章可戳: https://github.com/YvetteLau/...

__

本周面試題一覽:

什么是閉包?閉包的作用是什么?

實現(xiàn) Promise.all 方法

異步加載 js 腳本的方法有哪些?

請實現(xiàn)一個 flattenDeep 函數(shù),把嵌套的數(shù)組扁平化

可迭代對象有什么特點?

15. 什么是閉包?閉包的作用是什么? 什么是閉包?

閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包最常用的方式就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)。

創(chuàng)建一個閉包
function foo() {
    var a = 2;
    return function fn() {
        console.log(a);
    }
}
let func = foo();
func(); //輸出2

閉包使得函數(shù)可以繼續(xù)訪問定義時的詞法作用域。拜 fn 所賜,在 foo() 執(zhí)行后,foo 內(nèi)部作用域不會被銷毀。

無論通過何種手段將內(nèi)部函數(shù)傳遞到所在的詞法作用域之外,它都會持有對原始定義作用域的引用,無論在何處執(zhí)行這個函數(shù)都會使用閉包。如:

function foo() {
    var a = 2;
    function inner() {
        console.log(a);
    }
    outer(inner);
}
function outer(fn){
    fn(); //閉包
}
foo();
閉包的作用

能夠訪問函數(shù)定義時所在的詞法作用域(阻止其被回收)。

私有化變量

function base() {
    let x = 10; //私有變量
    return {
        getX: function() {
            return x;
        }
    }
}
let obj = base();
console.log(obj.getX()); //10

模擬塊級作用域

var a = [];
for (var i = 0; i < 10; i++) {
    a[i] = (function(j){
        return function () {
            console.log(j);
        }
    })(i);
}
a[6](); // 6

創(chuàng)建模塊

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"

模塊模式具有兩個必備的條件(來自《你不知道的JavaScript》)

必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的模塊實例)

封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。

閉包的缺點

閉包會導(dǎo)致函數(shù)的變量一直保存在內(nèi)存中,過多的閉包可能會導(dǎo)致內(nèi)存泄漏

16. 實現(xiàn) Promise.all 方法

在實現(xiàn) Promise.all 方法之前,我們首先要知道 Promise.all 的功能和特點,因為在清楚了 Promise.all 功能和特點的情況下,我們才能進一步去寫實現(xiàn)。

Promise.all 功能

Promise.all(iterable) 返回一個新的 Promise 實例。此實例在 iterable 參數(shù)內(nèi)所有的 promisefulfilled 或者參數(shù)中不包含 promise 時,狀態(tài)變成 fulfilled;如果參數(shù)中 promise 有一個失敗rejected,此實例回調(diào)失敗,失敗原因的是第一個失敗 promise 的返回結(jié)果。

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

p的狀態(tài)由 p1,p2,p3決定,分成以下;兩種情況:

(1)只有p1、p2、p3的狀態(tài)都變成 fulfilled,p的狀態(tài)才會變成 fulfilled,此時p1、p2、p3的返回值組成一個數(shù)組,傳遞給p的回調(diào)函數(shù)。

(2)只要p1、p2、p3之中有一個被 rejected,p的狀態(tài)就變成 rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調(diào)函數(shù)。

Promise.all 的特點
Promise.all 的返回值是一個 promise 實例

如果傳入的參數(shù)為空的可迭代對象,Promise.all同步 返回一個已完成狀態(tài)的 promise

如果傳入的參數(shù)中不包含任何 promise,Promise.all異步 返回一個已完成狀態(tài)的 promise

其它情況下,Promise.all 返回一個 處理中(pending) 狀態(tài)的 promise.

Promise.all 返回的 promise 的狀態(tài)

如果傳入的參數(shù)中的 promise 都變成完成狀態(tài),Promise.all 返回的 promise 異步地變?yōu)橥瓿伞?/p>

如果傳入的參數(shù)中,有一個 promise 失敗,Promise.all 異步地將失敗的那個結(jié)果給失敗狀態(tài)的回調(diào)函數(shù),而不管其它 promise 是否完成

在任何情況下,Promise.all 返回的 promise 的完成狀態(tài)的結(jié)果都是一個數(shù)組

Promise.all 實現(xiàn)
僅考慮傳入的參數(shù)是數(shù)組的情況
/** 僅考慮 promises 傳入的是數(shù)組的情況時 */
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 狀態(tài)都是 fulfilled,promise.all返回的實例才變成 fulfilled 態(tài)
                        resolve(result);
                    }
                }, err => {
                    reject(err);
                    return;
                });
            }
        }
    });
}

可使用 MDN 上的代碼進行測試

考慮 iterable 對象
Promise.all = function (promises) {
    /** promises 是一個可迭代對象,省略對參數(shù)類型的判斷 */
    return new Promise((resolve, reject) => {
        if (promises.length === 0) {
            //如果傳入的參數(shù)是空的可迭代對象
            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
            }
        }
    });
}

測試代碼:

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. 異步加載 js 腳本的方法有哪些?

deferasync 的區(qū)別在于:

defer 要等到整個頁面在內(nèi)存中正常渲染結(jié)束(DOM 結(jié)構(gòu)完全生成,以及其他腳本執(zhí)行完成),在window.onload 之前執(zhí)行;

async 一旦下載完,渲染引擎就會中斷渲染,執(zhí)行這個腳本以后,再繼續(xù)渲染。

如果有多個 defer 腳本,會按照它們在頁面出現(xiàn)的順序加載

多個 async 腳本不能保證加載順序

動態(tài)創(chuàng)建 script 標簽

動態(tài)創(chuàng)建的 script ,設(shè)置 src 并不會開始下載,而是要添加到文檔中,JS文件才會開始下載。

let script = document.createElement("script");
script.src = "XXX.js";
// 添加到html文件中才會開始下載
document.body.append(script);
XHR 異步加載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. 請實現(xiàn)一個 flattenDeep 函數(shù),把嵌套的數(shù)組扁平化 利用 Array.prototype.flat

ES6 為數(shù)組實例新增了 flat 方法,用于將嵌套的數(shù)組“拉平”,變成一維的數(shù)組。該方法返回一個新數(shù)組,對原數(shù)組沒有影響。

flat 默認只會 “拉平” 一層,如果想要 “拉平” 多層的嵌套數(shù)組,需要給 flat 傳遞一個整數(shù),表示想要拉平的層數(shù)。

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

當傳遞的整數(shù)大于數(shù)組嵌套的層數(shù)時,會將數(shù)組拉平為一維數(shù)組,JS能表示的最大數(shù)字為 Math.pow(2, 53) - 1,因此我們可以這樣定義 flattenDeep 函數(shù)

function flattenDeep(arr) {
    //當然,大多時候我們并不會有這么多層級的嵌套
    return arr.flat(Math.pow(2,53) - 1); 
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));
利用 reduce 和 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]]));
使用 stack 無限反嵌套多層嵌套數(shù)組
function flattenDeep(input) {
    const stack = [...input];
    const res = [];
    while (stack.length) {
        // 使用 pop 從 stack 中取出并移除值
        const next = stack.pop();
        if (Array.isArray(next)) {
            // 使用 push 送回內(nèi)層數(shù)組中的元素,不會改動原始輸入 original input
            stack.push(...next);
        } else {
            res.push(next);
        }
    }
    // 使用 reverse 恢復(fù)原數(shù)組的順序
    return res.reverse();
}
console.log(flattenDeep([1, [2, [3, [4]], 5]]));
19. 可迭代對象有什么特點

ES6 規(guī)定,默認的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的 Symbol.iterator 屬性,換個角度,也可以認為,一個數(shù)據(jù)結(jié)構(gòu)只要具有 Symbol.iterator 屬性(Symbol.iterator 方法對應(yīng)的是遍歷器生成函數(shù),返回的是一個遍歷器對象),那么就可以其認為是可迭代的。

可迭代對象的特點

具有 Symbol.iterator 屬性,Symbol.iterator() 返回的是一個遍歷器對象

可以使用 for ... of 進行循環(huán)

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 }
原生具有 Iterator 接口的數(shù)據(jù)結(jié)構(gòu):

Array

Map

Set

String

TypedArray

函數(shù)的 arguments 對象

NodeList 對象

自定義一個可迭代對象

上面我們說,一個對象只有具有正確的 Symbol.iterator 屬性,那么其就是可迭代的,因此,我們可以通過給對象新增 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表達式僅能使用在 Generator 函數(shù)中
        }
    }
};

for (var key of obj) {
    console.log(key); //Yvette 18 engineer
}
參考文章:

[1] MDN Promise.all

[2] Promise

[3] Iterator

謝謝各位小伙伴愿意花費寶貴的時間閱讀本文,如果本文給了您一點幫助或者是啟發(fā),請不要吝嗇你的贊和Star,您的肯定是我前進的最大動力。 https://github.com/YvetteLau/...

關(guān)注公眾號,加入技術(shù)交流群。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104782.html

相關(guān)文章

  • Step-By-Step高頻面試深入解析 / 周刊05

    摘要:關(guān)于點擊進入項目是我于開始的一個項目,每個工作日發(fā)布一道面試題。那個率先改變的實例的返回值,就傳遞給的回調(diào)函數(shù)。通過插入標簽的方式來實現(xiàn)跨域,參數(shù)只能通過傳入,僅能支持請求。因此清除浮動,只需要觸發(fā)一個即可。 關(guān)于【Step-By-Step】 Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發(fā)布一道面試題。每個周末我會仔細閱讀大家的...

    xiangchaobin 評論0 收藏0
  • Step-By-Step高頻面試深入解析 / 周刊06

    摘要:實例擁有構(gòu)造函數(shù)屬性,該屬性返回創(chuàng)建實例對象的構(gòu)造函數(shù)。在考慮對象而不是自定義類型和構(gòu)造函數(shù)的情況下,寄生式繼承也是一種有用的模式。在子類的構(gòu)造函數(shù)中,只有調(diào)用之后,才能使用關(guān)鍵字,否則報錯。 不積跬步無以至千里。 關(guān)于【Step-By-Step】 Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發(fā)布一道面試題。每個周末我會仔細閱讀...

    LiuRhoRamen 評論0 收藏0

發(fā)表評論

0條評論

youkede

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<