西安市城鄉(xiāng)建設(shè)檔案館網(wǎng)站域名注冊網(wǎng)站
目錄
一、內(nèi)存泄露
1、是什么
2、導(dǎo)致的原因
二、垃圾回收機制的策略
三、淺拷貝和深拷貝
1、淺拷貝
.slice()
...展開運算符
Object.assign(目標對象, 被復(fù)制的對象)
...展開運算符
2、深拷貝
structuredClone()? ? 瀏覽器提供
JSON.parse(JSON.stringify(obj))
四、為什么JS是單線程
五、Promise 的原理
六、宏任務(wù)和微任務(wù)都有哪些
七、宏任務(wù)和微任務(wù)都是怎樣執(zhí)行
八、變量和函數(shù)怎么進行提升的?優(yōu)先級是怎么樣的?
九、var let const 有什么區(qū)別
十、模塊化
1、為什么要使用模塊化
2、實現(xiàn)模塊化的方法
十一、exports和module.exports有什么區(qū)別
十二、ESM 和 commonjs 的區(qū)別
十三、Commonjs、AMD、CMD、UMD、ESM 都有什么區(qū)別
十四、require 和 import的區(qū)別
十五、箭頭函數(shù)和普通函數(shù)的區(qū)別
十六、箭頭函數(shù)可以當做構(gòu)造函數(shù) new 嗎
一、內(nèi)存泄露
1、是什么
不再用的內(nèi)存沒有被及時釋放出來,導(dǎo)致該段內(nèi)存無法被使用就是內(nèi)存泄漏
2、導(dǎo)致的原因
我們無法在通過js訪問某個對象,而垃圾回收機制卻認為該對象還在被引用,因此垃圾回收機制不會釋放該對象,導(dǎo)致該塊內(nèi)存永遠無法釋放,積少成多,系統(tǒng)會越來越卡以至于崩潰
二、垃圾回收機制的策略
1、標記清除法
垃圾回收機制獲取根并標記他們,然后訪問并標記所有來自它們的引用,然后在訪問這些對象并標記它們的引用…如此遞進結(jié)束后若發(fā)現(xiàn)有沒有標記的(不可達的)進行刪除,進入執(zhí)行環(huán)境的不能進行刪除
2、引用計數(shù)法
當聲明一個變量并給該變量賦值一個引用類型的值時候,該值的計數(shù)+1,當該值賦值給另一個變量的時候,該計數(shù)+1,當該值被其他值取代的時候,該計數(shù)-1,當計數(shù)變?yōu)?的時候,說明無法訪問該值了,垃圾回收機制清除該對象
缺點: 當兩個對象循環(huán)引用的時候,引用計數(shù)無計可施。如果循環(huán)引用多次執(zhí)行的話,會造成崩潰等問題。所以后來被標記清除法取代。
三、淺拷貝和深拷貝
1、淺拷貝
只會對對象本身進行復(fù)制,不會復(fù)制對象中的屬性(或元素),對象與被復(fù)制的對象指向的還是同一個內(nèi)存地址。
數(shù)組方法:
-
.slice()
-
...展開運算符
對象方法:
-
Object.assign(目標對象, 被復(fù)制的對象)
-
...展開運算符
- Object.assign({}, obj1)
2、深拷貝
深拷貝指不僅復(fù)制對象本身,還復(fù)制對象中的屬性和元素
方法:
-
structuredClone()? ? 瀏覽器提供
-
JSON.parse(JSON.stringify(obj))
手寫深拷貝: 見 =》
四、為什么JS是單線程
因為JS里面有可視的Dom,如果是多線程的話,這個線程正在刪除DOM節(jié)點,另一個線程正在編輯Dom節(jié)點,導(dǎo)致瀏覽器不知道該聽誰的
五、Promise 的原理
六、宏任務(wù)和微任務(wù)都有哪些
- 宏任務(wù):
script
、setTimeOut
、setInterval
、setImmediate
- 微任務(wù):
promise.then、
process.nextTick
、Object.observe
、MutationObserver
- 注意:Promise是同步任務(wù)
七、宏任務(wù)和微任務(wù)都是怎樣執(zhí)行
- 執(zhí)行宏任務(wù)script,
- 進入script后,所有的同步任務(wù)主線程執(zhí)行
- 所有宏任務(wù)放入宏任務(wù)執(zhí)行隊列
- 所有微任務(wù)放入微任務(wù)執(zhí)行隊列
- 先清空微任務(wù)隊列,
- 再取一個宏任務(wù),執(zhí)行,再清空微任務(wù)隊列
- 依次循環(huán)
八、變量和函數(shù)怎么進行提升的?優(yōu)先級是怎么樣的?
- 對所有函數(shù)聲明進行提升(除了函數(shù)表達式和箭頭函數(shù)),引用類型的賦值
- 開辟堆空間
- 存儲內(nèi)容
- 將地址賦給變量
- 對變量進行提升,只聲明,不賦值,值為
undefined
九、var let const 有什么區(qū)別
var
- var聲明的變量可進行變量提升,let和const不會
- var可以重復(fù)聲明
- var在非函數(shù)作用域中定義是掛在到window上的
let
- let聲明的變量只在局部起作用
- let防止變量污染
- 不可在聲明
const
- 具有l(wèi)et的所有特征
- 不可被改變:不可改變只適用于直接地址。如果使用const聲明的是對象的話,是可以修改對象內(nèi)部的值的
十、模塊化
1、為什么要使用模塊化
- 防止命名沖突
- 更好的分離,按需加載
- 更好的復(fù)用性
- 更高的維護性
2、實現(xiàn)模塊化的方法
早期:命名空間、閉包
現(xiàn)在:CommonJS、AMD模塊、ES6模塊
十一、exports
和module.exports
有什么區(qū)別
- 導(dǎo)出方式不一樣
exports.xxx='xxx'
module.export = {}
exports
是module.exports
的引用,兩個指向的是用一個地址,而require能看到的只有module.exports
十二、ESM 和 commonjs 的區(qū)別
- commonjs 是運行時加載 ;ESM 是編譯時加載
- commonjs 是同步加載模塊;ESM 是異步加載模塊
- commonjs 是對值的淺拷貝;ESM 是對值的引用,而且不可修改(直接地址不可修改,類似于 const)
十三、Commonjs、AMD、CMD、UMD、ESM 都有什么區(qū)別
1、Commonjs:是同步執(zhí)行的,不適合前端,后端 nodejs 可以使用 commonjs。
2、AMD/CMD/UMD 適用前端 ,異步執(zhí)行。
3、ESM使用 export 、 export default 來導(dǎo)出模塊,使用 import 來引入模塊
4、AMD 和 CMD 的差別是
AMD 是依賴前置(把依賴放在前面)、提前執(zhí)行(即使沒有用到某個模塊,也會提前執(zhí)行)
CMD依賴就近、延時執(zhí)行(用到的時候在聲明依賴)
十四、require 和 import的區(qū)別
調(diào)用時機
- require 是運行時調(diào)用,所以其實是可以放在任何地方的
- Import 是編譯時調(diào)用,所以必須放在文件的開頭
使用時
- require 需要使用 module.exports = fs 或者exports.fs = xxx
- import 用 export default 或 export const xx
解構(gòu)賦值
- require 是賦值的過程
- import 是解構(gòu)的過程
十五、箭頭函數(shù)和普通函數(shù)的區(qū)別
- 箭頭函數(shù)是普通函數(shù)的簡寫,但是它不具備很多普通函數(shù)的特性
- 箭頭函數(shù)的this指向它定義時所在的對象,而不是調(diào)用它的對象
- 不會進行函數(shù)提升
- 沒有arguments對象,不能使用arguments,如果要獲取參數(shù)的話可以使用rest運算符
- 沒有yield屬性,不能作為生成器Generator使用
十六、箭頭函數(shù)可以當做構(gòu)造函數(shù) new 嗎
不能new。因為:沒有自己的this,不能調(diào)用call和apply。沒有prototype,new關(guān)鍵字內(nèi)部需要把新對象的_proto_
指向函數(shù)的prototype。