主頁 > 前端設計 > 【面試利器】 原生JS靈魂拷問,你能答上多少(一)

【面試利器】 原生JS靈魂拷問,你能答上多少(一)

2021-10-20 13:08:20 前端設計

前言

目前的前端世界,三大框架橫行,原生JavaScript所用越來越少,但我認為JavaScript作為每一個前端工程師的立身之本,學再多遍都不為過,

因此我決定整理JavaScript中容易忽視或者混淆的知識點,寫一系列文章,以靈魂追問的方式,系統且完整的帶大家遨游不一樣的JavaScript

JS型別之問——檢測篇

第一問:js中的資料型別有哪些?

  1. 原始資料型別:共有7種
Boolean Number String undefined null Bigint Symbol
  1. 參考資料型別:1種
Object物件(包括普通Object、Function、Array、Date、RegExp、Math)

第二問:你真的懂typeof嗎?

  1. typeof的作用?

    區分資料型別,可以回傳7種資料型別:number、string、boolean、undefined、object、function,以及ES6新增的symbol

  2. typeof能正確區分資料型別嗎?

    不能,對于原始型別,除null都可以正確判斷;對于參考型別,除function外,都會回傳"object"

  3. typeof注意事項

    • typeof回傳值為·格式,注意類似這種考題: typeof(typeof(undefined)) -> "string"
    • typeof未定義的變數不會報錯,回傳"undefiend"
    • typeof(null) -> "object": 遺留已久的bug
    • typeof無法區別陣列與普通物件: typeof([]) -> "object"
    • typeof(NaN) -> "number"

習題

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({})));

答案

undefined // b未定義,回傳undefined
undefined
number // NaN 為number型別
object
number // +a 型別轉換為NaN
boolean
string
string // typeof(null) -> "object"; typeof("object") -> "string"
string

第三問:什么是instanceof?你能模擬實作一個instanceof嗎?

  1. instanceof可以準確判斷物件的型別,其內部機制是判斷物件的原型鏈上是否存在該型別的原型,
  2. instanceof常用來判斷A是否為B的實體:
// A是B的實體,回傳true,否則回傳false
// 判斷A的原型鏈上是否有B的原型
A instaceof B
  1. 模擬實作instanceof
    思想:沿原型鏈往上查找
function instance_of(Case, Constructor) {
    // 基本資料型別回傳false
    // 兼容一下函式物件
    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);
    }
}

測驗:

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

第四問:如何區分陣列與物件?instanceof判斷是否是陣列可靠嗎?

  1. Array.isArray()
  2. 如果不存在Array.isArray()呢?可以借助Object.prototype.toString.call()實作,這種實作方式兼容性最好
if (!Array.isArray) {
    Array.isArray = function(o) {
        return typeof(o) === 'object' 
               && Object.prototype.toString.call(o) === '[object Array]';
    }
}
  1. instanceof判斷
    判斷方式
// 如果為true,則arr為陣列
arr instanceof Array

instanceof判斷陣列如此之簡單,為何不推薦使用那?

instanceof運算子的問題在于,如果網頁中存在多個iframe,那便會存在多個Array建構式,此時判斷是否是陣列會存在問題,

更詳細的內容可以參考博文:JavaScript為啥不用instanceof檢測陣列

第五問:如何判斷一個數是否為NaN?

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

NaN === NaN // false

鑒于這個獨特的特性,可以手撕一個比較簡單的判斷函式

function isNaN(x) {
    return x != x;
}
  • isNaN方法:不推薦使用,MDN對它的介紹是:isNaN函式內包含一些非常有趣的規則,

    但為了避免一些面試官出一些冷門題目,稍微介紹一下,isNaN的有趣機制:會先判斷引數是不是Number型別,如果不是Number型別會嘗試將這個引數轉換為Number型別,之后再去判斷是不是NaN

    舉個例子:

    // 是不是很有趣
    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
    

    isNaN的結果很大程度上取決于Number()型別轉換,后面會專門有一部分來介紹,

  • Number.isNaN(推薦使用)
    isNaN()相比,Number.isNaN()不會自行將引數轉換成數字,只有在引數是值為NaN的數字時,才會回傳 true

第六問:如何實作一個可靠的型別判斷函式

利用Object.prototype.toString.call([value]),可以精準判斷資料型別,大家可以根據這個原理封裝一個自己的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]

JS型別之問——轉換篇

第七問:toString和valueOf的什么情況下會自動呼叫,優先級怎樣?

  1. 介紹:這兩個方法屬于Object物件,是為了解決JavaScript值運算與顯示的問題,為了更適合自身功能,很多JavaScript內置物件都重寫了這兩個方法,
  2. toString(): 回傳當前物件的字串形式;valueOf(): 回傳該物件的原始值
  3. 各個型別下兩個方法回傳值情況對比
型別valueOftoString
Array[1,2,3](3) [1, 2, 3]1,2,3
Object物件本身[object Object]
Boolean型別Boolean值“true"或"false”
Function函式本身function fnName(){code}
Number數值數值的字符換表示
Date毫米格式時間戳GMT格式時間字串
  1. 自動呼叫

    隱式轉換時會自動呼叫toString和valueOf方法,兩者優先級如下:

    • 在進行object格式轉換時,優先呼叫toString方法
    • 強制轉化為字串型別時,優先呼叫toString方法
    • 強制轉換為數值型別時,優先呼叫valueOf方法
    • 使用運算子運算子情況下,valueOf優先級高于toStirng
  2. 經典案例

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

console.log(obj[a]);
console.log(obj[b]);

JavaScript中物件的鍵都為字串格式,需要由物件轉換為字串,呼叫Object上的toString方法,

根據轉換規則,ab都轉換為[object Object],因此obj[a]obj[b]操作的是同一個鍵,最終列印兩個200

第八問:你知道物件轉換成原始值是什么流程嗎?

物件轉換成數字型別,會按照下面的步驟執行(三步走戰略):

  1. 先呼叫物件的Symbol.toPrimitive方法,如果不存在這個方法(toPrimitive,可以參考博客從ECMA規范徹底理解 JavaScript 型別轉換
    )
  2. 呼叫物件的valueOf(),如果轉換為原始型別,則回傳
  3. 呼叫物件的toString(),如果轉換為原始型別,則回傳
  4. 如果都沒有回傳原始型別,會報錯

第九問:你能理清型別轉換嗎?

首先需要知道:在JavaScript中,只有三種型別的轉換

  • 轉換為Number型別: Number() / parseFloat() / parseInt()
  • 轉化為String型別:String() / toString()
  • 轉化為Boolean型別: Boolean()

因此遇到型別轉換問題,只需要弄清楚在什么場景之下轉換成那種型別即可,

轉換為boolean

  • 顯式:Boolean方法可以顯式將值轉換為布爾型別
  • 隱式:通常在邏輯判斷或者有邏輯運算子時觸發(|| && !
Boolean(1)   // 顯式型別轉換
if (1) {}    // 邏輯判斷型別觸發隱式轉換
!!1          // 邏輯運算子觸發隱式轉換
1 || 'hello' // 邏輯運算子觸發隱式轉換

boolean型別只有truefalse兩種值,

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

轉化為string

  • 顯式:String方法可以顯式將值轉換為字串
  • 隱式:+運算子發下有兩種情況可以觸發(這里的+并非取正數運算子)
    • 有一側運算元為string型別
    • 有一側運算元為物件

轉化為string型別的本質:需要轉換為string的部分呼叫自身的toString方法(null/undefined回傳字串格式的null和undefined)

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

1 + '1' // 11
1 + {} // 1[object Object]

轉化為number

  • 顯式:Number方法可以顯式將值轉化為數字型別

Number的具體規則,ES5規范中給了一個對應的結果表

型別結果
undefinedNaN
null+0
BooleanNaN
undefined引數為true回傳1;false回傳+0
Number回傳與之相等的值
String有些復雜,舉例說明
Object三步走戰略
  1. String: 空字串回傳0,出現任何一個非有效數字字符,回傳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
  1. Object
    參考第八問,最后對回傳的原始值執行Number方法
  • 隱式:number的隱式型別轉換比較復雜,對需要隱式轉換的部分執行Number
    • 比較操作(<, >, <=, >=)
    • 按位操作(| & ^ ~)
    • 算數操作(+ - * / %) 注意:+的運算元存在字串時,為string轉換
    • 一元+-操作

第十問:== 與 === 的區別

  1. ===是嚴格相等,要求資料型別和值都要相等;==只需要值相等,
  2. ==會發生隱式型別轉換,===不會發生隱式型別轉換,
  3. ==的轉換規則:

null, undefined在==下互相等且自身等

被比較數B
NumberStringBooleanObject
比較數A
NumberA === BA === ToNumber(B)A === ToNumber(B)A == ToPrimitive(B)
StringToNumber(A) === BToNumber(A) === ToNumber(B)ToNumber(A) === ToNumber(B)ToPrimitive(B) == A
BooleanToNumber(A) === BToNumber(A) === ToNumber(B)ToNumber(A) === ToNumber(B)ToNumber(A) == ToPrimitive(B)
ObjectToPrimitive(A) == BToPrimitive(A) == BToPrimitive(A) == ToPrimitive(B)A === B
在上面的表格中,`ToNumber(A)`嘗試在比較前將引數`A(Number)`轉換為數字,`ToPrimitive(A)`通過嘗試呼叫A的`A.toString()`和 `A.valueOf()`方法,將引數A轉換為原始值(`Primitive`),

第十一問:1 + {}{} + 1的輸出結果分別是什么?

通過上面的學習,當物件與其他元素相加時,物件會發生隱式型別轉換,執行三步走戰略:

  1. 執行toPrimitive,判斷物件是否有Symbol.toPrimitive,沒有該方法
  2. 執行({}).toString(),回傳"[object Object]",回傳結果為原始值,轉換結束

此時 1 + {},一側為string型別,將1進行ToString()轉化為"1",最終輸出結果為 "1[object Object]"

注意{} + 1輸出的結果會和1 + {}一樣嗎?

{}JavaScript中,不止可以作為物件定義,也可以作為代碼塊的定義,js引擎會把{} + 1決議成1個代碼塊和1個+1,最終輸出結果為 1

答案

1[object Object]
1

常見習題

  1. {} + {}

    無法決議成兩個代碼塊,兩個物件都經過三步走戰略,轉化為原始值[object Object],最終結果[object Object][object Object]

  2. [] + {}

    陣列是特殊的物件,也需要三步走戰略,arr.valueOf()仍是arr,所以需要繼續呼叫toString()方法,[]回傳"",最侄訓傳結果為[object Object]

  3. [] + []

    兩個arr經過三步走都回傳"",最終結果""

  4. {} + []

    類似于{} + 1{} + [] 相當于 {}; + [],一元+強制將""隱式轉換為0,最終結果為0

第十二問:Object.is() 與 === 區別

Object.is()來進行相等判斷時,一般情況下與 === 相同,它處理了一些特殊的情況,比如+0-0不再相等,兩個NaN是相等的,

第十三問:你能靈活運用parseInt 與 parseFloat嗎

  1. parseInt:從數字類開始看,看到非數字類為止,回傳原來的數,(小數點也屬于非有效數字)
parseInt('123x') -> 123
parseInt('-023x') -> -23
parseInt('1.1') -> 1
parseInt('-abc') -> NaN
parseInt('x123') -> NaN
  1. parseInt(string, radix)還有第二個引數radix表示要決議數字的基數,取值為2~36(默認值為10)
  2. parseFloatparseInt類似,只不過它回傳浮點數,從數字類開始看,看到除了第一個點以外的非數字類為截止,回傳前面的數,

網紅題:[‘1’,‘2’,‘3’].map(parseInt)

這個網紅題考察的就是parseInt有兩個引數,map傳入的函式可執行三個引數:

// ele   遍歷的元素
// index 遍歷的元素索引
// arr   陣列
arr.map(function(ele, index, arr){})

[‘1’,‘2’,‘3’].map(parseInt)相當于執行了以下三次程序:

parseInt('1', 0, ['1','2','3'])
parseInt('2', 1, ['1','2','3'])
parseInt('3', 2, ['1','2','3'])
  • parseInt('1', 0, ['1','2','3']): radix為0時,默認取10,最后回傳1
  • parseInt('2', 1, ['1','2','3']): radix取值為2~36,回傳NaN
  • parseInt('3', 2, ['1','2','3']): radix取值為2,二進制只包括0,1,回傳NaN

第十四問:如何讓if(a == 1 && a == 2)條件成立?

valueOf的應用

var a = {
    value: 0,
    valueOf: function() {
        this.value++;
        return this.value;
    }
};
console.log(a == 1 && a == 2);//true

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/326212.html

標籤:其他

上一篇:類似于"左聯"的生產方式,在產量上有兩個集合。

下一篇:左視圖將占據水平LinearLayout中的所有空間

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more