<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>

          原生JavaScript靈魂拷問,你能答上多少

          共 9536字,需瀏覽 20分鐘

           ·

          2022-01-14 11:01


          大廠技術(shù)??高級(jí)前端??Node進(jìn)階

          點(diǎn)擊上方?程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          前言

          當(dāng)下的前端開發(fā),三大框架三分天下,框架的簡(jiǎn)單、強(qiáng)大讓我們欲罷不能,使用原生 JavaScript 越來越少。

          但我認(rèn)為 JavaScript 作為每一個(gè)前端工程師的立身之本,不止要學(xué)會(huì),還要學(xué)好、學(xué)精,學(xué)再多遍都不為過。

          另一方面,前端面試中,越來越重視原生 JavaScript 的考察,其所占比例也越來越高。

          我抓取了??蜕辖衲甑木€上面試題和面經(jīng),大約 500 左右道題,原生 JavaScript 的難點(diǎn)(閉包,eventLoop,this,手撕原生JS)考察的頻率非常高。

          完整的分析我還正在趕工中,希望大家到時(shí)候可以來支持一下。

          因此我決定整理JavaScript中容易忽視或者混淆的知識(shí)點(diǎn),寫一系列篇文章,以靈魂拷問的方式,系統(tǒng)且完整的帶大家遨游原生 JavaScript 的世界,希望能給大家?guī)硪恍┦斋@。

          JS類型之問——概念與檢測(cè)篇

          1.JS中的數(shù)據(jù)類型有哪些?

          1. 基本數(shù)據(jù)類型:共有7種
          Boolean?Number?String?undefined?null?Bigint?Symbol
          復(fù)制代碼

          SymbolES6 引入的一種新的原始值,表示獨(dú)一無二的值,主要為了解決屬性名沖突問題。

          BigintES2020 新增加,是比 Number 類型的整數(shù)范圍更大。

          1. 引用數(shù)據(jù)類型:1種
          Object對(duì)象(包括普通ObjectFunction、ArrayDate、RegExp、Math)
          復(fù)制代碼

          2.你真的懂typeof嗎?

          1. typeof的作用?

            區(qū)分?jǐn)?shù)據(jù)類型,可以返回7種數(shù)據(jù)類型:number、string、boolean、undefined、object、function ,以及 ES6 新增的 symbol

          2. typeof 能正確區(qū)分?jǐn)?shù)據(jù)類型嗎?

            不能。對(duì)于原始類型,除 null 都可以正確判斷;對(duì)于引用類型,除 function 外,都會(huì)返回 "object"

          3. typeof 注意事項(xiàng)

            • typeof 返回值為 string 格式,注意類似這種考題: typeof(typeof(undefined)) -> "string"
            • typeof 未定義的變量不會(huì)報(bào)錯(cuò),返回 "undefiend"
            • typeof(null) -> "object": 遺留已久的 bug
            • typeof無法區(qū)別數(shù)組與普通對(duì)象: typeof([]) -> "object"
            • typeof(NaN) -> "number"
          4. 習(xí)題

          console.log(typeof(b));
          console.log(typeof(undefined));?
          console.log(typeof(NaN));?
          console.log(typeof(null));?
          var?a?=?'123abc';?
          console.log(typeof(+a));?
          console.log(typeof(!!a));?
          console.log(typeof(a?+?""));?
          console.log(typeof(typeof(null)));
          console.log(typeof(typeof({})));
          復(fù)制代碼

          答案

          undefined?//?b未定義,返回undefined
          undefined
          number?//?NaN?為number類型
          object
          number?//?+a?類型轉(zhuǎn)換為NaN
          boolean
          string
          string?//?typeof(null)?->?"object";?typeof("object")?->?"string"
          string
          復(fù)制代碼

          3.什么是instanceof?你能模擬實(shí)現(xiàn)一個(gè)instanceof嗎?

          1. `instanceof` 判斷對(duì)象的原型鏈上是否存在構(gòu)造函數(shù)的原型。只能判斷引用類型。
          2. `instanceof` 常用來判斷 `A` 是否為 `B` 的實(shí)例
          //?A是B的實(shí)例,返回true,否則返回false
          //?判斷A的原型鏈上是否有B的原型
          A?instaceof?B
          復(fù)制代碼
          1. 模擬實(shí)現(xiàn) instanceof

          思想:沿原型鏈往上查找

          function?instance_of(Case,?Constructor)?{
          ????//?基本數(shù)據(jù)類型返回false
          ????//?兼容一下函數(shù)對(duì)象
          ????if?((typeof(Case)?!=?'object'?&&?typeof(Case)?!=?'function')?||?Case?==?'null')?return?false;
          ????let?CaseProto?=?Object.getPrototypeOf(Case);
          ????while?(true)?{
          ????????//?查到原型鏈頂端,仍未查到,返回false
          ????????if?(CaseProto?==?null)?return?false;
          ????????//?找到相同的原型
          ????????if?(CaseProto?===?Constructor.prototype)?return?true;
          ????????CaseProto?=?Object.getPrototypeOf(CaseProto);
          ????}
          }
          復(fù)制代碼

          測(cè)試:

          console.log(instance_of(Array,?Object))?//?true
          function?User(name){
          ????this.name?=?name;
          }
          const?user?=?new?User('zc');
          const?vipUser?=?Object.create(user);
          console.log(instance_of(vipUser,?User))?//?true
          復(fù)制代碼

          4.如何區(qū)分?jǐn)?shù)組與對(duì)象?使用instanceof判斷數(shù)組可靠嗎?

          1. `ES6` 提供的新方法 `Array.isArray()`
          2. 如果不存在`Array.isArray()`呢?可以借助`Object.prototype.toString.call()` 進(jìn)行判斷,此方式兼容性最好
          if?(!Array.isArray)?{
          ????Array.isArray?=?function(o)?{
          ????????return?typeof(o)?===?'object'?
          ???????????????&&?Object.prototype.toString.call(o)?===?'[object?Array]';
          ????}
          }
          復(fù)制代碼
          1. instanceof 判斷

          判斷方式

          //?如果為true,則arr為數(shù)組
          arr?instanceof?Array
          復(fù)制代碼

          instanceof 判斷數(shù)組類型如此之簡(jiǎn)單,為何不推薦使用那?

          instanceof 操作符的問題在于,如果網(wǎng)頁(yè)中存在多個(gè) iframe ,那便會(huì)存在多個(gè) Array 構(gòu)造函數(shù),此時(shí)判斷是否是數(shù)組會(huì)存在問題。

          更詳細(xì)的內(nèi)容可以參考博文:JavaScript為啥不用instanceof檢測(cè)數(shù)組[4]

          5.如何判斷一個(gè)數(shù)是否為NaN?

          NaN 有個(gè)非常特殊的特性, NaN 與任何值都不相等,包括它自身

          NaN?===?NaN?//?false
          NaN?==?NaN?//?false
          復(fù)制代碼

          鑒于這個(gè)獨(dú)特的特性,可以手撕一個(gè)比較簡(jiǎn)單的判斷函數(shù)

          function?isNaN(x)?{
          ????return?x?!=?x;
          }
          復(fù)制代碼
          • 全局函數(shù) isNaN 方法:不推薦使用。MDN 對(duì)它的介紹是:isNaN 函數(shù)內(nèi)包含一些非常有趣的規(guī)則。

          但為了避免一些面試官出一些冷門題目,咱們來稍微了解一下 isNaN 的有趣機(jī)制:會(huì)先判斷參數(shù)是不是 Number 類型,如果不是 Number 類型會(huì)嘗試將這個(gè)參數(shù)轉(zhuǎn)換為 Number 類型,之后再去判斷是不是 NaN 。

          舉個(gè)例子:

          //?為什么對(duì)象會(huì)帶來三種不同的結(jié)果
          //?是不是很有趣
          //?具體原因可以參考類型轉(zhuǎn)換篇
          console.log(isNaN([]))?//?false
          console.log(isNaN([1]))?//?false
          console.log(isNaN([1,?2]))?//?true?
          console.log(isNaN(null))?//?false
          console.log(isNaN(undefined))?//?true
          復(fù)制代碼

          isNaN 的結(jié)果很大程度上取決于 Number() 類型轉(zhuǎn)換的結(jié)果,關(guān)于 Number 的轉(zhuǎn)換結(jié)果,后面會(huì)專門有一部分來介紹。

          • Number.isNaN (推薦使用)

          isNaN() 相比,Number.isNaN() 不會(huì)自行將參數(shù)轉(zhuǎn)換成數(shù)字,只有在參數(shù)是值為 NaN 的數(shù)字時(shí),才會(huì)返回 true。

          6.如何實(shí)現(xiàn)一個(gè)功能完善的類型判斷函數(shù)?

          Object.prototype.toString.call([value]) ,可以精準(zhǔn)判斷數(shù)據(jù)類型,因此可以根據(jù)這個(gè)原理封裝一個(gè)自己的 type 方法。

          toString.call(()=>{})???????//?[object?Function]
          toString.call({})???????????//?[object?Object]
          toString.call([])???????????//?[object?Array]
          toString.call('')???????????//?[object?String]
          toString.call(22)???????????//?[object?Number]
          toString.call(undefined)????//?[object?undefined]
          toString.call(null)?????????//?[object?null]
          toString.call(new?Date)?????//?[object?Date]
          toString.call(Math)?????????//?[object?Math]
          toString.call(window)???????//?[object?Window]
          復(fù)制代碼

          JS類型之問——類型轉(zhuǎn)換篇

          7.toString 和 valueOf 方法有什么區(qū)別?

          1. 基礎(chǔ):這兩個(gè)方法屬于 Object 對(duì)象,是為了解決 JavaScript 值運(yùn)算與顯示的問題。為了更適合自身功能,很多 JavaScript 內(nèi)置對(duì)象都重寫了這兩個(gè)方法。
          2. toString(): 返回當(dāng)前對(duì)象的字符串形式;valueOf() : 返回該對(duì)象的原始值
          3. 各個(gè)類型下兩個(gè)方法返回值情況對(duì)比
          類型valueOftoString
          Array[1,2,3]數(shù)組本身[1, 2, 3]1,2,3
          Object對(duì)象本身[object Object]
          Boolean類型Boolean值"true"或"false"
          Function函數(shù)本身function fnName(){code}
          Number數(shù)值數(shù)值的字符換表示
          Date毫米格式時(shí)間戳GMT格式時(shí)間字符串
          1. 調(diào)用優(yōu)先級(jí)

            隱式轉(zhuǎn)換時(shí)會(huì)自動(dòng)調(diào)用 toStringvalueOf 方法,兩者優(yōu)先級(jí)如下:

            • 強(qiáng)制轉(zhuǎn)化為字符串類型時(shí),優(yōu)先調(diào)用 toString 方法
            • 強(qiáng)制轉(zhuǎn)換為數(shù)值類型時(shí),優(yōu)先調(diào)用 valueOf 方法
            • 使用運(yùn)算符操作符情況下,valueOf 優(yōu)先級(jí)高于 toStirng
            • 對(duì)象的類型轉(zhuǎn)換見下一問。

          8.你知道對(duì)象轉(zhuǎn)換成原始值是什么流程嗎 (ToPrimitive)?

          對(duì)象轉(zhuǎn)換成原始類型,會(huì)調(diào)用內(nèi)置的 [ToPrimitive]函數(shù)

          (參考博客: 從ECMA規(guī)范徹底理解 JavaScript 類型轉(zhuǎn)換[5])

          • ToPrimitive 方法接受兩個(gè)參數(shù),一個(gè)是輸入的值 input,一個(gè)是期望轉(zhuǎn)換的類型 PreferredType
            1. 如果未傳入 PreferredType 參數(shù),讓 hint 等于 'default',后面會(huì)將 hint 修改為 'number'
            2. 如果 PreferredTypehint String,讓 hint 等于 'string'
            3. 如果 PreferredTypehint Number,讓 hint 等于 'number'
            4. 返回 OrdinaryToPrimitive(input, hint)
          • OrdinaryToPrimitive(input, hint)
            1. 如果 hint'string',那么就將 methodNames 設(shè)置為 toString、valueOf
            2. 如果 hint'number',那么就將 methodNames 設(shè)置為 valueOf、toString

          methodName 存儲(chǔ)的就是當(dāng)前 preferredType 下的調(diào)用優(yōu)先級(jí),如果全部調(diào)用完畢仍然未轉(zhuǎn)化為原始值,會(huì)發(fā)生報(bào)錯(cuò)。

          9.你能做出下面這個(gè)題嗎?

          const?a?=?{x:1};
          const?b?=?{x:2};
          const?obj?=?{};
          obj[a]?=?100;
          obj[b]?=?200;

          console.log(obj[a]);
          console.log(obj[b]);
          復(fù)制代碼

          有了第七問和第八問的知識(shí),這個(gè)題目就不難了。JavaScript 對(duì)象的鍵必須是字符串,因此分別需要將對(duì)象 ab 轉(zhuǎn)換為 string 類型。具體轉(zhuǎn)換流程:

          //?1.執(zhí)行ToPrimitive
          //?hint?為?string
          ToPrimitive(a,?'hint?String')
          //?2.執(zhí)行OrdinaryToPrimitive
          OrdinaryToPrimitive(a,?'string')
          //?3.返回methodNames
          methodNames?=?['toString',?'valueOf']
          //?4.調(diào)用methodNames里方法
          //?調(diào)用toString
          a.toString()?//?返回[object?Object]
          復(fù)制代碼

          對(duì)象 ab 轉(zhuǎn)換后的結(jié)果都是 [object Object],obj 對(duì)象上只添加了一個(gè)屬性 [object Object]。

          答案

          200
          200
          復(fù)制代碼

          10.你能理清類型轉(zhuǎn)換嗎?

          首先需要知道:在JavaScript中,只有三種類型的轉(zhuǎn)換

          • 轉(zhuǎn)換為Number類型: Number() / parseFloat() / parseInt()
          • 轉(zhuǎn)化為String類型: String() / toString()
          • 轉(zhuǎn)化為Boolean類型: Boolean()

          因此遇到類型轉(zhuǎn)換問題,只需要弄清楚在什么場(chǎng)景之下轉(zhuǎn)換成那種類型即可。

          轉(zhuǎn)換為boolean

          • 顯式:Boolean 方法可以顯式將值轉(zhuǎn)換為布爾類型
          • 隱式:通常在邏輯判斷或者有邏輯運(yùn)算符時(shí)觸發(fā)(|| && !
          Boolean(1)???//?顯式類型轉(zhuǎn)換
          if?(1)?{}????//?邏輯判斷類型觸發(fā)隱式轉(zhuǎn)換
          !!1??????????//?邏輯運(yùn)算符觸發(fā)隱式轉(zhuǎn)換
          1?||?'hello'?//?邏輯運(yùn)算符觸發(fā)隱式轉(zhuǎn)換
          復(fù)制代碼

          boolean 類型只有 truefalse 兩種值。

          除值 0,-0,null,NaN,undefined,或空字符串("")false 外,其余全為 true

          轉(zhuǎn)化為string

          • 顯式:String 方法可以顯式將值轉(zhuǎn)換為字符串
          • 隱式:+ 運(yùn)算符有一側(cè)操作數(shù)為 string 類型時(shí)

          轉(zhuǎn)化為 string 類型的本質(zhì):需要轉(zhuǎn)換為string的部分調(diào)用自身的toString方法(null/undefined返回字符串格式的null和undefined)

          當(dāng)被轉(zhuǎn)換值為對(duì)象時(shí),相當(dāng)于執(zhí)行 ToPrimitive(input, 'hint String')

          String([1,2,3])?//?1,2,3
          String({x:1})?//?[object?Object]

          1?+?'1'?//?11
          1?+?{}?//?1[object?Object]
          復(fù)制代碼

          轉(zhuǎn)化為number

          • 顯式:Number 方法可以顯式將值轉(zhuǎn)化為數(shù)字類型

          Number 的具體規(guī)則,ES5 規(guī)范中給了一個(gè)對(duì)應(yīng)的結(jié)果表[6]

          類型結(jié)果
          undefinedNaN
          null+0
          BooleanNaN
          undefined參數(shù)為true返回1;false返回+0
          Number返回與之相等的值
          String有些復(fù)雜,舉例說明
          Object先執(zhí)行ToPrimitive方法,在執(zhí)行Number類型轉(zhuǎn)換
          1. `String`: 空字符串返回 `0`,出現(xiàn)任何一個(gè)非有效數(shù)字字符,返回 `NaN`
          console.log(Number("1?3"))?//?NaN
          console.log(Number("abc"))?//?NaN
          console.log(Number("1a"))?//?NaN
          console.log(Number("0x11"))?//?17
          console.log(Number("123"))?//?123
          console.log(Number("-123"))?//?-123
          console.log(Number("1.2"))?//?1.2
          復(fù)制代碼
          • 隱式:number的隱式類型轉(zhuǎn)換比較復(fù)雜,對(duì)需要隱式轉(zhuǎn)換的部分執(zhí)行 Number
            • 比較操作(<, >, <=, >=)
            • 按位操作(| & ^ ~)
            • 算數(shù)操作(+ - * / %) 注意:+的操作數(shù)存在字符串時(shí),為string轉(zhuǎn)換
            • 一元 +- 操作

          11.== 的隱式轉(zhuǎn)換規(guī)則

          1. ==: 只需要值相等,無需類型相等;null, undefined== 下互相等且自身等
          2. == 的轉(zhuǎn)換規(guī)則:
          被比較數(shù)B

          比較數(shù)A
          Number
          String
          Boolean
          Object

          在上面的表格中,ToNumber(A) 嘗試在比較前將參數(shù) A 轉(zhuǎn)換為數(shù)字。ToPrimitive(A) 將參數(shù) A 轉(zhuǎn)換為原始值( Primitive )。

          12.1 + {}{} + 1的輸出結(jié)果分別是什么?

          通過上面的學(xué)習(xí),當(dāng)對(duì)象與其他元素相加時(shí),對(duì)象會(huì)調(diào)用 toPrimitive 轉(zhuǎn)化為原始值:

          1. 執(zhí)行 toPrimitive,未傳入 PreferredType,methodNames[valueOf, toString]
          2. 執(zhí)行 ({}).valueOf,返回對(duì)象本身 {},不是原始值
          3. 繼續(xù)執(zhí)行 ({}).toString(),返回 "[object Object]",返回結(jié)果為原始值,轉(zhuǎn)換結(jié)束

          此時(shí) 1 + {},右側(cè)為 string 類型,將 1 進(jìn)行 ToString() 轉(zhuǎn)化為 "1" ,最后字符串連接,結(jié)果為 "1[object Object]"

          注意{} + 1 輸出的結(jié)果會(huì)和 1 + {} 一樣嗎?

          {}JavaScript 中,不止可以作為對(duì)象定義,也可以作為代碼塊的定義。js 引擎會(huì)把 {} + 1 解析成1個(gè)代碼塊和1個(gè)+1,最終輸出結(jié)果為 1

          答案

          1[object?Object]
          1
          復(fù)制代碼

          13.[]與{}的相加的結(jié)果是多少?

          [] + {}

          數(shù)組是特殊的對(duì)象,需要調(diào)用 toPrimitive,轉(zhuǎn)換為原始值

          • 執(zhí)行 toPrimitive,未傳入 PreferredType,methodNames[valueOf, toString]
          • 執(zhí)行 [].valueOf,返回?cái)?shù)組本身
          • 執(zhí)行 [].toString,返回空字符串 ''

          空對(duì)象不做贅述。

          答案

          "[object?Object]"
          復(fù)制代碼

          [] + []

          類似 1 兩個(gè)空數(shù)組都執(zhí)行 toPrimitive,返回兩個(gè)空字符串。

          答案

          ""
          復(fù)制代碼

          {} + []

          類似于 {} + 1,{} + [] 相當(dāng)于 {}; + [],一元 + 強(qiáng)制將 "" 隱式轉(zhuǎn)換為0,最終結(jié)果為0

          答案

          0
          復(fù)制代碼

          {} + {}

          對(duì)于這個(gè)題,我先公布一下答案,之后說一下我的疑問。

          答案

          [object?Object][object?Object]
          復(fù)制代碼

          疑問

          為什么 JavaScript 引擎沒有將前面的 {} 解釋成代碼塊?

          友情提示:由于 {} 可以解釋為代碼塊的形式,有些需要注意的地方,舉個(gè)栗子:

          • 空對(duì)象調(diào)用方法時(shí):{}.toString() 會(huì)報(bào)錯(cuò)
          • 箭頭函數(shù)返回對(duì)象時(shí):let getTempItem = id => { id: id, name: "Temp" } 會(huì)報(bào)錯(cuò)

          14.你能靈活運(yùn)用 parseInt 與 parseFloat 嗎

          1. `parseInt`:從數(shù)字類開始看,看到非數(shù)字類為止,返回原來的數(shù)。\(小數(shù)點(diǎn)也屬于非有效數(shù)字\)
          parseInt('123x')?->?123
          parseInt('-023x')?->?-23
          parseInt('1.1')?->?1
          parseInt('-abc')?->?NaN
          parseInt('x123')?->?NaN
          復(fù)制代碼
          1. parseInt(string, radix) 還有第二個(gè)參數(shù) radix 表示要解析數(shù)字的基數(shù),取值為 2~36 (默認(rèn)值為10)
          2. parseFloatparseInt 類似,只不過它返回浮點(diǎn)數(shù)。從數(shù)字類開始看,看到除了第一個(gè)點(diǎn)以外的非數(shù)字類為截止,返回前面的數(shù)。

          網(wǎng)紅題:['1','2','3'].map(parseInt)

          這個(gè)網(wǎng)紅題考察的就是 parseInt 有兩個(gè)參數(shù)。map 傳入的函數(shù)可執(zhí)行三個(gè)參數(shù):

          //?ele???遍歷的元素
          //?index?遍歷的元素索引
          //?arr???數(shù)組
          arr.map(function(ele,?index,?arr){})
          復(fù)制代碼

          ['1','2','3'].map(parseInt)相當(dāng)于執(zhí)行了以下三次過程:

          parseInt('1',?0,?['1','2','3'])
          parseInt('2',?1,?['1','2','3'])
          parseInt('3',?2,?['1','2','3'])
          復(fù)制代碼
          • parseInt('1', 0, ['1','2','3']): radix為0時(shí),默認(rèn)取10,最后返回1
          • parseInt('2', 1, ['1','2','3']): radix取值為2~36,返回NaN
          • parseInt('3', 2, ['1','2','3']): radix取值為2,二進(jìn)制只包括0,1,返回NaN

          15.如何讓 if(a == 1 && a == 2) 條件成立?

          valueOf 的應(yīng)用

          var?a?=?{
          ????value:?0,
          ????valueOf:?function()?{
          ????????this.value++;
          ????????return?this.value;
          ????}
          };
          console.log(a?==?1?&&?a?==?2);?//true
          復(fù)制代碼


          關(guān)于本文

          作者:戰(zhàn)場(chǎng)小包

          https://juejin.cn/post/7021750693262262308

          最后

          Node 社群


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


          ???“分享、點(diǎn)贊、在看” 支持一波??

          瀏覽 53
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  99人妻久久 | 操逼网站免费看无遮挡 | 亚洲欧洲在线aa观看视频 | 亚洲AV无MM码性色AV无码网站HMM | 精品久久久久成人片中文字幕 |