中級前端面試題,不低於12k,整理的是js較高頻知識點,可能不夠完善,大家有興趣可以留言補充,我會逐步完善,若發現哪里有錯,還請多多斧正,哈哈
http和瀏覽器相關知識點,已分離出,會在下篇整理
數據類型
基本類型:number,string,boolean,null,undefined
引用類型:object,array,function (統稱為object)
基本類型和引用類型的區別
引用類型值保存在堆里,基本類型是存放在棧里
引用類型值可添加屬性和方法,而基本類型值則不可以
判斷類型方式
- typeof:常用,但是無法區分objec t和 null
- instanceof:通過原型鏈來判斷
- Object.prototype.toString.call() :最完美的判斷方法
棧和堆的區別
棧由編譯器自動分配釋放空間,堆一般由程序員分配釋放
棧存放在一級緩存中,調用完畢立即釋放;堆則是在二級緩存中,生命周期由虛擬機的垃圾回收算法來決定
數組常用方法
改變原數組
shift:刪除第一個元素
unshift:向數組開頭添加元素
pop:刪除最后一個元素
push:向數組末尾添加元素
reverse:數組倒序排序
sort:數組正序排序
splice: splice(start,length,item)刪,增,替換數組元素
不改變原數組
concat:連接多個數組
join:將數組所有元素以字符分隔
slice:slice(start,end),切割數組
map,filter,some,every等不改變原數組
數組排序
- reverse()倒序
- sort()正序
- 冒泡排序
var arr = [1, 9, 4, 50, 49, 6, 3, 2]; function test(){ for (var i = 0; i < arr.length - 1; i++){ for (var j = i + 1; j < arr.length; j++){ var tempi = arr[i]; // 獲取第一個值,並與后一個值比較 var tempj = arr[j]; if (tempi > tempj) { arr[i] = tempj; arr[j] = tempi; // 如果前一個值比后一個值大,那么相互交換 } } } console.log(arr); // return arr } test(arr); // [1, 2, 3, 4, 6, 9, 49, 50]
數組去重
- indexOf() 用for循環遍歷數組,把等於下標值為-1的值push進新建的空數組里
- es6的set()方法
var arr = [1,1,12,12,13,13,8,8,9,7,5]; var arr2 = [...new Set(arr)]; // [1, 12, 13, 8, 9, 7, 5]
淺拷貝與深拷貝
- 深拷貝和淺拷貝只針引用類型(Object、Array)的數據
- 淺拷貝只復制指向某個對象的指針,而不復制對象本身,新舊對象共享同一內存,修改新對象會改變原對象
- 深拷貝則另外創造個一模一樣的對象,新舊對象不共享內存,修改新對象不會改到原對象
淺拷貝實現方法
- Object.assign() // 注意,當object只有一層結構,是深拷貝
- Array.prototype.concat()
- Array.prototype.slice()
深拷貝實現方法
- JSON.parse(JSON.stringify())
- 遞歸法,for循環遍歷對象、數組直到里邊都是基本數據類型,然后再賦值
JSON.stringify()實現深拷貝的缺點
如obj里有時間對象,則JSON.stringify(序列化)再JSON.parse(反序列化)后,時間對象將變成字符串形式,而不是對象形式
如obj里有正則(RegExp)、Error對象,則序列化后只得到空對象
如obj里有函數,undefined,則序列化后會丟失
如obj里有NaN、正無窮(Infinity)和負無窮(-Infinity),則序列化后會變成null
null,undefined的區別
null用來表示尚未存在的對象
undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義
函數聲明與函數表達式
在js中,解析器會率先讀取函數聲明,並使其在執行任何代碼前可用(可訪問)
而函數表達式,則必須等到解析器執行到它所在的代碼行,才會真正被解析執行
原型鏈
函數對象
在JS中,函數即對象
原型對象
定義函數對象時,會包含一個預定義屬性prototype,稱為原型對象
__proto__
創建對象時,會有個[[proto]]內置屬性,用於指向創建它的函數對象的prototype,prototype也有[[proto]]屬性,在不斷指向中,形成了原型鏈
原型鏈的終點
原型鏈終點是null
原型鏈終點為什么是null
- 原型鏈上所有節點都是對象,不能是字符串、數字、布爾值等原始類型
- 另外,規范要求原型鏈必須是有限長度
new操作符具體做了什么
- 創建空對象,this引用該對象,同時繼承該對象的原型
- 屬性和方法被加入到this引用的對象中
this指向問題
- 當沒有被對象調用時,指向window
- 當被對象調用時,指向調用他的對象
- 當實例化對象就在對象中時,指向該實例化對象
判斷空對象方法
1. JSON.stringify(obj)
// 判斷JSON.stringify(data) == "{}"
2. Object.keys(obj)
// 返回自身的可枚舉屬性
// 判斷Object.keys(data).length === 0
閉包
閉包就是能夠讀取其他函數內部變量的函數
閉包優點
- 將變量長期保存,不被垃圾回收機制回收
- 避免全局變量的污染
- 安全性提高
閉包缺點
- 容易造成內存泄漏
閉包應用場景
- 封裝私有變量
- 通過閉包實現setTimeout傳參
- 作為回調函數綁定到事件
常見內存泄漏
- 閉包
- 全局變量,相當於掛載到 window 對象上
- 被遺忘的定時器和回調函數
垃圾回收機制
- 標記清除
- 引用計數
事件冒泡
當元素接收事件時,會把接收的事件傳遞給自己的父級,層層傳遞直到window
阻止事件冒泡
IE瀏覽器: e.cancelBubble = true
其他: e.stopPropagation()
事件捕獲
用addEventListener監聽目標元素事件
阻止默認事件
return false
ev.preventDefault()
事件委托原理,及優缺點
原理為事件冒泡機制
優點
- 可大量節省內存占用,減少事件注冊
- 可實現當新增子對象時,無需再對其事件綁定,對於動態內容部分尤為合適
缺點
- 可能會出現事件誤判,把本不應用觸發事件的被綁上了事件
事件循環
Javascriprt為單線程。單線程的缺點是所有任務需排隊,后一個任務要等前一個任務執行完畢,這樣耗時太久,於是js所有任務分為兩種:同步任務,異步任務
JS引擎將所有任務按類添加到宏任務、微任務兩個隊列,首先在宏任務隊列中取出第一個任務,執行完畢后,再把微任務隊列中所有任務按序執行完,之后再取宏任務,周而復始,直至兩個隊列的任務都取完,過程就叫事件循環
宏任務和微任務
宏任務:setTimeout,setInterval
微任務:Promise,process.nextTick