自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

開(kāi)發(fā) 前端
本篇給大家介紹字節(jié)跳動(dòng)最?lèi)?ài)考的前端面試題:JavaScript 基礎(chǔ),希望對(duì)你有所幫助。

[[379885]]

 注意:每道題前面出現(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)型來(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)?,所以造成精度丟失。

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

參考鏈接

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

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

基本類(lèi)型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用類(lèi)型:Object,對(duì)象子類(lèi)型(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)型來(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ù)能夠深度克隆基本類(lèi)型

淺克?。?/p>

  1. function shallowClone(obj) { 
  2.   let cloneObj = {}; 
  3.    
  4.   for (let i in obj) { 
  5.     cloneObj[i] = obj[i]; 
  6.   } 
  7.    
  8.   return cloneObj; 

深克?。?/p>

  • 考慮基礎(chǔ)類(lèi)型
  • 引用類(lèi)型

RegExp、Date、函數(shù) 不是 JSON 安全的

會(huì)丟失 constructor,所有的構(gòu)造函數(shù)都指向 Object

破解循環(huán)引用

  1. function deepCopy(obj) { 
  2.   if (typeof obj === 'object') { 
  3.     var result = obj.constructor === Array ? [] : {}; 
  4.      
  5.     for (var i in obj) { 
  6.       result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]; 
  7.     } 
  8.   } else { 
  9.     var result = obj; 
  10.   } 
  11.    
  12.   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ì)象。

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <meta charset="UTF-8"
  5.     <title>事件冒泡</title> 
  6. </head> 
  7. <body> 
  8.     <div> 
  9.         <p id="parEle">我是父元素    <span id="sonEle">我是子元素</span></p> 
  10.     </div> 
  11. </body> 
  12. </html> 
  13. <script type="text/javascript"
  14. var sonEle = document.getElementById('sonEle'); 
  15. var parEle = document.getElementById('parEle'); 
  16.  
  17. parEle.addEventListener('click'function () { 
  18.     alert('父級(jí) 冒泡'); 
  19. }, false); 
  20. parEle.addEventListener('click'function () { 
  21.     alert('父級(jí) 捕獲'); 
  22. }, true); 
  23.  
  24. sonEle.addEventListener('click'function () { 
  25.     alert('子級(jí)冒泡'); 
  26. }, false); 
  27. sonEle.addEventListener('click'function () { 
  28.     alert('子級(jí)捕獲'); 
  29. }, true); 
  30.  
  31. </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é)處理事件的代碼段通常被稱(chēng)為事件處理程序(Event Handler),也就是「啟動(dòng)對(duì)話(huà)框的顯示」這個(gè)動(dòng)作。

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

  • DOM0 級(jí)事件,直接在 html 元素上綁定 on-event,比如 onclick,取消的話(huà),dom.onclick = null,同一個(gè)事件只能有一個(gè)處理程序,后面的會(huì)覆蓋前面的。
  • DOM2 級(jí)事件,通過(guò) addEventListener 注冊(cè)事件,通過(guò) removeEventListener 來(lái)刪除事件,一個(gè)事件可以有多個(gè)事件處理程序,按順序執(zhí)行,捕獲事件和冒泡事件
  • DOM3級(jí)事件,增加了事件類(lèi)型,比如 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() 可以在全局訪(fǎng)問(wèn) symbol

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

閉包是指有權(quán)訪(fǎng)問(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í)符名稱(chēng)進(jìn)行變量(變量名或者函數(shù)名)查找

什么是作用域鏈?

首先要了解作用域鏈,當(dāng)訪(fǎ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(fǎng)問(wèn)權(quán)限的變量和函數(shù)的有序訪(fǎng)問(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í),如果訪(fǎng)問(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ǔ)類(lèi)型進(jìn)行轉(zhuǎn)換

時(shí)會(huì)先調(diào)用 valueOf,如果 valueOf 無(wú)法返回基本類(lèi)型值,就會(huì)調(diào)用 toString

字符串和數(shù)字

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

布爾值到數(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)制類(lèi)型轉(zhuǎn)換,而嚴(yán)格相等不允許

字符串與數(shù)字

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

其他類(lèi)型與布爾類(lèi)型

  • 先把布爾類(lèi)型轉(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
  1. function foo() { 
  2.   console.log(this.a);  
  3.  
  4. var a = 2; 
  5. foo(); 
  • 隱式綁定:調(diào)用位置是否有上下文對(duì)象,或者是否被某個(gè)對(duì)象擁有或者包含,那么隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的 this 綁定到這個(gè)上下文對(duì)象。而且,對(duì)象屬性鏈只有上一層或者說(shuō)最后一層在調(diào)用位置中起作用
  1. function foo() { 
  2.   console.log(this.a); 
  3.  
  4. var obj = { 
  5.   a: 2, 
  6.   foo: foo, 
  7.  
  8. obj.foo(); // 2 
  • 顯示綁定:通過(guò)在函數(shù)上運(yùn)行 call 和 apply ,來(lái)顯示的綁定 this
  1. function foo() { 
  2.   console.log(this.a); 
  3.  
  4. var obj = { 
  5.   a: 2 
  6. }; 
  7.  
  8. foo.call(obj); 

顯示綁定之硬綁定

  1. function foo(something) { 
  2.   console.log(this.a, something); 
  3.    
  4.   return this.a + something; 
  5.  
  6. function bind(fn, obj) { 
  7.   return function() { 
  8.     return fn.apply(obj, arguments); 
  9.   }; 
  10.  
  11. var obj = { 
  12.   a: 2 
  13.  
  14. 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,
  1. function foo(a) { 
  2.   this.a = a; 
  3.  
  4. var bar = new foo(2); 
  5. console.log(bar.a) 

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

  1. // call 
  2.  
  3. Function.prototype.call = function (context, ...args) { 
  4.   context = context || window; 
  5.    
  6.   const fnSymbol = Symbol("fn"); 
  7.   context[fnSymbol] = this; 
  8.    
  9.   context[fnSymbol](...args); 
  10.   delete context[fnSymbol]; 

  1. // apply 
  2.  
  3. Function.prototype.apply = function (context, argsArr) { 
  4.   context = context || window; 
  5.    
  6.   const fnSymbol = Symbol("fn"); 
  7.   context[fnSymbol] = this; 
  8.    
  9.   context[fnSymbol](...argsArr); 
  10.   delete context[fnSymbol]; 

  1. // bind 
  2.  
  3. Function.prototype.bind = function (context, ...args) { 
  4.   context = context || window; 
  5.   const fnSymbol = Symbol("fn"); 
  6.   context[fnSymbol] = this; 
  7.    
  8.   return function (..._args) { 
  9.     _args = _args.concat(args); 
  10.      
  11.     context[fnSymbol](..._args); 
  12.     delete context[fnSymbol];    
  13.   } 
  14.      

(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 原理

  1. class MyPromise { 
  2.   constructor(fn) { 
  3.     this.resolvedCallbacks = []; 
  4.     this.rejectedCallbacks = []; 
  5.      
  6.     this.state = 'PENDING'
  7.     this.value = ''
  8.      
  9.     fn(this.resolve.bind(this), this.reject.bind(this)); 
  10.      
  11.   } 
  12.    
  13.   resolve(value) { 
  14.     if (this.state === 'PENDING') { 
  15.       this.state = 'RESOLVED'
  16.       this.value = value; 
  17.        
  18.       this.resolvedCallbacks.map(cb => cb(value));    
  19.     } 
  20.   } 
  21.    
  22.   reject(value) { 
  23.     if (this.state === 'PENDING') { 
  24.       this.state = 'REJECTED'
  25.       this.value = value; 
  26.        
  27.       this.rejectedCallbacks.map(cb => cb(value)); 
  28.     } 
  29.   } 
  30.    
  31.   then(onFulfilled, onRejected) { 
  32.     if (this.state === 'PENDING') { 
  33.       this.resolvedCallbacks.push(onFulfilled); 
  34.       this.rejectedCallbacks.push(onRejected); 
  35.        
  36.     } 
  37.      
  38.     if (this.state === 'RESOLVED') { 
  39.       onFulfilled(this.value); 
  40.     } 
  41.      
  42.     if (this.state === 'REJECTED') { 
  43.       onRejected(this.value); 
  44.     } 
  45.   } 
  46.        

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

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

參考資料

https://mp.weixin.qq.com/s/pw5lfFeNagmjFj45ygl2dQ

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

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

問(wèn): <script src=’xxx’ ’xxx’/>外部js文件先加載還是onload先執(zhí)行,為什么?
onload 是所以加載完成之后執(zhí)行的

問(wèn):怎么加事件監(jiān)聽(tīng),兩種
onclick 和 addEventListener

問(wèn):事件傳播機(jī)制(事件流)
冒泡和捕獲

(4)問(wèn):說(shuō)一下原型鏈和原型鏈的繼承吧

  • 所有普通的 [[Prototype]] 鏈最終都會(huì)指向內(nèi)置的 Object.prototype,其包含了 JavaScript 中許多通用的功能
  • 為什么能創(chuàng)建 “類(lèi)”,借助一種特殊的屬性:所有的函數(shù)默認(rèn)都會(huì)擁有一個(gè)名為 prototype 的共有且不可枚舉的屬性,它會(huì)指向另外一個(gè)對(duì)象,這個(gè)對(duì)象通常被稱(chēng)為函數(shù)的原型
  1. function Person(name) { 
  2.   this.name = name
  3.  
  4. Person.prototype.constructor = Person 
  • 在發(fā)生 new 構(gòu)造函數(shù)調(diào)用時(shí),會(huì)將創(chuàng)建的新對(duì)象的 [[Prototype]] 鏈接到 Person.prototype 指向的對(duì)象,這個(gè)機(jī)制就被稱(chēng)為原型鏈繼承
  • 方法定義在原型上,屬性定義在構(gòu)造函數(shù)上
  • 首先要說(shuō)一下 JS 原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù) (constructor)都有一個(gè)原型對(duì)象(prototype),這個(gè)原型對(duì)象包含一個(gè)指向此構(gòu)造函數(shù)的指針屬性,通過(guò) new 進(jìn)行構(gòu)造函數(shù)調(diào)用生成的實(shí)例,此實(shí)例包含一個(gè)指向原型對(duì)象的指針,也就是通過(guò) [[Prototype]] 鏈接到了這個(gè)原型對(duì)象
  • 然后說(shuō)一下 JS 中屬性的查找:當(dāng)我們?cè)噲D引用實(shí)例對(duì)象的某個(gè)屬性時(shí),是按照這樣的方式去查找的,首先查找實(shí)例對(duì)象上是否有這個(gè)屬性,如果沒(méi)有找到,就去構(gòu)造這個(gè)實(shí)例對(duì)象的構(gòu)造函數(shù)的 prototype 所指向的對(duì)象上去查找,如果還找不到,就從這個(gè) prototype 對(duì)象所指向的構(gòu)造函數(shù)的 prototype 原型對(duì)象上去查找
  • 什么是原型鏈:這樣逐級(jí)查找形似一個(gè)鏈條,且通過(guò) [[Prototype]] 屬性鏈接,所以被稱(chēng)為原型鏈
  • 什么是原型鏈繼承,類(lèi)比類(lèi)的繼承:當(dāng)有兩個(gè)構(gòu)造函數(shù) A 和 B,將一個(gè)構(gòu)造函數(shù) A 的原型對(duì)象的,通過(guò)其 [[Prototype]] 屬性鏈接到另外一個(gè) B 構(gòu)造函數(shù)的原型對(duì)象時(shí),這個(gè)過(guò)程被稱(chēng)之為原型繼承。

標(biāo)準(zhǔn)答案更正確的解釋
什么是原型鏈?

當(dāng)對(duì)象查找一個(gè)屬性的時(shí)候,如果沒(méi)有在自身找到,那么就會(huì)查找自身的原型,如果原型還沒(méi)有找到,那么會(huì)繼續(xù)查找原型的原型,直到找到 Object.prototype 的原型時(shí),此時(shí)原型為 null,查找停止。這種通過(guò) 通過(guò)原型鏈接的逐級(jí)向上的查找鏈被稱(chēng)為原型鏈

什么是原型繼承?

一個(gè)對(duì)象可以使用另外一個(gè)對(duì)象的屬性或者方法,就稱(chēng)之為繼承。具體是通過(guò)將這個(gè)對(duì)象的原型設(shè)置為另外一個(gè)對(duì)象,這樣根據(jù)原型鏈的規(guī)則,如果查找一個(gè)對(duì)象屬性且在自身不存在時(shí),就會(huì)查找另外一個(gè)對(duì)象,相當(dāng)于一個(gè)對(duì)象可以使用另外一個(gè)對(duì)象的屬性和方法了。

參考鏈接
https://zhuanlan.zhihu.com/p/35790971
問(wèn):說(shuō)下對(duì) JS 的了解吧
是基于原型的動(dòng)態(tài)語(yǔ)言,主要獨(dú)特特性有 this、原型和原型鏈。

JS 嚴(yán)格意義上來(lái)說(shuō)分為:語(yǔ)言標(biāo)準(zhǔn)部分(ECMAScript)+ 宿主環(huán)境部分

語(yǔ)言標(biāo)準(zhǔn)部分
2015 年發(fā)布 ES6,引入諸多新特性使得能夠編寫(xiě)大型項(xiàng)目變成可能,標(biāo)準(zhǔn)自 2015 之后以年號(hào)代號(hào),每年一更

宿主環(huán)境部分
在瀏覽器宿主環(huán)境包括 DOM + BOM 等
在 Node,宿主環(huán)境包括一些文件、數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)、與操作系統(tǒng)的交互等
問(wèn):數(shù)組能夠調(diào)用的函數(shù)有那些?

  • push
  • pop
  • splice
  • slice
  • shift
  • unshift
  • sort
  • find
  • findIndex
  • map/filter/reduce 等函數(shù)式編程方法
  • 還有一些原型鏈上的方法:toString/valudOf

問(wèn):如何判斷數(shù)組類(lèi)型
Array.isArray

問(wèn): 函數(shù)中的arguments是數(shù)組嗎?類(lèi)數(shù)組轉(zhuǎn)數(shù)組的方法了解一下?
是類(lèi)數(shù)組,是屬于鴨子類(lèi)型的范疇,長(zhǎng)得像數(shù)組,

... 運(yùn)算符
Array.from
Array.prototype.slice.apply(arguments)
問(wèn):用過(guò) TypeScript 嗎?它的作用是什么?
為 JS 添加類(lèi)型支持,以及提供最新版的 ES 語(yǔ)法的支持,是的利于團(tuán)隊(duì)協(xié)作和排錯(cuò),開(kāi)發(fā)大型項(xiàng)目

問(wèn):PWA使用過(guò)嗎?serviceWorker的使用原理是啥?
漸進(jìn)式網(wǎng)絡(luò)應(yīng)用(PWA)是谷歌在2015年底提出的概念。基本上算是web應(yīng)用程序,但在外觀和感覺(jué)上與原生app類(lèi)似。支持PWA的網(wǎng)站可以提供脫機(jī)工作、推送通知和設(shè)備硬件訪(fǎng)問(wèn)等功能。

Service Worker是瀏覽器在后臺(tái)獨(dú)立于網(wǎng)頁(yè)運(yùn)行的腳本,它打開(kāi)了通向不需要網(wǎng)頁(yè)或用戶(hù)交互的功能的大門(mén)?,F(xiàn)在,它們已包括如推送通知和后臺(tái)同步等功能。將來(lái),Service Worker將會(huì)支持如定期同步或地理圍欄等其他功能。本教程討論的核心功能是攔截和處理網(wǎng)絡(luò)請(qǐng)求,包括通過(guò)程序來(lái)管理緩存中的響應(yīng)。

參考鏈接
https://juejin.im/post/5e26aa785188254c257c462d#heading-8
問(wèn):ES6 之前使用 prototype 實(shí)現(xiàn)繼承
Object.create() 會(huì)創(chuàng)建一個(gè) “新” 對(duì)象,然后將此對(duì)象內(nèi)部的 [[Prototype]] 關(guān)聯(lián)到你指定的對(duì)象(Foo.prototype)。Object.create(null) 創(chuàng)建一個(gè)空 [[Prototype]] 鏈接的對(duì)象,這個(gè)對(duì)象無(wú)法進(jìn)行委托。

  1. function Foo(name) { 
  2.   this.name = name
  3.  
  4. Foo.prototype.myName = function () { 
  5.   return this.name
  6.  
  7. // 繼承屬性,通過(guò)借用構(gòu)造函數(shù)調(diào)用 
  8. function Bar(name, label) { 
  9.   Foo.call(this, name); 
  10.   this.label = label; 
  11.  
  12. // 繼承方法,創(chuàng)建備份 
  13. Bar.prototype = Object.create(Foo.prototype); 
  14.  
  15. // 必須設(shè)置回正確的構(gòu)造函數(shù),要不然在會(huì)發(fā)生判斷類(lèi)型出錯(cuò) 
  16. Bar.prototype.constructor = Bar; 
  17.  
  18.  // 必須在上一步之后 
  19. Bar.prototype.myLabel = function () { 
  20.   return this.label; 
  21.  
  22. var a = new Bar("a""obj a"); 
  23.  
  24. a.myName(); // "a" 
  25. a.myLabel(); // "obj a" 

問(wèn):如果一個(gè)構(gòu)造函數(shù),bind了一個(gè)對(duì)象,用這個(gè)構(gòu)造函數(shù)創(chuàng)建出的實(shí)例會(huì)繼承這個(gè)對(duì)象的屬性嗎?為什么?
不會(huì)繼承,因?yàn)楦鶕?jù) this 綁定四大規(guī)則,new 綁定的優(yōu)先級(jí)高于 bind 顯示綁定,通過(guò) new 進(jìn)行構(gòu)造函數(shù)調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)新對(duì)象會(huì)代替 bind 的對(duì)象綁定,作為此函數(shù)的 this,并且在此函數(shù)沒(méi)有返回對(duì)象的情況下,返回這個(gè)新建的對(duì)象

(3)箭頭函數(shù)和普通函數(shù)有啥區(qū)別?箭頭函數(shù)能當(dāng)構(gòu)造函數(shù)嗎?

  1. 普通函數(shù)通過(guò) function 關(guān)鍵字定義, this 無(wú)法結(jié)合詞法作用域使用,在運(yùn)行時(shí)綁定,只取決于函數(shù)的調(diào)用方式,在哪里被調(diào)用,調(diào)用位置。(取決于調(diào)用者,和是否獨(dú)立運(yùn)行)
  2. 箭頭函數(shù)使用被稱(chēng)為 “胖箭頭” 的操作 => 定義,箭頭函數(shù)不應(yīng)用普通函數(shù) this 綁定的四種規(guī)則,而是根據(jù)外層(函數(shù)或全局)的作用域來(lái)決定 this,且箭頭函數(shù)的綁定無(wú)法被修改(new 也不行)。
  • 一個(gè)函數(shù)內(nèi)部有兩個(gè)方法:[[Call]] 和 [[Construct]],在通過(guò) new 進(jìn)行函數(shù)調(diào)用時(shí),會(huì)執(zhí)行 [[construct]] 方法,創(chuàng)建一個(gè)實(shí)例對(duì)象,然后再執(zhí)行這個(gè)函數(shù)體,將函數(shù)的 this 綁定在這個(gè)實(shí)例對(duì)象上
  • 當(dāng)直接調(diào)用時(shí),執(zhí)行 [[Call]] 方法,直接執(zhí)行函數(shù)體
  • 箭頭函數(shù)沒(méi)有 [[Construct]] 方法,不能被用作構(gòu)造函數(shù)調(diào)用,當(dāng)使用 new 進(jìn)行函數(shù)調(diào)用時(shí)會(huì)報(bào)錯(cuò)。
  • 箭頭函數(shù)常用于回調(diào)函數(shù)中,包括事件處理器或定時(shí)器
  • 箭頭函數(shù)和 var self = this,都試圖取代傳統(tǒng)的 this 運(yùn)行機(jī)制,將 this 的綁定拉回到詞法作用域
  • 沒(méi)有原型、沒(méi)有 this、沒(méi)有 super,沒(méi)有 arguments,沒(méi)有 new.target
  • 不能通過(guò) new 關(guān)鍵字調(diào)用
  1. function foo() { 
  2.   return (a) => { 
  3.     console.log(this.a); 
  4.   } 
  5.  
  6. var obj1 = { 
  7.   a: 2 
  8.  
  9. var obj2 = { 
  10.   a: 3  
  11.  
  12. var bar = foo.call(obj1); 
  13. bar.call(obj2); 

參考資料
https://segmentfault.com/a/1190000015162781
問(wèn):知道 ES6 的 Class 嘛?Static 關(guān)鍵字有了解嘛
為這個(gè)類(lèi)的函數(shù)對(duì)象直接添加方法,而不是加在這個(gè)函數(shù)對(duì)象的原型對(duì)象上

(3)問(wèn):事件循環(huán)機(jī)制 (Event Loop)
事件循環(huán)機(jī)制從整體上告訴了我們 JavaScript 代碼的執(zhí)行順序Event Loop即事件循環(huán),是指瀏覽器或Node的一種解決javaScript單線(xiàn)程運(yùn)行時(shí)不會(huì)阻塞的一種機(jī)制,也就是我們經(jīng)常使用異步的原理。

先執(zhí)行宏任務(wù)隊(duì)列,然后執(zhí)行微任務(wù)隊(duì)列,然后開(kāi)始下一輪事件循環(huán),繼續(xù)先執(zhí)行宏任務(wù)隊(duì)列,再執(zhí)行微任務(wù)隊(duì)列。

  • 宏任務(wù):script/setTimeout/setInterval/setImmediate/ I/O / UI Rendering
  • 微任務(wù):process.nextTick()/Promise

上訴的 setTimeout 和 setInterval 等都是任務(wù)源,真正進(jìn)入任務(wù)隊(duì)列的是他們分發(fā)的任務(wù)。

優(yōu)先級(jí)

  • setTimeout = setInterval 一個(gè)隊(duì)列
  • setTimeout > setImmediate
  • process.nextTick > Promise
  1. for (const macroTask of macroTaskQueue) {   
  2.   handleMacroTask();     
  3.   for (const microTask of microTaskQueue) {     
  4.    handleMicroTask(microTask);   
  5.   } 

參考鏈接
https://juejin.im/post/59e85eebf265da430d571f89
(2)手寫(xiě)題:數(shù)組扁平化

  1. function flatten(arr) { 
  2.   let result = []; 
  3.  
  4.   for (let i = 0; i < arr.length; i++) { 
  5.     if (Array.isArray(arr[i])) { 
  6.       result = result.concat(flatten(arr[i])); 
  7.     } else { 
  8.       result = result.concat(arr[i]); 
  9.     } 
  10.   } 
  11.  
  12.   return result; 
  13.  
  14. const a = [1, [2, [3, 4]]]; 
  15. console.log(flatten(a)); 

 手寫(xiě)題:實(shí)現(xiàn)柯里化
預(yù)先設(shè)置一些參數(shù)

柯里化是什么:是指這樣一個(gè)函數(shù),它接收函數(shù) A,并且能返回一個(gè)新的函數(shù),這個(gè)新的函數(shù)能夠處理函數(shù) A 的剩余參數(shù)

  1. function createCurry(func, args) { 
  2.   var argity = func.length; 
  3.   var args = args || []; 
  4.    
  5.   return function () { 
  6.     var _args = [].slice.apply(arguments); 
  7.     args.push(..._args); 
  8.      
  9.     if (args.length < argity) { 
  10.       return createCurry.call(this, func, args); 
  11.     } 
  12.      
  13.     return func.apply(this, args); 
  14.   } 

手寫(xiě)題:數(shù)組去重

  1. Array.from(new Set([1, 1, 2, 2])) 

問(wèn):let 閉包
let 會(huì)產(chǎn)生臨時(shí)性死區(qū),在當(dāng)前的執(zhí)行上下文中,會(huì)進(jìn)行變量提升,但是未被初始化,所以在執(zhí)行上下文執(zhí)行階段,執(zhí)行代碼如果還沒(méi)有執(zhí)行到變量賦值,就引用此變量就會(huì)報(bào)錯(cuò),此變量未初始化。

問(wèn):變量提升
函數(shù)在運(yùn)行的時(shí)候,會(huì)首先創(chuàng)建執(zhí)行上下文,然后將執(zhí)行上下文入棧,然后當(dāng)此執(zhí)行上下文處于棧頂時(shí),開(kāi)始運(yùn)行執(zhí)行上下文。

在創(chuàng)建執(zhí)行上下文的過(guò)程中會(huì)做三件事:創(chuàng)建變量對(duì)象,創(chuàng)建作用域鏈,確定 this 指向,其中創(chuàng)建變量對(duì)象的過(guò)程中,首先會(huì)為 arguments 創(chuàng)建一個(gè)屬性,值為 arguments,然后會(huì)掃碼 function 函數(shù)聲明,創(chuàng)建一個(gè)同名屬性,值為函數(shù)的引用,接著會(huì)掃碼 var 變量聲明,創(chuàng)建一個(gè)同名屬性,值為 undefined,這就是變量提升。

instance 如何使用
左邊可以是任意值,右邊只能是函數(shù)

  1. 'hello tuture' instanceof String // false 

參考資料

  • https://juejin.im/post/5d79ccf85188254bf34fd9d1
  • https://mp.weixin.qq.com/s/pw5lfFeNagmjFj45ygl2dQ
  • https://mp.weixin.qq.com/s/bHclDpsGdfaZQT8u9VRAAw
  • https://www.jianshu.com/p/cd3fee40ef59

 

責(zé)任編輯:姜華 來(lái)源: 圖雀社區(qū)
相關(guān)推薦

2021-03-15 09:53:37

計(jì)算機(jī)網(wǎng)絡(luò)面試題

2024-02-26 15:35:44

2022-02-09 07:40:42

JavaScript前端面試題

2022-01-18 08:16:52

Web 前端JavaScript

2022-07-27 08:27:34

Call前端

2019-02-21 14:12:26

前端面試題Vue

2023-05-19 08:21:40

MarginCSS

2023-08-27 15:57:28

前端開(kāi)發(fā)

2024-01-01 15:30:59

JavaScriptWeb 應(yīng)用程序開(kāi)發(fā)

2023-06-26 08:24:23

JavaScriptAJAX

2022-07-08 08:21:26

JSbind 方法

2018-03-08 18:40:47

Java百度面試題

2020-09-16 14:17:42

flat方法

2010-12-02 11:31:24

2025-01-09 12:00:00

JavaScript前端數(shù)組

2019-09-02 15:06:16

面試字節(jié)跳動(dòng)算法

2013-01-05 14:51:34

JavaScriptjQuery面試

2024-06-04 14:52:28

2017-09-06 09:13:24

2023-12-12 07:40:52

JavaScript面試題前端
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)