<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          字節(jié)跳動(dòng)最愛(ài)考的前端面試題:JavaScript 基礎(chǔ)

          共 12084字,需瀏覽 25分鐘

           ·

          2021-02-02 00:50


          注意:每道題前面出現(xiàn)的 (xx) 數(shù)字代表這道題出現(xiàn)的頻次,此 JS 基礎(chǔ)是基于 30+ 篇前端面經(jīng)整理出的問(wèn)題和對(duì)應(yīng)的回答、參考鏈接等。

          (2)問(wèn):0.1 + 0.2 === 0.3 嘛?為什么?

          JavaScirpt 使用 Number 類型來(lái)表示數(shù)字(整數(shù)或浮點(diǎn)數(shù)),遵循 IEEE 754 標(biāo)準(zhǔn),通過(guò) 64 位來(lái)表示一個(gè)數(shù)字(1 + 11 + 52)

          • 1 符號(hào)位,0 表示正數(shù),1 表示負(fù)數(shù) s
          • 11 指數(shù)位(e)
          • 52 尾數(shù),小數(shù)部分(即有效數(shù)字)

          最大安全數(shù)字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,轉(zhuǎn)換成整數(shù)就是 16 位,所以 0.1 === 0.1,是因?yàn)橥ㄟ^(guò) toPrecision(16) 去有效位之后,兩者是相等的。

          在兩數(shù)相加時(shí),會(huì)先轉(zhuǎn)換成二進(jìn)制,0.1 和 0.2 轉(zhuǎn)換成二進(jìn)制的時(shí)候尾數(shù)會(huì)發(fā)生無(wú)限循環(huán),然后進(jìn)行對(duì)階運(yùn)算,JS 引擎對(duì)二進(jìn)制進(jìn)行截?cái)啵栽斐删葋G失。

          所以總結(jié):精度丟失可能出現(xiàn)在進(jìn)制轉(zhuǎn)換和對(duì)階運(yùn)算中

          參考鏈接

          • https://juejin.im/post/5b90e00e6fb9a05cf9080dff

          (4)問(wèn):JS 數(shù)據(jù)類型

          基本類型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用類型:Object,對(duì)象子類型(Array,F(xiàn)unction)

          參考鏈接

          • https://juejin.im/post/5b2b0a6051882574de4f3d96
          • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures

          問(wèn):JS 整數(shù)是怎么表示的?

          • 通過(guò) Number 類型來(lái)表示,遵循 IEEE754 標(biāo)準(zhǔn),通過(guò) 64 位來(lái)表示一個(gè)數(shù)字,(1 + 11 + 52),最大安全數(shù)字是 Math.pow(2, 53) - 1,對(duì)于 16 位十進(jìn)制。(符號(hào)位 + 指數(shù)位 + 小數(shù)部分有效位)

          問(wèn):Number() 的存儲(chǔ)空間是多大?如果后臺(tái)發(fā)送了一個(gè)超過(guò)最大自己的數(shù)字怎么辦

          Math.pow(2, 53) ,53 為有效數(shù)字,會(huì)發(fā)生截?cái)啵扔?JS 能支持的最大數(shù)字。

          (4)寫(xiě)代碼:實(shí)現(xiàn)函數(shù)能夠深度克隆基本類型

          淺克?。?/p>

          function?shallowClone(obj)?{
          ??let?cloneObj?=?{};
          ??
          ??for?(let?i?in?obj)?{
          ????cloneObj[i]?=?obj[i];
          ??}
          ??
          ??return?cloneObj;
          }

          深克隆:

          • 考慮基礎(chǔ)類型
          • 引用類型
            • RegExp、Date、函數(shù) 不是 JSON 安全的
            • 會(huì)丟失 constructor,所有的構(gòu)造函數(shù)都指向 Object
            • 破解循環(huán)引用
          function?deepCopy(obj)?{
          ??if?(typeof?obj?===?'object')?{
          ????var?result?=?obj.constructor?===?Array???[]?:?{};
          ????
          ????for?(var?i?in?obj)?{
          ??????result[i]?=?typeof?obj[i]?===?'object'???deepCopy(obj[i])?:?obj[i];
          ????}
          ??}?else?{
          ????var?result?=?obj;
          ??}
          ??
          ??return?result;
          }

          問(wèn):事件流

          事件流是網(wǎng)頁(yè)元素接收事件的順序,"DOM2級(jí)事件"規(guī)定的事件流包括三個(gè)階段:事件捕獲階段、處于目標(biāo)階段、事件冒泡階段。首先發(fā)生的事件捕獲,為截獲事件提供機(jī)會(huì)。然后是實(shí)際的目標(biāo)接受事件。最后一個(gè)階段是時(shí)間冒泡階段,可以在這個(gè)階段對(duì)事件做出響應(yīng)。雖然捕獲階段在規(guī)范中規(guī)定不允許響應(yīng)事件,但是實(shí)際上還是會(huì)執(zhí)行,所以有兩次機(jī)會(huì)獲取到目標(biāo)對(duì)象。

          html>
          <html?lang="en">
          <head>
          ????<meta?charset="UTF-8">
          ????<title>事件冒泡title>
          head>
          <body>
          ????<div>
          ????????<p?id="parEle">我是父元素????<span?id="sonEle">我是子元素span>p>
          ????div>
          body>
          html>
          <script?type="text/javascript">
          var?sonEle?=?document.getElementById('sonEle');
          var?parEle?=?document.getElementById('parEle');

          parEle.addEventListener('click',?function?()?{
          ????alert('父級(jí)?冒泡');
          },?false);
          parEle.addEventListener('click',?function?()?{
          ????alert('父級(jí)?捕獲');
          },?true);

          sonEle.addEventListener('click',?function?()?{
          ????alert('子級(jí)冒泡');
          },?false);
          sonEle.addEventListener('click',?function?()?{
          ????alert('子級(jí)捕獲');
          },?true);

          script>

          當(dāng)容器元素及嵌套元素,即在捕獲階段又在冒泡階段調(diào)用事件處理程序時(shí):事件按DOM事件流的順序執(zhí)行事件處理程序:

          • 父級(jí)捕獲
          • 子級(jí)冒泡
          • 子級(jí)捕獲
          • 父級(jí)冒泡

          且當(dāng)事件處于目標(biāo)階段時(shí),事件調(diào)用順序決定于綁定事件的書(shū)寫(xiě)順序,按上面的例子為,先調(diào)用冒泡階段的事件處理程序,再調(diào)用捕獲階段的事件處理程序。依次alert出“子集冒泡”,“子集捕獲”。

          IE 兼容

          • attchEvent('on' + type, handler)
          • detachEvent('on' + type, handler)

          參考鏈接

          • https://juejin.im/entry/5826ba9d0ce4630056f85e07

          問(wèn):事件是如何實(shí)現(xiàn)的?

          基于發(fā)布訂閱模式,就是在瀏覽器加載的時(shí)候會(huì)讀取事件相關(guān)的代碼,但是只有實(shí)際等到具體的事件觸發(fā)的時(shí)候才會(huì)執(zhí)行。

          比如點(diǎn)擊按鈕,這是個(gè)事件(Event),而負(fù)責(zé)處理事件的代碼段通常被稱為事件處理程序(Event Handler),也就是「啟動(dòng)對(duì)話框的顯示」這個(gè)動(dòng)作。

          在 Web 端,我們常見(jiàn)的就是 DOM 事件:

          • DOM0 級(jí)事件,直接在 html 元素上綁定 on-event,比如 onclick,取消的話,dom.onclick = null,同一個(gè)事件只能有一個(gè)處理程序,后面的會(huì)覆蓋前面的。
          • DOM2 級(jí)事件,通過(guò) addEventListener 注冊(cè)事件,通過(guò) removeEventListener 來(lái)刪除事件,一個(gè)事件可以有多個(gè)事件處理程序,按順序執(zhí)行,捕獲事件和冒泡事件
          • DOM3級(jí)事件,增加了事件類型,比如 UI 事件,焦點(diǎn)事件,鼠標(biāo)事件

          參考鏈接

          • https://zhuanlan.zhihu.com/p/73091706

          問(wèn):new 一個(gè)函數(shù)發(fā)生了什么

          構(gòu)造調(diào)用:

          • 創(chuàng)造一個(gè)全新的對(duì)象
          • 這個(gè)對(duì)象會(huì)被執(zhí)行 [[Prototype]] 連接,將這個(gè)新對(duì)象的 [[Prototype]] 鏈接到這個(gè)構(gòu)造函數(shù).prototype 所指向的對(duì)象
          • 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的 this
          • 如果函數(shù)沒(méi)有返回其他對(duì)象,那么 new 表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象

          問(wèn):new 一個(gè)構(gòu)造函數(shù),如果函數(shù)返回 return {} 、 return null , return 1 , return true 會(huì)發(fā)生什么情況?

          如果函數(shù)返回一個(gè)對(duì)象,那么new 這個(gè)函數(shù)調(diào)用返回這個(gè)函數(shù)的返回對(duì)象,否則返回 new 創(chuàng)建的新對(duì)象

          問(wèn):symbol?有什么用處

          可以用來(lái)表示一個(gè)獨(dú)一無(wú)二的變量防止命名沖突。但是面試官問(wèn)還有嗎?我沒(méi)想出其他的用處就直接答我不知道了,還可以利用?symbol?不會(huì)被常規(guī)的方法(除了?Object.getOwnPropertySymbols?外)遍歷到,所以可以用來(lái)模擬私有變量。

          主要用來(lái)提供遍歷接口,布置了?symbol.iterator?的對(duì)象才可以使用?for···of?循環(huán),可以統(tǒng)一處理數(shù)據(jù)結(jié)構(gòu)。調(diào)用之后回返回一個(gè)遍歷器對(duì)象,包含有一個(gè) next 方法,使用 next 方法后有兩個(gè)返回值 value 和 done 分別表示函數(shù)當(dāng)前執(zhí)行位置的值和是否遍歷完畢。

          Symbol.for() 可以在全局訪問(wèn) symbol

          (3)問(wèn):閉包是什么?

          閉包是指有權(quán)訪問(wèn)另外一個(gè)函數(shù)作用域中的變量的函數(shù)

          JavaScript代碼的整個(gè)執(zhí)行過(guò)程,分為兩個(gè)階段,代碼編譯階段與代碼執(zhí)行階段。編譯階段由編譯器完成,將代碼翻譯成可執(zhí)行代碼,這個(gè)階段作用域規(guī)則會(huì)確定。執(zhí)行階段由引擎完成,主要任務(wù)是執(zhí)行可執(zhí)行代碼,執(zhí)行上下文在這個(gè)階段創(chuàng)建。

          image.png

          什么是作業(yè)域?

          ES5 中只存在兩種作用域:全局作用域和函數(shù)作用域。在 JavaScript 中,我們將作用域定義為一套規(guī)則,這套規(guī)則用來(lái)管理引擎如何在當(dāng)前作用域以及嵌套子作用域中根據(jù)標(biāo)識(shí)符名稱進(jìn)行變量(變量名或者函數(shù)名)查找

          什么是作用域鏈?

          首先要了解作用域鏈,當(dāng)訪問(wèn)一個(gè)變量時(shí),編譯器在執(zhí)行這段代碼時(shí),會(huì)首先從當(dāng)前的作用域中查找是否有這個(gè)標(biāo)識(shí)符,如果沒(méi)有找到,就會(huì)去父作用域查找,如果父作用域還沒(méi)找到繼續(xù)向上查找,直到全局作用域?yàn)橹?,而作用域鏈,就是有當(dāng)前作用域與上層作用域的一系列變量對(duì)象組成,它保證了當(dāng)前執(zhí)行的作用域?qū)Ψ显L問(wèn)權(quán)限的變量和函數(shù)的有序訪問(wèn)。

          閉包產(chǎn)生的本質(zhì)

          當(dāng)前環(huán)境中存在指向父級(jí)作用域的引用

          什么是閉包

          閉包是一種特殊的對(duì)象,它由兩部分組成:執(zhí)行上下文(代號(hào) A),以及在該執(zhí)行上下文中創(chuàng)建的函數(shù) (代號(hào) B),當(dāng) B 執(zhí)行時(shí),如果訪問(wèn)了 A 中變量對(duì)象的值,那么閉包就會(huì)產(chǎn)生,且在 Chrome 中使用這個(gè)執(zhí)行上下文 A 的函數(shù)名代指閉包。

          一般如何產(chǎn)生閉包

          • 返回函數(shù)
          • 函數(shù)當(dāng)做參數(shù)傳遞

          閉包的應(yīng)用場(chǎng)景

          • 柯里化 bind
          • 模塊

          參考文章

          • https://segmentfault.com/a/1190000012646221

          問(wèn):NaN 是什么,用 typeof 會(huì)輸出什么?

          Not a Number,表示非數(shù)字,typeof NaN === 'number'

          (2)問(wèn):JS 隱式轉(zhuǎn)換,顯示轉(zhuǎn)換

          一般非基礎(chǔ)類型進(jìn)行轉(zhuǎn)換時(shí)會(huì)先調(diào)用 valueOf,如果 valueOf 無(wú)法返回基本類型值,就會(huì)調(diào)用 toString

          字符串和數(shù)字

          • "+" 操作符,如果有一個(gè)為字符串,那么都轉(zhuǎn)化到字符串然后執(zhí)行字符串拼接
          • "-" 操作符,轉(zhuǎn)換為數(shù)字,相減 (-a, a * 1 a/1) 都能進(jìn)行隱式強(qiáng)制類型轉(zhuǎn)換
          []?+?{}?和?{}?+?[]

          布爾值到數(shù)字

          • 1 + true = 2
          • 1 + false = 1

          轉(zhuǎn)換為布爾值

          • for 中第二個(gè)
          • while
          • if
          • 三元表達(dá)式
          • || (邏輯或) && (邏輯與)左邊的操作數(shù)

          符號(hào)

          • 不能被轉(zhuǎn)換為數(shù)字
          • 能被轉(zhuǎn)換為布爾值(都是 true)
          • 可以被轉(zhuǎn)換成字符串 "Symbol(cool)"

          寬松相等和嚴(yán)格相等

          寬松相等允許進(jìn)行強(qiáng)制類型轉(zhuǎn)換,而嚴(yán)格相等不允許

          字符串與數(shù)字

          轉(zhuǎn)換為數(shù)字然后比較

          其他類型與布爾類型

          • 先把布爾類型轉(zhuǎn)換為數(shù)字,然后繼續(xù)進(jìn)行比較

          對(duì)象與非對(duì)象

          • 執(zhí)行對(duì)象的 ToPrimitive(對(duì)象)然后繼續(xù)進(jìn)行比較

          假值列表

          • undefined
          • null
          • false
          • +0, -0, NaN
          • ""

          (2)問(wèn):了解 this 嘛,bind,call,apply 具體指什么

          它們都是函數(shù)的方法

          call: Array.prototype.call(this, args1, args2])apply: Array.prototype.apply(this, [args1, args2]) :ES6 之前用來(lái)展開(kāi)數(shù)組調(diào)用, foo.appy(null, []),ES6 之后使用 ... 操作符

          • New 綁定 > 顯示綁定 > 隱式綁定 > 默認(rèn)綁定
          • 如果需要使用 bind 的柯里化和 apply 的數(shù)組解構(gòu),綁定到 null,盡可能使用 Object.create(null) 創(chuàng)建一個(gè) DMZ 對(duì)象

          四條規(guī)則:

          • 默認(rèn)綁定,沒(méi)有其他修飾(bind、apply、call),在非嚴(yán)格模式下定義指向全局對(duì)象,在嚴(yán)格模式下定義指向 undefined
          function?foo()?{
          ??console.log(this.a);?
          }

          var?a?=?2;
          foo();
          • 隱式綁定:調(diào)用位置是否有上下文對(duì)象,或者是否被某個(gè)對(duì)象擁有或者包含,那么隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的 this 綁定到這個(gè)上下文對(duì)象。而且,對(duì)象屬性鏈只有上一層或者說(shuō)最后一層在調(diào)用位置中起作用
          function?foo()?{
          ??console.log(this.a);
          }

          var?obj?=?{
          ??a:?2,
          ??foo:?foo,
          }

          obj.foo();?//?2
          • 顯示綁定:通過(guò)在函數(shù)上運(yùn)行 call 和 apply ,來(lái)顯示的綁定 this
          function?foo()?{
          ??console.log(this.a);
          }

          var?obj?=?{
          ??a:?2
          };

          foo.call(obj);

          顯示綁定之硬綁定

          function?foo(something)?{
          ??console.log(this.a,?something);
          ??
          ??return?this.a?+?something;
          }

          function?bind(fn,?obj)?{
          ??return?function()?{
          ????return?fn.apply(obj,?arguments);
          ??};
          }

          var?obj?=?{
          ??a:?2
          }

          var?bar?=?bind(foo,?obj);

          New 綁定,new 調(diào)用函數(shù)會(huì)創(chuàng)建一個(gè)全新的對(duì)象,并將這個(gè)對(duì)象綁定到函數(shù)調(diào)用的 this。

          • New 綁定時(shí),如果是 new 一個(gè)硬綁定函數(shù),那么會(huì)用 new 新建的對(duì)象替換這個(gè)硬綁定 this,
          function?foo(a)?{
          ??this.a?=?a;
          }

          var?bar?=?new?foo(2);
          console.log(bar.a)

          (4)問(wèn):手寫(xiě) bind、apply、call

          //?call

          Function.prototype.call?=?function?(context,?...args)?{
          ??context?=?context?||?window;
          ??
          ??const?fnSymbol?=?Symbol("fn");
          ??context[fnSymbol]?=?this;
          ??
          ??context[fnSymbol](...args);
          ??delete?context[fnSymbol];
          }
          //?apply

          Function.prototype.apply?=?function?(context,?argsArr)?{
          ??context?=?context?||?window;
          ??
          ??const?fnSymbol?=?Symbol("fn");
          ??context[fnSymbol]?=?this;
          ??
          ??context[fnSymbol](...argsArr);
          ??delete?context[fnSymbol];
          }
          //?bind

          Function.prototype.bind?=?function?(context,?...args)?{
          ??context?=?context?||?window;
          ??const?fnSymbol?=?Symbol("fn");
          ??context[fnSymbol]?=?this;
          ??
          ??return?function?(..._args)?{
          ????_args?=?_args.concat(args);
          ????
          ????context[fnSymbol](..._args);
          ????delete?context[fnSymbol];???
          ??}
          }
          ????

          (3)問(wèn):setTimeout(fn, 0)多久才執(zhí)行,Event Loop

          setTimeout 按照順序放到隊(duì)列里面,然后等待函數(shù)調(diào)用棧清空之后才開(kāi)始執(zhí)行,而這些操作進(jìn)入隊(duì)列的順序,則由設(shè)定的延遲時(shí)間來(lái)決定

          手寫(xiě)題:Promise 原理

          class?MyPromise?{
          ??constructor(fn)?{
          ????this.resolvedCallbacks?=?[];
          ????this.rejectedCallbacks?=?[];
          ????
          ????this.state?=?'PENDING';
          ????this.value?=?'';
          ????
          ????fn(this.resolve.bind(this),?this.reject.bind(this));
          ????
          ??}
          ??
          ??resolve(value)?{
          ????if?(this.state?===?'PENDING')?{
          ??????this.state?=?'RESOLVED';
          ??????this.value?=?value;
          ??????
          ??????this.resolvedCallbacks.map(cb?=>?cb(value));???
          ????}
          ??}
          ??
          ??reject(value)?{
          ????if?(this.state?===?'PENDING')?{
          ??????this.state?=?'REJECTED';
          ??????this.value?=?value;
          ??????
          ??????this.rejectedCallbacks.map(cb?=>?cb(value));
          ????}
          ??}
          ??
          ??then(onFulfilled,?onRejected)?{
          ????if?(this.state?===?'PENDING')?{
          ??????this.resolvedCallbacks.push(onFulfilled);
          ??????this.rejectedCallbacks.push(onRejected);
          ??????
          ????}
          ????
          ????if?(this.state?===?'RESOLVED')?{
          ??????onFulfilled(this.value);
          ????}
          ????
          ????if?(this.state?===?'REJECTED')?{
          ??????onRejected(this.value);
          ????}
          ??}
          }
          ??????

          問(wèn):js腳本加載問(wèn)題,async、defer問(wèn)題

          • 如果依賴其他腳本和 DOM 結(jié)果,使用 defer
          • 如果與 DOM 和其他腳本依賴不強(qiáng)時(shí),使用 async

          參考資料

          問(wèn):如何判斷一個(gè)對(duì)象是不是空對(duì)象?

          Object.keys(obj).length === 0

          問(wèn):?
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    一区二区男女无码 | 国产无码一二三 | av777777 | 婷婷五月天天爽 | 亚洲影院之台湾 |