字節(jié)跳動最愛考的前端面試題:JavaScript 基礎
注意:每道題前面出現(xiàn)的 (xx) 數(shù)字代表這道題出現(xiàn)的頻次,此 JS 基礎是基于 30+ 篇前端面經整理出的問題和對應的回答、參考鏈接等。
(2)問:0.1 + 0.2 === 0.3 嘛?為什么?
JavaScirpt 使用 Number 類型來表示數(shù)字(整數(shù)或浮點數(shù)),遵循 IEEE 754 標準,通過 64 位來表示一個數(shù)字(1 + 11 + 52)
1 符號位,0 表示正數(shù),1 表示負數(shù) s 11 指數(shù)位(e) 52 尾數(shù),小數(shù)部分(即有效數(shù)字)
最大安全數(shù)字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,轉換成整數(shù)就是 16 位,所以 0.1 === 0.1,是因為通過 toPrecision(16) 去有效位之后,兩者是相等的。
在兩數(shù)相加時,會先轉換成二進制,0.1 和 0.2 轉換成二進制的時候尾數(shù)會發(fā)生無限循環(huán),然后進行對階運算,JS 引擎對二進制進行截斷,所以造成精度丟失。
所以總結:精度丟失可能出現(xiàn)在進制轉換和對階運算中
參考鏈接
https://juejin.im/post/5b90e00e6fb9a05cf9080dff
(4)問:JS 數(shù)據(jù)類型
基本類型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用類型:Object,對象子類型(Array,F(xiàn)unction)
參考鏈接
https://juejin.im/post/5b2b0a6051882574de4f3d96 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures
問:JS 整數(shù)是怎么表示的?
通過 Number 類型來表示,遵循 IEEE754 標準,通過 64 位來表示一個數(shù)字,(1 + 11 + 52),最大安全數(shù)字是 Math.pow(2, 53) - 1,對于 16 位十進制。(符號位 + 指數(shù)位 + 小數(shù)部分有效位)
問:Number() 的存儲空間是多大?如果后臺發(fā)送了一個超過最大自己的數(shù)字怎么辦
Math.pow(2, 53) ,53 為有效數(shù)字,會發(fā)生截斷,等于 JS 能支持的最大數(shù)字。
(4)寫代碼:實現(xiàn)函數(shù)能夠深度克隆基本類型
淺克隆:
function shallowClone(obj) {
let cloneObj = {};
for (let i in obj) {
cloneObj[i] = obj[i];
}
return cloneObj;
}
深克隆:
考慮基礎類型 引用類型 RegExp、Date、函數(shù) 不是 JSON 安全的 會丟失 constructor,所有的構造函數(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ǎng)頁元素接收事件的順序,"DOM2級事件"規(guī)定的事件流包括三個階段:事件捕獲階段、處于目標階段、事件冒泡階段。首先發(fā)生的事件捕獲,為截獲事件提供機會。然后是實際的目標接受事件。最后一個階段是時間冒泡階段,可以在這個階段對事件做出響應。雖然捕獲階段在規(guī)范中規(guī)定不允許響應事件,但是實際上還是會執(zhí)行,所以有兩次機會獲取到目標對象。
<!DOCTYPE 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('父級 冒泡');
}, false);
parEle.addEventListener('click', function () {
alert('父級 捕獲');
}, true);
sonEle.addEventListener('click', function () {
alert('子級冒泡');
}, false);
sonEle.addEventListener('click', function () {
alert('子級捕獲');
}, true);
</script>
當容器元素及嵌套元素,即在捕獲階段又在冒泡階段調用事件處理程序時:事件按DOM事件流的順序執(zhí)行事件處理程序:
父級捕獲 子級冒泡 子級捕獲 父級冒泡
且當事件處于目標階段時,事件調用順序決定于綁定事件的書寫順序,按上面的例子為,先調用冒泡階段的事件處理程序,再調用捕獲階段的事件處理程序。依次alert出“子集冒泡”,“子集捕獲”。
IE 兼容
attchEvent('on' + type, handler) detachEvent('on' + type, handler)
參考鏈接
https://juejin.im/entry/5826ba9d0ce4630056f85e07
問:事件是如何實現(xiàn)的?
基于發(fā)布訂閱模式,就是在瀏覽器加載的時候會讀取事件相關的代碼,但是只有實際等到具體的事件觸發(fā)的時候才會執(zhí)行。
比如點擊按鈕,這是個事件(Event),而負責處理事件的代碼段通常被稱為事件處理程序(Event Handler),也就是「啟動對話框的顯示」這個動作。
在 Web 端,我們常見的就是 DOM 事件:
DOM0 級事件,直接在 html 元素上綁定 on-event,比如 onclick,取消的話,dom.onclick = null,同一個事件只能有一個處理程序,后面的會覆蓋前面的。 DOM2 級事件,通過 addEventListener 注冊事件,通過 removeEventListener 來刪除事件,一個事件可以有多個事件處理程序,按順序執(zhí)行,捕獲事件和冒泡事件 DOM3級事件,增加了事件類型,比如 UI 事件,焦點事件,鼠標事件
參考鏈接
https://zhuanlan.zhihu.com/p/73091706
問:new 一個函數(shù)發(fā)生了什么
構造調用:
創(chuàng)造一個全新的對象 這個對象會被執(zhí)行 [[Prototype]] 連接,將這個新對象的 [[Prototype]] 鏈接到這個構造函數(shù).prototype 所指向的對象 這個新對象會綁定到函數(shù)調用的 this 如果函數(shù)沒有返回其他對象,那么 new 表達式中的函數(shù)調用會自動返回這個新對象
問:new 一個構造函數(shù),如果函數(shù)返回 return {} 、 return null , return 1 , return true 會發(fā)生什么情況?
如果函數(shù)返回一個對象,那么new 這個函數(shù)調用返回這個函數(shù)的返回對象,否則返回 new 創(chuàng)建的新對象
問:symbol 有什么用處
可以用來表示一個獨一無二的變量防止命名沖突。但是面試官問還有嗎?我沒想出其他的用處就直接答我不知道了,還可以利用 symbol 不會被常規(guī)的方法(除了 Object.getOwnPropertySymbols 外)遍歷到,所以可以用來模擬私有變量。
主要用來提供遍歷接口,布置了 symbol.iterator 的對象才可以使用 for···of 循環(huán),可以統(tǒng)一處理數(shù)據(jù)結構。調用之后回返回一個遍歷器對象,包含有一個 next 方法,使用 next 方法后有兩個返回值 value 和 done 分別表示函數(shù)當前執(zhí)行位置的值和是否遍歷完畢。
Symbol.for() 可以在全局訪問 symbol
(3)問:閉包是什么?
閉包是指有權訪問另外一個函數(shù)作用域中的變量的函數(shù)
JavaScript代碼的整個執(zhí)行過程,分為兩個階段,代碼編譯階段與代碼執(zhí)行階段。編譯階段由編譯器完成,將代碼翻譯成可執(zhí)行代碼,這個階段作用域規(guī)則會確定。執(zhí)行階段由引擎完成,主要任務是執(zhí)行可執(zhí)行代碼,執(zhí)行上下文在這個階段創(chuàng)建。

什么是作業(yè)域?
ES5 中只存在兩種作用域:全局作用域和函數(shù)作用域。在 JavaScript 中,我們將作用域定義為一套規(guī)則,這套規(guī)則用來管理引擎如何在當前作用域以及嵌套子作用域中根據(jù)標識符名稱進行變量(變量名或者函數(shù)名)查找
什么是作用域鏈?
首先要了解作用域鏈,當訪問一個變量時,編譯器在執(zhí)行這段代碼時,會首先從當前的作用域中查找是否有這個標識符,如果沒有找到,就會去父作用域查找,如果父作用域還沒找到繼續(xù)向上查找,直到全局作用域為止,,而作用域鏈,就是有當前作用域與上層作用域的一系列變量對象組成,它保證了當前執(zhí)行的作用域對符合訪問權限的變量和函數(shù)的有序訪問。
閉包產生的本質
當前環(huán)境中存在指向父級作用域的引用
什么是閉包
閉包是一種特殊的對象,它由兩部分組成:執(zhí)行上下文(代號 A),以及在該執(zhí)行上下文中創(chuàng)建的函數(shù) (代號 B),當 B 執(zhí)行時,如果訪問了 A 中變量對象的值,那么閉包就會產生,且在 Chrome 中使用這個執(zhí)行上下文 A 的函數(shù)名代指閉包。
一般如何產生閉包
返回函數(shù) 函數(shù)當做參數(shù)傳遞
閉包的應用場景
柯里化 bind 模塊
參考文章
https://segmentfault.com/a/1190000012646221
問:NaN 是什么,用 typeof 會輸出什么?
Not a Number,表示非數(shù)字,typeof NaN === 'number'
(2)問:JS 隱式轉換,顯示轉換
一般非基礎類型進行轉換時會先調用 valueOf,如果 valueOf 無法返回基本類型值,就會調用 toString
字符串和數(shù)字
"+" 操作符,如果有一個為字符串,那么都轉化到字符串然后執(zhí)行字符串拼接 "-" 操作符,轉換為數(shù)字,相減 (-a, a * 1 a/1) 都能進行隱式強制類型轉換
[] + {} 和 {} + []
布爾值到數(shù)字
1 + true = 2 1 + false = 1
轉換為布爾值
for 中第二個 while if 三元表達式 || (邏輯或) && (邏輯與)左邊的操作數(shù)
符號
不能被轉換為數(shù)字 能被轉換為布爾值(都是 true) 可以被轉換成字符串 "Symbol(cool)"
寬松相等和嚴格相等
寬松相等允許進行強制類型轉換,而嚴格相等不允許
字符串與數(shù)字
轉換為數(shù)字然后比較
其他類型與布爾類型
先把布爾類型轉換為數(shù)字,然后繼續(xù)進行比較
對象與非對象
執(zhí)行對象的 ToPrimitive(對象)然后繼續(xù)進行比較
假值列表
undefined null false +0, -0, NaN ""
(2)問:了解 this 嘛,bind,call,apply 具體指什么
它們都是函數(shù)的方法
call: Array.prototype.call(this, args1, args2])apply: Array.prototype.apply(this, [args1, args2]) :ES6 之前用來展開數(shù)組調用, foo.appy(null, []),ES6 之后使用 ... 操作符
New 綁定 > 顯示綁定 > 隱式綁定 > 默認綁定 如果需要使用 bind 的柯里化和 apply 的數(shù)組解構,綁定到 null,盡可能使用 Object.create(null) 創(chuàng)建一個 DMZ 對象
四條規(guī)則:
默認綁定,沒有其他修飾(bind、apply、call),在非嚴格模式下定義指向全局對象,在嚴格模式下定義指向 undefined
function foo() {
console.log(this.a);
}
var a = 2;
foo();
隱式綁定:調用位置是否有上下文對象,或者是否被某個對象擁有或者包含,那么隱式綁定規(guī)則會把函數(shù)調用中的 this 綁定到這個上下文對象。而且,對象屬性鏈只有上一層或者說最后一層在調用位置中起作用
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo,
}
obj.foo(); // 2
顯示綁定:通過在函數(shù)上運行 call 和 apply ,來顯示的綁定 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 調用函數(shù)會創(chuàng)建一個全新的對象,并將這個對象綁定到函數(shù)調用的 this。
New 綁定時,如果是 new 一個硬綁定函數(shù),那么會用 new 新建的對象替換這個硬綁定 this,
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a)
(4)問:手寫 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)問:setTimeout(fn, 0)多久才執(zhí)行,Event Loop
setTimeout 按照順序放到隊列里面,然后等待函數(shù)調用棧清空之后才開始執(zhí)行,而這些操作進入隊列的順序,則由設定的延遲時間來決定
手寫題: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);
}
}
}
問:js腳本加載問題,async、defer問題
如果依賴其他腳本和 DOM 結果,使用 defer 如果與 DOM 和其他腳本依賴不強時,使用 async
參考資料
問:如何判斷一個對象是不是空對象?
Object.keys(obj).length === 0
問: <script src=’xxx’ ’xxx’/>外部js文件先加載還是onload先執(zhí)行,為什么?
onload 是所以加載完成之后執(zhí)行的
問:怎么加事件監(jiān)聽,兩種
onclick 和 addEventListener
問:事件傳播機制(事件流)
冒泡和捕獲
(4)問:說一下原型鏈和原型鏈的繼承吧
所有普通的 [[Prototype]] 鏈最終都會指向內置的 Object.prototype,其包含了 JavaScript 中許多通用的功能 為什么能創(chuàng)建 “類”,借助一種特殊的屬性:所有的函數(shù)默認都會擁有一個名為 prototype 的共有且不可枚舉的屬性,它會指向另外一個對象,這個對象通常被稱為函數(shù)的原型
function Person(name) {
this.name = name;
}
Person.prototype.constructor = Person
在發(fā)生 new 構造函數(shù)調用時,會將創(chuàng)建的新對象的 [[Prototype]] 鏈接到 Person.prototype 指向的對象,這個機制就被稱為原型鏈繼承
方法定義在原型上,屬性定義在構造函數(shù)上
首先要說一下 JS 原型和實例的關系:每個構造函數(shù) (constructor)都有一個原型對象(prototype),這個原型對象包含一個指向此構造函數(shù)的指針屬性,通過 new 進行構造函數(shù)調用生成的實例,此實例包含一個指向原型對象的指針,也就是通過 [[Prototype]] 鏈接到了這個原型對象
然后說一下 JS 中屬性的查找:當我們試圖引用實例對象的某個屬性時,是按照這樣的方式去查找的,首先查找實例對象上是否有這個屬性,如果沒有找到,就去構造這個實例對象的構造函數(shù)的 prototype 所指向的對象上去查找,如果還找不到,就從這個 prototype 對象所指向的構造函數(shù)的 prototype 原型對象上去查找
什么是原型鏈:這樣逐級查找形似一個鏈條,且通過 [[Prototype]] 屬性鏈接,所以被稱為原型鏈
什么是原型鏈繼承,類比類的繼承:當有兩個構造函數(shù) A 和 B,將一個構造函數(shù) A 的原型對象的,通過其 [[Prototype]] 屬性鏈接到另外一個 B 構造函數(shù)的原型對象時,這個過程被稱之為原型繼承。
標準答案更正確的解釋
什么是原型鏈?
當對象查找一個屬性的時候,如果沒有在自身找到,那么就會查找自身的原型,如果原型還沒有找到,那么會繼續(xù)查找原型的原型,直到找到 Object.prototype 的原型時,此時原型為 null,查找停止。這種通過 通過原型鏈接的逐級向上的查找鏈被稱為原型鏈
什么是原型繼承?
一個對象可以使用另外一個對象的屬性或者方法,就稱之為繼承。具體是通過將這個對象的原型設置為另外一個對象,這樣根據(jù)原型鏈的規(guī)則,如果查找一個對象屬性且在自身不存在時,就會查找另外一個對象,相當于一個對象可以使用另外一個對象的屬性和方法了。
參考鏈接
https://zhuanlan.zhihu.com/p/35790971
問:說下對 JS 的了解吧
是基于原型的動態(tài)語言,主要獨特特性有 this、原型和原型鏈。
JS 嚴格意義上來說分為:語言標準部分(ECMAScript)+ 宿主環(huán)境部分
語言標準部分
2015 年發(fā)布 ES6,引入諸多新特性使得能夠編寫大型項目變成可能,標準自 2015 之后以年號代號,每年一更
宿主環(huán)境部分
在瀏覽器宿主環(huán)境包括 DOM + BOM 等 在 Node,宿主環(huán)境包括一些文件、數(shù)據(jù)庫、網(wǎng)絡、與操作系統(tǒng)的交互等
問:數(shù)組能夠調用的函數(shù)有那些?
push pop splice slice shift unshift sort find findIndex map/filter/reduce 等函數(shù)式編程方法 還有一些原型鏈上的方法:toString/valudOf
問:如何判斷數(shù)組類型
Array.isArray
問: 函數(shù)中的arguments是數(shù)組嗎?類數(shù)組轉數(shù)組的方法了解一下?
是類數(shù)組,是屬于鴨子類型的范疇,長得像數(shù)組,
... 運算符 Array.from Array.prototype.slice.apply(arguments)
問:用過 TypeScript 嗎?它的作用是什么?
為 JS 添加類型支持,以及提供最新版的 ES 語法的支持,是的利于團隊協(xié)作和排錯,開發(fā)大型項目
問:PWA使用過嗎?serviceWorker的使用原理是啥?
漸進式網(wǎng)絡應用(PWA)是谷歌在2015年底提出的概念。基本上算是web應用程序,但在外觀和感覺上與原生app類似。支持PWA的網(wǎng)站可以提供脫機工作、推送通知和設備硬件訪問等功能。
Service Worker是瀏覽器在后臺獨立于網(wǎng)頁運行的腳本,它打開了通向不需要網(wǎng)頁或用戶交互的功能的大門。現(xiàn)在,它們已包括如推送通知和后臺同步等功能。將來,Service Worker將會支持如定期同步或地理圍欄等其他功能。本教程討論的核心功能是攔截和處理網(wǎng)絡請求,包括通過程序來管理緩存中的響應。
參考鏈接
https://juejin.im/post/5e26aa785188254c257c462d#heading-8
問:ES6 之前使用 prototype 實現(xiàn)繼承
Object.create() 會創(chuàng)建一個 “新” 對象,然后將此對象內部的 [[Prototype]] 關聯(lián)到你指定的對象(Foo.prototype)。Object.create(null) 創(chuàng)建一個空 [[Prototype]] 鏈接的對象,這個對象無法進行委托。
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function () {
return this.name;
}
// 繼承屬性,通過借用構造函數(shù)調用
function Bar(name, label) {
Foo.call(this, name);
this.label = label;
}
// 繼承方法,創(chuàng)建備份
Bar.prototype = Object.create(Foo.prototype);
// 必須設置回正確的構造函數(shù),要不然在會發(fā)生判斷類型出錯
Bar.prototype.constructor = Bar;
// 必須在上一步之后
Bar.prototype.myLabel = function () {
return this.label;
}
var a = new Bar("a", "obj a");
a.myName(); // "a"
a.myLabel(); // "obj a"
問:如果一個構造函數(shù),bind了一個對象,用這個構造函數(shù)創(chuàng)建出的實例會繼承這個對象的屬性嗎?為什么?
不會繼承,因為根據(jù) this 綁定四大規(guī)則,new 綁定的優(yōu)先級高于 bind 顯示綁定,通過 new 進行構造函數(shù)調用時,會創(chuàng)建一個新對象,這個新對象會代替 bind 的對象綁定,作為此函數(shù)的 this,并且在此函數(shù)沒有返回對象的情況下,返回這個新建的對象
(3)箭頭函數(shù)和普通函數(shù)有啥區(qū)別?箭頭函數(shù)能當構造函數(shù)嗎?
普通函數(shù)通過 function 關鍵字定義, this 無法結合詞法作用域使用,在運行時綁定,只取決于函數(shù)的調用方式,在哪里被調用,調用位置。(取決于調用者,和是否獨立運行) 箭頭函數(shù)使用被稱為 “胖箭頭” 的操作 =>定義,箭頭函數(shù)不應用普通函數(shù) this 綁定的四種規(guī)則,而是根據(jù)外層(函數(shù)或全局)的作用域來決定 this,且箭頭函數(shù)的綁定無法被修改(new 也不行)。一個函數(shù)內部有兩個方法:[[Call]] 和 [[Construct]],在通過 new 進行函數(shù)調用時,會執(zhí)行 [[construct]] 方法,創(chuàng)建一個實例對象,然后再執(zhí)行這個函數(shù)體,將函數(shù)的 this 綁定在這個實例對象上 當直接調用時,執(zhí)行 [[Call]] 方法,直接執(zhí)行函數(shù)體 箭頭函數(shù)沒有 [[Construct]] 方法,不能被用作構造函數(shù)調用,當使用 new 進行函數(shù)調用時會報錯。 箭頭函數(shù)常用于回調函數(shù)中,包括事件處理器或定時器 箭頭函數(shù)和 var self = this,都試圖取代傳統(tǒng)的 this 運行機制,將 this 的綁定拉回到詞法作用域 沒有原型、沒有 this、沒有 super,沒有 arguments,沒有 new.target 不能通過 new 關鍵字調用
function foo() {
return (a) => {
console.log(this.a);
}
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2);
參考資料
https://segmentfault.com/a/1190000015162781
問:知道 ES6 的 Class 嘛?Static 關鍵字有了解嘛
為這個類的函數(shù)對象直接添加方法,而不是加在這個函數(shù)對象的原型對象上
(3)問:事件循環(huán)機制 (Event Loop)
事件循環(huán)機制從整體上告訴了我們 JavaScript 代碼的執(zhí)行順序Event Loop即事件循環(huán),是指瀏覽器或Node的一種解決javaScript單線程運行時不會阻塞的一種機制,也就是我們經常使用異步的原理。
先執(zhí)行宏任務隊列,然后執(zhí)行微任務隊列,然后開始下一輪事件循環(huán),繼續(xù)先執(zhí)行宏任務隊列,再執(zhí)行微任務隊列。
宏任務:script/setTimeout/setInterval/setImmediate/ I/O / UI Rendering 微任務:process.nextTick()/Promise
上訴的 setTimeout 和 setInterval 等都是任務源,真正進入任務隊列的是他們分發(fā)的任務。
優(yōu)先級
setTimeout = setInterval 一個隊列 setTimeout > setImmediate process.nextTick > Promise
for (const macroTask of macroTaskQueue) {
handleMacroTask();
for (const microTask of microTaskQueue) {
handleMicroTask(microTask);
}
}
參考鏈接
https://juejin.im/post/59e85eebf265da430d571f89
(2)手寫題:數(shù)組扁平化
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result = result.concat(arr[i]);
}
}
return result;
}
const a = [1, [2, [3, 4]]];
console.log(flatten(a));
手寫題:實現(xiàn)柯里化
預先設置一些參數(shù)
柯里化是什么:是指這樣一個函數(shù),它接收函數(shù) A,并且能返回一個新的函數(shù),這個新的函數(shù)能夠處理函數(shù) A 的剩余參數(shù)
function createCurry(func, args) {
var argity = func.length;
var args = args || [];
return function () {
var _args = [].slice.apply(arguments);
args.push(..._args);
if (args.length < argity) {
return createCurry.call(this, func, args);
}
return func.apply(this, args);
}
}
手寫題:數(shù)組去重
Array.from(new Set([1, 1, 2, 2]))
問:let 閉包
let 會產生臨時性死區(qū),在當前的執(zhí)行上下文中,會進行變量提升,但是未被初始化,所以在執(zhí)行上下文執(zhí)行階段,執(zhí)行代碼如果還沒有執(zhí)行到變量賦值,就引用此變量就會報錯,此變量未初始化。
問:變量提升
函數(shù)在運行的時候,會首先創(chuàng)建執(zhí)行上下文,然后將執(zhí)行上下文入棧,然后當此執(zhí)行上下文處于棧頂時,開始運行執(zhí)行上下文。
在創(chuàng)建執(zhí)行上下文的過程中會做三件事:創(chuàng)建變量對象,創(chuàng)建作用域鏈,確定 this 指向,其中創(chuàng)建變量對象的過程中,首先會為 arguments 創(chuàng)建一個屬性,值為 arguments,然后會掃碼 function 函數(shù)聲明,創(chuàng)建一個同名屬性,值為函數(shù)的引用,接著會掃碼 var 變量聲明,創(chuàng)建一個同名屬性,值為 undefined,這就是變量提升。
instance 如何使用
左邊可以是任意值,右邊只能是函數(shù)
'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
1.看到這里了就點個在看支持下吧,你的「點贊,在看」是我創(chuàng)作的動力。
2.關注公眾號
程序員成長指北,回復「1」加入高級前端交流群!「在這里有好多 前端 開發(fā)者,會討論 前端 Node 知識,互相學習」!3.也可添加微信【ikoala520】,一起成長。
“在看轉發(fā)”是最大的支持
