js面試題整理

因為借鑒的文章比較多加上個人理解整理,沒有備注來源。如侵權比刪!

一、js的數據類型

ES5的5種:

基本數據類型: Number、 String、 Boolean、 undefined、 null

復雜數據類型:Object、function、Array

ES6新增

Symbol 表示獨一無二

ES10新增:

BigLnt 表示任意大的數

ps:存儲區別

基本數據類型和引用數據類型存儲在內存中的位置不同:

  • 基本數據類型存儲在棧中
  • 引用類型的對象存儲于堆中

二、undefined和null的區別

相同點:

1、在if語句中nullundefined都會轉換為false

2、用 == 比較 返回true

null ==undefined // true

不同點:

undefined:代表的含義未定義

null: 表示一個空對象指針

typeof undefined //'undefined'
typeof null // "object"

三、判斷 JavaScript 的數據類型typeof

typeof:type的返回值是字符串(String)

typeof undefined // "undefined"
typeof null // "object"
typeof 1 // "number"
typeof "1" // "string"
typeof Symbol() // "symbol"
typeof function() {} // "function"
typeof {} // "object"

typeof 不能識別 null,如何識別 null?[使用全等即可]

let a = null
a === null

instanceof: 可以用來判斷對象的類型:

instanceof 只能正確判斷引用數據類型 而不能判斷基本數據類型,

原因:其內部運行機制是判斷在其原型鏈中能否找到該類型的原型

或者可以理解為:一個對象是否在一個類的示例上

var date = new Date()
date instanceof Date // true

var number = new Number()
number instanceof Number // true 

var string = new String()
string instanceof String // true

四、js數據類型轉換

強制類型轉換

轉化成字符串 toString() String()

轉換成數字 Number()、 parseInt()、 parseFloat()

轉換成布爾類型 Boolean()

隱式類型轉換

"" + - / % === =

例子:

轉換為數字

Number():可以把任意值轉換成數字,如果有不是數字的值,則會返回NaN
------------------
Number('1')   // 1
Number(true)  // 1
Number('123a') // NaN
// 空字符串轉為0
Number('') // 0
// 布爾值:true 轉成 1,
//false 轉成 0
Number(true) // 1
Number(false) // 0
// undefined:轉成 NaN
Number(undefined) // NaN
// null:轉成0
Number(null) // 0

parseInt(string):解析一個字符串并返回指定基數的十進制整數,
------------------
parseInt('a123')  // NaN  如果第一個字符不是數字或者符號就返回NaN
parseInt('123a')  // 123
parseInt('32a3') //32

String()//轉換字符串
-------------------
String(1) // "1"
String("a") // "a" 字符串轉換后還是原來的值
String(true) // "true"
String(false) // "false"
String(undefined) // "undefined"
String(null) // "null"

Boolean()可以將任意類型的值轉為布爾值
-------------------
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(1)// true
Boolean(NaN) // false
Boolean('') // false
Boolean({}) // true
Boolean([]) // true
隱式類型轉換
-------------------
    - * 不進行演示
一旦存在字符串,進行字符串拼接操作
'1' + 1 // '11'
'1' + true // "1true"
'1' + false // "1false"
'1' + {} // "1[object Object]"
'1' + [] // "1"
'1' + undefined // "1undefined"
'1' + null // "1null"

5、==和===的區別

(==)相等操作符會做類型轉換,再進行值的比較,

(===)全等運算符不會做類型轉換

'' == '0' // false
1 == '1' // true
1 === '1' // false

6、作用域

簡單的理解就是變量的有效范圍

可分為:全局作用域、函數作用域、塊級作用域

全局作用域

函數最外層定義的變量擁有全局作用域,函數內部是可以訪問的

let inVariable = "全局作用域";
function fn() {
    console.log(inVariable); // 全局作用域
}
fn();

函數作用域

函數作用域也叫局部作用域:如果一個變量是在函數內部聲明的,那這些變量只能在函數下訪問,不能再函數以外去訪問

function fn() {
    let inVariable = "函數內部變量";
    console.log(inVariable)// "函數內部變量";
}
fn();
//報錯
console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined

塊級作用域

ES6引入了塊級作用域 ,【由大括號包裹,比如:if(){},for(){}等】

letconst關鍵字,和var關鍵字不同【后續講解let、const、var區別】

在大括號中使用letconst聲明的變量存在于塊級作用域中。在大括號之外不能訪問這些變量

{
  // 塊級作用域中的變量
  let a = 'Hello';
  var b = 'World';
  console.log(a); // Hello
}
console.log(b); // 'World'
console.log(a); // 報錯:Uncaught ReferenceError: a is not defined

如何訪問函數內部的變量(本人面試時候有問到)

1、通過return訪問:

     function bar(value) {
        var testValue = "hello word";
        return testValue;
      }
     console.log(bar());//hello word

2、通過 閉包 訪問函數內部變量

閉包的定義:閉包就是能夠讀取其他函數內部變量的函數

可以理解成“定義在一個函數內部的函數“

閉包是將函 數內部和函數外部連接起來的橋梁。”

     function bar() {
        var testValue = "hello";
        var rusult = testValue + "Word";
         
        function innser() {
          console.log(rusult);//helloWord
          return rusult;
        }
         
        return innser();
      }
      console.log(bar()); // "helloWord"

7、var、let、const之間的區別

var 聲明變量可以重復聲明,而 let 不可以重復聲

var 是不受限于塊級作用域的,而 let 是受限于塊級作用域

var 可以在聲明的上面訪問變量,而 let 有暫存死區,在聲明的上面訪問變量會報錯

var在全局作用域下聲明變量會導致變量掛載在 window 上let、const 不會

const 聲明之后必須賦值,否則會報錯 const 定義不可變的量,改變了就會報錯

const 和 let 一樣支持塊級作用域、在聲明的上面訪問變量會報錯

上代碼var

//用var聲明的變量既是全局變量也是頂層變量,所謂頂層就是window
var a = 10;
console.log(window.a) // 10
//使用var聲明的變量存在變量提升的情況
console.log(a) // undefined
var a = 20
//在編譯階段,編譯器會將其變成以下執行
var a;
console.log(a); //undefined
a = 20;
console.log(a); //20
//var 多次聲明
var a = 20 
var a = 30
console.log(a) // 30
//在函數中使用使用var聲明變量時候,該變量是局部的
var a = 20
function change(){
    var a = 30
}
change()
console.log(a) // 20 

let

//let 具有塊級作用域
{
    let a = 20
}
console.log(a) // 報錯Uncaught ReferenceError: a is not defined
//不存在變量提升
console.log(a) // 報錯Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 2
// let 不允許相同作用域下聲明
let a = 20
let a = 30 //報錯【累了具體報錯不打印了】

const

//const聲明一個只讀的常量,一旦聲明,常量的值就不能改變
const a = 1
a = 3 // 報錯
//const一旦聲明變量,就必須立即初始化,不能留到以后賦值
const a;
// SyntaxError: Missing initializer in const declaration

const實際上保證的并不是變量的值不能改動,而是變量指向的那個內存地址的數據不能改動。

復雜數據類型變量指向的是內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的,并不能確保改變量的結構不變

const foo = {};

// 為 foo 添加一個屬性,可以成功
foo.a = 123;
foo.a // 123

// 將 foo 指向另一個對象,就會報錯
foo = {}; //報錯

8、閉包

閉包的概念就是:有權利訪問另一個函數作用域中的變量,一般就是函數包裹著函數[之前有提到過閉包的定義]

閉包可以重用一個變量,且保證這個變量不會被污染的一種機制。這些變量的值始終保持在內存中,不會被垃圾回收機制處理

閉包的缺點:由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題

使用場景 :

  • 防抖、節流、函數套函數避免全局污染

  • 創建私有變量

  • 延長變量的生命周期

//簡單的閉包    
function bar() {
        var testValue = "hello";
        var rusult = testValue + "Word";
         
        function innser() {
          console.log(rusult);//helloWord
          return rusult;
        }
         
        return innser();
      }
      console.log(bar()); // "helloWord"

9、什么是內存泄漏

內存泄漏指任何對象在您不再擁有或需要它之后仍然存在

10、原型、原型鏈

原型

  1. 每個函數都有一個prototype屬性,被稱為顯示原型
  2. 每個引用數據類型都會有_ _proto_ _屬性,其被稱為隱式原型
  3. 每個引用數據類型,它的_ _ proto_ _屬性指向它的構造函數的’prototype’屬性。
  4. 每個prototype原型都有一個constructor屬性,指向它關聯的構造函數。
  5. 當試圖得到一個對象的屬性時,如果這個對象本身不存在這個屬性,那么就會去它的_ _ proto_ _屬性(也就是它的構造函數的’prototype’屬性)中去尋找。

原型鏈

當訪問一個對象的某個屬性時,會先在這個對象本身屬性上查找,如果沒有找到,則會去它的proto隱式原型上查找,即它的構造函數的prototype,如果還沒有找到就會再在構造函數的prototype的proto中查找,這樣一層一層向上查找就會形成一個鏈式結構,我們稱為原型鏈。直到頂層返回null

11、什么是遞歸

遞歸:如果一個函數在內部可以調用其本身,那么這個函數就是遞歸函數。簡單理解:函數內部自己調用自己, 這個函數就是遞歸函數

注意:遞歸函數的作用和循環效果一樣,由于遞歸很容易發生“棧溢出”錯誤(stack overflow),所以必須要加退出條件return。

12、什么是防抖什么是節流

防抖:觸發高頻事件后 n 秒內函數只會執行一次,如果 n 秒內高頻事件再次被觸發,則重新計算時間

應用場景:用戶在輸入框中連續輸入一串字符時,可以通過防抖策略,只在輸入完后,才執行查詢的請求,這樣可以有效減

少請求次數,節約請求資源;

節流:高頻事件觸發,但在 n 秒內只會執行一次,所以節流會稀釋函數的執行頻率(也可以理解:可以減少一段時間內事件的觸發頻率)

應用場景: 鼠標連續不斷地觸發某事件(如點擊),只在單位時間內只觸發一次;

區別:防抖動是將多次執行變為最后一次執行,節流是將多次執行變成每隔一段時間執行。

13、call,apply和bind的區別

相同點: 三個函數都會改變this的指向(調用這三個函數的函數內部的this)

不同點:

  • call、apply與bind的差別

call和apply改變了函數的this上下文后便執行該函數,而bind則是返回改變了上下文后的一個函數。(bind不會立即執行)

  • call、apply的區別

他們倆之間的差別在于參數的區別,call和apply的第一個參數都是要改變上下文的對象,而call從第二個參數開始以參數列表的形式展現,apply則是把除了改變上下文對象的參數放在一個數組里面作為它的第二個參數

14、Localstorage、sessionStorage、cookie 的區別

共同點:都是保存在瀏覽器端的,且同源

localStorage:聲生命周期永久生效,除非手動刪除 否則關閉頁面也會存在

sessionStorage:生命周期為關閉瀏覽器窗口

存儲大小:sessionStorage約5M、localStorage約20M

Cookie是服務器發給客戶端的特殊信息,cookie是以文本的方式保存在客戶端(儲存量4k左右)。cookie可以設置過期時間,到達時間后自動銷毀,如果沒有設置會隨瀏覽器的關閉而銷毀。cookei中儲存的數據會伴隨著每一次http請求發送到服務端。

15、同源策略

MDN官方給定的概念:同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的重要安全機制

通俗的理解:瀏覽器規定,A 網站的 JavaScript,不允許和非同源的網站 C 之間,進行資源的交互

同源:協議,域名,端口,三者必須一致

跨域

同源指的是兩個 URL 的協議、域名、端口一致,反之,則是跨域

跨域,指的是從一個域名去請求另外一個域名的資源。即跨域名請求

跨域時,瀏覽器不能執行其他域名網站的腳本,是由瀏覽器的同源策略造成的,也是瀏覽器施加的安全限制。

怎么解決跨域

1、需要后臺配置cors進行跨域,原理是給服務器設置一個響應頭,然后瀏覽器將會允許跨域請求

2、jsonp:原理動態創建一個script標簽,利用script標簽的src屬性不受同源策略的限制。所有的src屬性和href都不會受同源策略的限制。可以請求第三方服務器的數據內容

3、反向代理

4、ngex

16、常見的http狀態碼

200:這個是最常見的http狀態碼,表示服務器已經成功接受請求,并將返回客戶端所請求的最終結果

202:表示服務器已經接受了請求,但是還沒有處理,而且這個請求最終會不會處理還不確定

204:服務器成功處理了請求,但沒有返回任何實體內容 ,可能會返回新的頭部元信息

301:客戶端請求的網頁已經永久移動到新的位置,當鏈接發生變化時,返回301代碼告訴客戶端鏈接的變化,客戶端保存新的鏈接,并向新的鏈接發出請求,已返回請求結果

404:請求失敗,客戶端請求的資源沒有找到或者是不存在

500:服務器遇到未知的錯誤,導致無法完成客戶端當前的請求。

503:服務器由于臨時的服務器過載或者是維護,無法解決當前的請求,

17、事件循環機制EventLoop

Event Loop即事件循環,是解決javaScript單線程運行阻塞的一種機制。

首先我們需要知道JS 是??阻塞單線程語?,就是同一時間只能做一件事情

同步任務和異步任務

javascript是單線程。單線程就意味著,所有任務需要排隊,前一個任務結束,才會執行后一個任務。如果前一個任務耗時很長,后一個任務就意味著等待。于是javascript所有任務分為兩種:同步任務,異步任務

同步任務:不需要等待可立即看到執行結果,比如console、promise 的回調

異步任務:異步任務需要等待一定的時候才能看到結果,比如setTimeout、setInterval、網絡請求(ajax)、script 腳本的執行

異步任務分為:宏任務與微任務

宏任務:script(整體代碼)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 環境)

微任務:Promise、 MutaionObserver、process.nextTick(Node.js環境)

  1. 在執行同步代碼的時候,如果遇到了異步事件,js 引擎并不會一直等待其返回結果,而是會將這個事件掛起,繼續執行執行棧中的其他任務
  2. 當同步事件執行完畢后,再將異步事件對應的回調加入到與當前執行棧中,不同的另一個任務隊列中等待執行。
  3. 任務隊列可以分為宏任務對列和微任務對列,當當前執行棧中的事件執行完畢后,js 引擎首先會判斷微任務對列中是否有任務可以執行,如果有就將微任務隊列的事件壓入棧中執行。
  4. 當微任務對列中的任務都執行完成后再去判斷宏任務對列中的任務。

執行順序
1、先執行主線程

2、遇到宏隊列,放到宏隊列

3、遇到微隊列,放到微隊列,

4、主線程執行完畢

5、執行微隊列,微隊列執行完畢

6、執行一次宏隊列,中的一個任務,執行完畢

7、執行微隊列,執行完畢

8、依次循環

上代碼:

    setTimeout(function () {
        console.log(1);
      });
      new Promise(function (resolve, reject) {
        console.log(2);
        resolve(3);
      }).then(function (val) {
        console.log(val);
      });
      console.log(4);
  // 2431


setTimeout(function() {
  console.log(1)
}, 0);
new Promise(function(resolve, reject) {
  console.log(2);
  resolve()
}).then(function() {
  console.log(3)
});
process.nextTick(function () {
  console.log(4)
})
console.log(5)
//25431
1、主線程開始執行,遇到setTimeout,將setTimeout的回調函數丟到宏任務隊列中
2、在往下執行new Promise立即執行,輸出2
3、.then的回調函數丟到微任務隊列中,再繼續執行
4、遇到process.nextTick,同樣將回調函數扔到為任務隊列,再繼續執行,輸出5
5、當所有同步任務執行完成后看有沒有可以執行的微任務
6、因為process.nextTick指定的異步任務總是發生在所有異步任務之前,因此先執行process.nextTick輸出4,然后執行.then函數輸出3,第一輪執行結束。
7、第二輪:從宏任務隊列開始,發現setTimeout回調,輸出1執行完畢,因此結果是25431

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容