国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

8道經(jīng)典JavaScript面試題解析,你真的掌握J(rèn)avaScript了嗎?

taowen / 744人閱讀

摘要:瀏覽器的主要組成包括有調(diào)用堆棧,事件循環(huán),任務(wù)隊(duì)列和。好了,現(xiàn)在有了前面這些知識,我們可以看一下這道題的講解過程實(shí)現(xiàn)步驟調(diào)用會(huì)將函數(shù)放入調(diào)用堆棧。由于調(diào)用堆棧是空的,事件循環(huán)將選擇回調(diào)并將其推入調(diào)用堆棧進(jìn)行處理。進(jìn)程再次重復(fù),堆棧不會(huì)溢出。

JavaScript是前端開發(fā)中非常重要的一門語言,瀏覽器是他主要運(yùn)行的地方。JavaScript是一個(gè)非常有意思的語言,但是他有很多一些概念,大家經(jīng)常都會(huì)忽略。比如說,原型,閉包,原型鏈,事件循環(huán)等等這些概念,很多JS開發(fā)人員都研究不多。

所以今天,就來和大家看看下面幾個(gè)問題,大家可以先思考一下,嘗試作答。

八道面試題

問題1:下面這段代碼,瀏覽器控制臺(tái)上會(huì)打印什么?

問題2:如果我們使用 let 或 const 代替 var,輸出是否相同

問題3:“newArray”中有哪些元素?

問題4:如果我們在瀏覽器控制臺(tái)中運(yùn)行"foo"函數(shù),是否會(huì)導(dǎo)致堆棧溢出錯(cuò)誤?


問題5: 如果在控制臺(tái)中運(yùn)行以下函數(shù),頁面(選項(xiàng)卡) 是否會(huì)有響應(yīng)

問題6: 我們能否以某種方式為下面的語句使用展開運(yùn)算而不導(dǎo)致類型錯(cuò)誤

問題7:運(yùn)行以下代碼片段時(shí),控制臺(tái)上會(huì)打印什么?

問題8:xGetter() 會(huì)打印什么值?

答案

前面的問題我們都舉例出來了,接下來我們會(huì)從頭到尾,一個(gè)個(gè)來分析我們這些問題的答案,給大家一些學(xué)習(xí)的思路

問題1:
使用var關(guān)鍵字聲明的變量在JavaScript中會(huì)被提升,并在內(nèi)存中開辟空間,由于沒有賦值,無法定義數(shù)值類型,所以分配默認(rèn)值undefined。var聲明的變量,真正的數(shù)值初始化,是發(fā)生在你確定賦值的位置。同時(shí),我們要知道,var聲明的變量是函數(shù)作用域的,也就是我們需要區(qū)分局部變量和全局變量,而let和const是塊作用域的。所以我們這道題的運(yùn)行過程是這樣的:

var a = 10; // 全局作用域,全局變量。a=10
function foo() {
// var a 
//的聲明將被提升到到函數(shù)的頂部。
// 比如:var a

console.log(a); // 打印 undefined

// 實(shí)際初始化值20只發(fā)生在這里
   var a = 20; // local scope
}

圖解在下面,好理解一點(diǎn)

所以問題1的答案是:undefined

問題 2:
let和const聲明可以讓變量在其作用域上受限于它所在的塊、語句或表達(dá)式中。和var不同的地方在于,這兩個(gè)聲明的變量,不會(huì)被提升。并且我們會(huì)有一個(gè)稱為暫時(shí)死區(qū)(TDZ)。如果訪問TDZ中的變量的話,就會(huì)報(bào)ReferenceError,因?yàn)樗麄兊牡淖饔糜蚴窃谒麄兟暶鞯奈恢玫模粫?huì)有提升。所以必須在執(zhí)行到聲明的位置才能訪問。

var a = 10; // 全局使用域
function foo() { // TDZ 開始

// 創(chuàng)建了未初始化的"a"
    console.log(a); // ReferenceError

// TDZ結(jié)束,"a"僅在此處初始化,值為20
    let a = 20;
}

圖解:

問題2答案:ReferenceError: a is not defined

問題3:

這個(gè)問題,是循環(huán)結(jié)構(gòu)會(huì)給大家?guī)硪环N塊級作用域的誤區(qū),在for的循環(huán)的頭部使用var聲明的變量,就是單個(gè)聲明的變量綁定(單個(gè)存儲(chǔ)空間)。在循環(huán)過程中,這個(gè)var聲明的i變量是會(huì)隨循環(huán)變化的。但是在循環(huán)中執(zhí)行的數(shù)組push方法,最后實(shí)際上是push了i最終循環(huán)結(jié)束的3這個(gè)值。所以最后push進(jìn)去的全都是3。

// 誤解作用域:認(rèn)為存在塊級作用域
var array = [];
for (var i = 0; i < 3; i++) {
    // 三個(gè)箭頭函數(shù)體中的每個(gè)"i"都指向相同的綁定,
    // 這就是為什么它們在循環(huán)結(jié)束時(shí)返回相同的值"3"。
    array.push(() => i);
}
var newArray = array.map(el => el());
console.log(newArray); // [3, 3, 3]

圖解:

如果想記錄每一次循環(huán)的值下來,可以使用let聲明一個(gè)具有塊級作用域的變量,這樣為每個(gè)循環(huán)迭代創(chuàng)建一個(gè)新的綁定。

// 使用ES6塊級作用域
var array = [];
for (let i = 0; i < 3; i++) {
    // 這一次,每個(gè)"i"指的是一個(gè)新的的綁定,并保留當(dāng)前的值。
    // 因此,每個(gè)箭頭函數(shù)返回一個(gè)不同的值。
    array.push(() => i);
}
var newArray = array.map(el => el());
console.log(newArray); // [0, 1, 2]

還有解決這個(gè)問題的另外一種解決方案就是使用閉包就好了。

let array = [];
for (var i = 0; i < 3; i++) {
    array[i] = (function(x) {
     return function() {
           return x;
          };
    })(i);
}
const newArray = array.map(el => el());
console.log(newArray); // [0, 1, 2]  

問題3答案:3,3,3

問題4
JavaScript的并發(fā)模式基于我們常說的”事件循環(huán)“。
瀏覽器是提供運(yùn)行時(shí)環(huán)境來給我們執(zhí)行JS代碼的。瀏覽器的主要組成包括有調(diào)用堆棧,事件循環(huán),任務(wù)隊(duì)列和WEB API。像什么常用的定時(shí)器setTimeout,setInterval這些全局函數(shù)就不是JavaScript的一部分,而是WEB API給我們提供的。

JS調(diào)用棧是后進(jìn)先出(LIFO)的。引擎每次從堆棧中取出一個(gè)函數(shù),然后從上到下依次運(yùn)行代碼。每當(dāng)它遇到一些異步代碼,如setTimeout,它就把它交給Web API(箭頭1)。因此,每當(dāng)事件被觸發(fā)時(shí),callback 都會(huì)被發(fā)送到任務(wù)隊(duì)列(箭頭2)。
事件循環(huán)(Event loop)不斷地監(jiān)視任務(wù)隊(duì)列(Task Queue),并按它們排隊(duì)的順序一次處理一個(gè)回調(diào)。每當(dāng)調(diào)用堆棧(call stack)為空時(shí),Event loop獲取回調(diào)并將其放入堆棧(stack )(箭頭3)中進(jìn)行處理。請記住,如果調(diào)用堆棧不是空的,則事件循環(huán)不會(huì)將任何回調(diào)推入堆棧。

好了,現(xiàn)在有了前面這些知識,我們可以看一下這道題的講解過程:
實(shí)現(xiàn)步驟:

調(diào)用 foo()會(huì)將foo函數(shù)放入調(diào)用堆棧(call stack)。

在處理內(nèi)部代碼時(shí),JS引擎遇到setTimeout。

然后將foo回調(diào)函數(shù)傳遞給WebAPIs(箭頭1)并從函數(shù)返回,調(diào)用堆棧再次為空

計(jì)時(shí)器被設(shè)置為0,因此foo將被發(fā)送到任務(wù)隊(duì)列(箭頭2)。

由于調(diào)用堆棧是空的,事件循環(huán)將選擇foo回調(diào)并將其推入調(diào)用堆棧進(jìn)行處理。

進(jìn)程再次重復(fù),堆棧不會(huì)溢出。

問題4答案:堆棧不會(huì)溢出。

問題5:
在很多時(shí)候,很多做前端開發(fā)的同學(xué)都是認(rèn)為循環(huán)事件圖中就只會(huì)有一個(gè)任務(wù)列表。但事實(shí)上不是這樣的,我們是可以有多個(gè)任務(wù)列表的。由瀏覽器選擇其中一個(gè)隊(duì)列并在該隊(duì)列進(jìn)行處理回調(diào)。
從底層來看,JavaScript中是可以有宏認(rèn)為和微任務(wù)的,比如說setTimeout回調(diào)是宏任務(wù),而Promise回調(diào)是微任務(wù)。

他們有什么區(qū)別呢?
主要的區(qū)別在于他們的執(zhí)行方式。宏任務(wù)在單個(gè)循環(huán)周期中一次一個(gè)低堆入堆棧,但是微任務(wù)隊(duì)列總是在執(zhí)行后返回到事件之前清空。所以,如果你以處理?xiàng)l目的速度向這個(gè)隊(duì)列添加條目,那么你就永遠(yuǎn)在處理微任務(wù)。只有當(dāng)微任務(wù)隊(duì)列為空時(shí),事件循環(huán)才會(huì)重新渲染頁面。

然后我們再回到我們前面講的問題5中:

function foo() {
  return Promise.resolve().then(foo);
};    

我們這段代碼,每次我們?nèi)フ{(diào)用【foo】的時(shí)候,都會(huì)在微任務(wù)隊(duì)列上加另一個(gè)【foo】的回調(diào),因此事件循環(huán)沒辦法繼續(xù)去處理其他的事件了(比如說滾動(dòng),點(diǎn)擊事件等等),直到該隊(duì)列完全清空位置。因此,不會(huì)執(zhí)行渲染,會(huì)被阻止。

問題5答案:不會(huì)響應(yīng)。

問題6:
在我們做面試題的時(shí)候,展開語法和for-of語句去遍歷iterable對象定義要遍歷的數(shù)據(jù)。其中我們要使用迭代器的時(shí)候,Array和Map都是有默認(rèn)迭代操作的內(nèi)置迭代器的。
但是,對象是不可迭代的,也就是我們這道題里的,這是一個(gè)對象的集合。但是我們可以使用iterable和iterator協(xié)議來把它變成可以迭代的。
在我們研究對象的時(shí)候,如果一個(gè)對象他實(shí)現(xiàn)了@@iterator方法,那么它就是可以迭代的。這意味著這個(gè)對象(在他的原型鏈上的一個(gè)對象)必須是又@@iterator鍵的屬性的,然后我們就可以利用這個(gè)鍵,通過常量Symbol.iterator獲得。
下面是這道題的舉例寫法:

var obj = { x: 1, y: 2, z: 3 };
obj[Symbol.iterator] = function() {
    // iterator 是一個(gè)具有 next 方法的對象,
    // 它的返回至少有一個(gè)對象
    // 兩個(gè)屬性:value&done。
    // 返回一個(gè) iterator 對象
    return {
        next: function() {
            if (this._countDown === 3) {
               const lastValue = this._countDown;
               return { value: this._countDown, done: true };
              }
            this._countDown = this._countDown + 1;
            return { value: this._countDown, done: false };
        },
        _countDown: 0
    };
};
[...obj]; // 打印 [1, 2, 3]

問題6答案:如上是一種方案,可以避免TypeError異常。

問題7:
在看這個(gè)問題的時(shí)候,我們要先理解for-in循環(huán)遍歷本身的可枚舉屬性和對象從原來的原型繼承來的屬性。可枚舉屬性是可以在for-in循環(huán)期間可以訪問的屬性。
當(dāng)我們知道這個(gè)知識點(diǎn)前提了之后,我們在看這道題,你就知道這道題打印的其實(shí)就是只能打印這些特定的屬性。

var obj = { a: 1, b: 2 }; //a,b 都是可枚舉屬性

// 將{c:3}設(shè)置為"obj"的原型,
// 并且我們知道for-in 循環(huán)也迭代 obj 繼承的屬性
// 從它的原型,"c"也可以被訪問。
Object.setPrototypeOf(obj, { c: 3 });

// 我們在"obj"中定義了另外一個(gè)屬性"d",
// 但是將"enumerable"可枚舉設(shè)置為false。 這意味著"d"將被忽略。
Object.defineProperty(obj, "d", { value: 4, enumerable: false });
//所以最后使用for-in遍歷這個(gè)對象集合,那就是只能遍歷出可枚舉屬性
for (let prop in obj) {
    console.log(prop);
}

// 也就是只能打印
// a
// b
// c

圖解

問題7答案:a、b、c

問題8:
首先我們可以看到var x是一個(gè)全局遍歷,在不是嚴(yán)格模式下,這個(gè)X就直接是window對象的屬性了。在這段代碼里,我們最重要是要理解this的對象指向問題,this始終是指向調(diào)用方法的對象的。所以,在foo,xGetter()的情況下,this指向的是foo對象,返回的就是在foo中的屬性x,值就是90。但是在xGetter()的情況下,他是直接調(diào)用的foo的getx()方法,但是其中this的指向是在xGetter的作用域,就是指向的window對象中,這時(shí)指向的就是全局變量x了,值也就是10。

var x = 10; // 全局變量
var foo = {
    x: 90,//foo對象的內(nèi)部屬性
    getX: function() {
         return this.x;
    }
};
foo.getX(); // 此時(shí)是指向的foo對象,
//所以打印的是X屬性 值就是90
let xGetter = foo.getX;//xGetter是在全局作用域,
//這里的this就是指向window對象
xGetter(); // 打印 10


問題8答案:10

最后

ok,我們的8道問題都解決了,如果你前面寫的答案全部都正確,那么你非常棒!去面試前端工作起碼12k起步了。就算做不出來或者做錯(cuò)了也沒有關(guān)系,我們都是不斷通過犯錯(cuò)來學(xué)習(xí)的,一步步的理解錯(cuò)誤,理解背后的原因,才能進(jìn)步。

更多技術(shù)好文,前端開發(fā)學(xué)習(xí)教程,歡迎關(guān)注公眾號【前端研究所】看更多前端技術(shù)文章!

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

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106600.html

相關(guān)文章

  • 前端最強(qiáng)面經(jīng)匯總

    摘要:獲取的對象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對象即使沒有代碼,也會(huì)把默認(rèn)的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對于一個(gè)光禿禿的元素,方法返回對象中屬性值如果有就是據(jù)我測試不同環(huán)境結(jié)果可能有差異而就是。 花了很長時(shí)間整理的前端面試資源,喜歡請大家不要吝嗇star~ 別只收藏,點(diǎn)個(gè)贊,點(diǎn)個(gè)star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項(xiàng)目地址 https:...

    wangjuntytl 評論0 收藏0
  • 前端經(jīng)典文章

    摘要:上周末看這篇文章時(shí),偶有靈光,所以,分享出來給大家一起看看前端面試四月二十家前端面試題分享請各位讀者添加一下作者的微信公眾號,以后有新的文章,將在微信公眾號直接推送給各位,非常感謝。 前端切圖神器 avocode 有了這個(gè)神器,切圖再也腰不酸,腿不疼了。 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,...

    lowett 評論0 收藏0
  • javasscript - 收藏集 - 掘金

    摘要:跨域請求詳解從繁至簡前端掘金什么是為什么要用是的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。異步編程入門道典型的面試題前端掘金在界中,開發(fā)人員的需求量一直居高不下。 jsonp 跨域請求詳解——從繁至簡 - 前端 - 掘金什么是jsonp?為什么要用jsonp?JSONP(JSON with Padding)是JSON的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題...

    Rango 評論0 收藏0
  • JavasScript重難點(diǎn)知識

    摘要:忍者級別的函數(shù)操作對于什么是匿名函數(shù),這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果...

    forsigner 評論0 收藏0
  • 程序語言

    摘要:一面應(yīng)該還問了其他內(nèi)容,但是兩次面試多線程面試問題和答案采訪中,我們通常會(huì)遇到兩個(gè)主題采集問題和多線程面試問題。多線程是關(guān)于并發(fā)和線程的。我們正在共享重要的多線程面試問題和答案。。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 【碼農(nóng)每日一題】Java 內(nèi)部類(Part 2)相關(guān)面試題 關(guān)注一下嘛,又不讓你背鍋!問:Ja...

    mtunique 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<