JS面試題:公司真實(shí)JS面試題整理
一、說一下js單線程的理解?
js是單線程的,內(nèi)部要處理的任務(wù)分同步任務(wù)、異步任務(wù)。
異步任務(wù)分微任務(wù)、宏任務(wù)
執(zhí)行順序:【又稱 事件循環(huán)機(jī)制 】
先執(zhí)行同步任務(wù),遇到異步宏任務(wù)則將異步宏任務(wù)放入宏任務(wù)隊(duì)列中,遇到異步微任務(wù)則將異步微任務(wù)放入微任務(wù)隊(duì)列中。當(dāng)所有同步任務(wù)執(zhí)行完畢后,再將異步微任務(wù)從隊(duì)列中調(diào)入主線程執(zhí)行,微任務(wù)執(zhí)行完畢后再將異步宏任務(wù)從隊(duì)列中調(diào)入主線程執(zhí)行,一直循環(huán)直至所有任務(wù)執(zhí)行完畢。
微任務(wù)和宏任務(wù)有哪些:
- 宏任務(wù)一般是:script、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel。
- 微任務(wù):Promise.then、Object.observe、MutationObserver。
示例:
setTimeout(function(){
console.log(1);
});
new Promise(function(resolve){
console.log(2);
resolve();
}).then(function(){
console.log(3);
}).then(function(){
console.log(4)
});
console.log(5);
// 2 5 3 4 1
遇到setTimout,異步宏任務(wù),放入宏任務(wù)隊(duì)列中。
遇到new Promise,new Promise在實(shí)例化的過程中所執(zhí)行的代碼都是同步進(jìn)行的,所以輸出2。
Promise.then,異步微任務(wù),將其放入微任務(wù)隊(duì)列中。
遇到同步任務(wù)console.log(5);輸出5;主線程中同步任務(wù)執(zhí)行完。
從微任務(wù)隊(duì)列中取出任務(wù)到主線程中,輸出3、 4,微任務(wù)隊(duì)列為空。
從宏任務(wù)隊(duì)列中取出任務(wù)到主線程中,輸出1,宏任務(wù)隊(duì)列為空。
二、說一下defer和async的區(qū)別?
相同點(diǎn):
- 都是script標(biāo)簽的屬性。
- 都是異步加載js。
- 都是為了避免加載腳本的時(shí)候就會阻塞頁面的渲染,出現(xiàn)空白的現(xiàn)象的問題。
不同點(diǎn):
- 沒有加defer 或 async,同步加載、立即執(zhí)行、阻塞HTML解析。
- 加defer,異步加載、HTML解析完畢后執(zhí)行、不阻塞HTML解析。
- 加async,異步加載、立即執(zhí)行、可能阻塞也可能不阻塞HTML解析。
注意:
async和defer屬性都僅適用于外部腳本,如果script標(biāo)簽沒有src屬性,盡管寫了async、defer屬性也會被忽略。
三、說一下淺拷貝和深拷貝的區(qū)別?
深拷貝和淺拷貝是只針對Object和Array這樣的引用數(shù)據(jù)類型的。
js中基本數(shù)據(jù)類型存放在棧中,引用數(shù)據(jù)類型存放在堆中。
淺拷貝是在堆中先創(chuàng)建一個(gè)新對象,拷貝原始對象的屬性值。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,拷貝的就是內(nèi)存地址。
深拷貝是在堆中先創(chuàng)建一個(gè)新對象,采用遞歸方法實(shí)現(xiàn)深度克隆原理,將一個(gè)對象從內(nèi)存中完整的拷貝一份出來。如果屬性是基本類型,拷貝的就是基本類型的值,如果屬性是引用類型,在堆中創(chuàng)建一個(gè)新對象再完整拷貝原對象。
區(qū)別:
- 淺拷貝基本類型之間互不影響,引用類型其中一個(gè)對象改變了地址,就會影響另一個(gè)對象。
- 深拷貝改變新對象不會影響原對象,他們之間互不影響。
實(shí)現(xiàn):
- 淺拷貝:Object.assign()、展開運(yùn)算符… 、concat()、slice()。
- 深拷貝:JSON.parse(JSON.stringify())、jQuery.extend()、遞歸。
四、說一下數(shù)組常用方法有哪些?
- push(): 將元素添加到數(shù)組的結(jié)尾,添加多個(gè)用逗號隔開。
- pop(): 刪除數(shù)組的最后一項(xiàng)。
- unshift(): 將元素添加到數(shù)組的開頭,添加多個(gè)用逗號隔開。
- shift(): 刪除數(shù)組的第一項(xiàng)。
- splice(): 刪除指定元素,并在刪除位置添加元素 --- 3個(gè)參數(shù):起始索引 刪除數(shù)目 新增內(nèi)容。
- slice() 截取區(qū)間內(nèi)的元素 --- 2個(gè)參數(shù):開始位置 結(jié)束位置。
- fill(): 填充數(shù)組 --- 3個(gè)參數(shù):值 開始位置 結(jié)束位置。
- String()、toString(): 將數(shù)組轉(zhuǎn)成字符串。
- join(): 把數(shù)組轉(zhuǎn)換成字符串,然后給他規(guī)定一個(gè)連接字符,默認(rèn)是逗號。
- Array.from(): 方法用于將兩類對象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對象和可遍歷的對象(Set 和 Map)。
- Array.of(): 用于將一組值,轉(zhuǎn)換為數(shù)組。
- map():循環(huán),并且返回新的數(shù)組。
- forEach(): 循環(huán),遍歷。
- filter(): 過濾,篩選出數(shù)組中的滿足條件的,并且返回新的數(shù)組。
- find(): 查找出第一個(gè)符合條件的數(shù)組元素。
- findIndex(): 查找出第一個(gè)符合條件的數(shù)組元素,所在的索引位置。
- indexOf():查找數(shù)組中值第一次出現(xiàn)的索引。
- includes(): 查看數(shù)組中是否存在此元素。
- every(): 檢測數(shù)組中元素是否都是符合條件。
- some(): 檢測數(shù)組中元素是否有滿足條件的元素。
- sort(): 對數(shù)組排序,正序。
- reverse(): 對數(shù)組進(jìn)行顛倒。
- concat(): 合并數(shù)組,返回一個(gè)新數(shù)組。
- copyWithin(): 指定位置的成員復(fù)制到其他位置。
五、說一下字符串常用方法有哪些?
- replace(): 在字符串中用一些字符替換另一些字符。
- substr(): 從起始索引提取字符串中指定數(shù)目的字符。
- substring(): 提取字符串中兩個(gè)指定索引之間的字符。
- slice() 截取區(qū)間內(nèi)的元素 --- 2個(gè)參數(shù):開始位置 結(jié)束位置。
- split(): 把字符串轉(zhuǎn)換成數(shù)組,字符串以什么符號連接,就以什么符號分割。
- charAt(): 返回在指定位置的字符。
- indexOf(): 返回某個(gè)指定的字符串值在字符串中首次出現(xiàn)的位置。
- lastIndexOf(): 從后向前搜索字符串,并從起始位置(0)開始計(jì)算返回字符串最后出現(xiàn)的位置。
- includes(): 查找字符串中是否包含指定的字符串。
- search(): 檢索字符串中指定的子字符串。
- startsWith(): 查看字符串是否以指定的字符串開頭。
- toLowerCase(): 把字符串轉(zhuǎn)為小寫。
- toUpperCase(): 把字符串轉(zhuǎn)為大寫。
- trim(): 去掉字符串兩邊的空白。
- concat(): 連接兩個(gè)或多個(gè)字符串,返回新的字符串。
六、說一下數(shù)據(jù)類型有哪些?如何判斷數(shù)據(jù)類型?
- 基本數(shù)據(jù)類型:Number、String、Boolean、Symbol、Null、Undefined。
- 引用數(shù)據(jù)類型:Object、Array、Function。
- typeof:可判斷基本數(shù)據(jù)類型、Function,不能將Object、Array和Null區(qū)分,都返回Object。
- instanceof:可判斷Array、Object、Function,不能判斷基本數(shù)據(jù)類型 原理:判斷B是否在A的原型鏈上。
- Object.prototype.toString.call():可判斷所有數(shù)據(jù)類型。
七、說一下數(shù)組去重的方法?
雙重for循環(huán) + splice。
for(var i=0;i<arr.length;i++){
for(var j=i+1;j<arr.length;j++){
if(arr[i]===arr[j]){
arr.splice(j,1)
j--
}
}
}
filter + indexOf,返回item第一次出現(xiàn)的位置等于當(dāng)前的index的元素 【常用】。
let newArr = arr.filter((item, index) => arr.indexOf(item) === index);
filter + Object.hasOwnProperty,利用對象的鍵名不可重復(fù)的特點(diǎn)
let obj = {}
arr.filter(item => obj.hasOwnProperty(typeof item + item) ? false : obj[typeof item])
new Set + 擴(kuò)展運(yùn)算符 或 Array.from 【常用】。
let newArr = [...new Set(arr)];
let newArr = Array.from(new Set(arr));
八、說一下call、apply、bind區(qū)別?
ObjA.call(ObjB, argument) --- ObjB調(diào)用ObjA中的方法,并把a(bǔ)rgument作為參數(shù)傳入。
作用:改變this的指向。
區(qū)別:
調(diào)用方式不同:
- call、apply:立即調(diào)用,返回的的是一個(gè)值。
- bind:手動(dòng)調(diào)用,返回的是一個(gè)函數(shù)形式。
參數(shù)不同:
三者第一個(gè)參數(shù)都是調(diào)用的對象。
- call、bind:第二個(gè)參數(shù)為一個(gè)值,多個(gè)參數(shù)間用逗號分開
- apply:第二個(gè)參數(shù)為一個(gè)數(shù)組
九、說一下什么是原型、原型鏈?
原型:
每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,即 顯式原型屬性,它指向構(gòu)造函數(shù)的原型對象。
每個(gè)實(shí)例對象都有一個(gè)__proto__屬性,即 隱式原型屬性,它指向構(gòu)造函數(shù)的原型對象。
通過顯式原型屬性向原型對象上設(shè)置值,通過隱式原型屬性向原型對象上讀取值,即 實(shí)例對象的隱式原型屬性值等于其構(gòu)造函數(shù)的顯式原型屬性值。
原型鏈:
每個(gè)構(gòu)造函數(shù)的原型對象,默認(rèn)是一個(gè)空的Object構(gòu)造函數(shù)的實(shí)例對象,也都有一個(gè)__proto__屬性。
實(shí)例對象和原型對象的__proto__屬性連接起來的一條鏈,即 原型鏈,它的盡頭是Object構(gòu)造函數(shù)的原型對象的__proto__屬性。
當(dāng)在實(shí)例對象上讀取值時(shí),先在實(shí)例對象本身上找,當(dāng)找不到,再通過__proto__屬性,在其構(gòu)造函數(shù)的原型對象上找,
如果還找不到,就繼續(xù)沿著__proto__屬性向上找,直到Object構(gòu)造函數(shù)的原型對象的__proto__屬性為止,此時(shí)值為null。
十、說一下什么是閉包?
定義在一個(gè)函數(shù)體內(nèi),且訪問了外部函數(shù)變量 的函數(shù),即 閉包函數(shù)(閉包)。
優(yōu)點(diǎn):
- 延長函數(shù)內(nèi)局部變量的生命周期。
- 在函數(shù)外部可以操作到函數(shù)內(nèi)部的私有變量【重點(diǎn)作用】。
缺點(diǎn):會導(dǎo)致內(nèi)存泄露,所以要謹(jǐn)慎使用。
應(yīng)用場景:
- 將函數(shù)作為一個(gè)函數(shù)的返回值 如:封裝API模塊,只對外暴漏內(nèi)部的功能函數(shù),不暴漏外部函數(shù)的私有變量 --- 類似于類的權(quán)限修飾。
- 將函數(shù)作為實(shí)參傳遞給一個(gè)函數(shù)內(nèi)部的另一個(gè)函數(shù)調(diào)用 如:函數(shù)內(nèi)調(diào)用定時(shí)器函數(shù),將閉包函數(shù)作為定時(shí)器的回調(diào)函數(shù)傳遞。
回調(diào)和閉包的區(qū)別:【是否定義在函數(shù)體內(nèi)】。
- 回調(diào)函數(shù):作為實(shí)參傳遞的函數(shù),沒有定義在一個(gè)函數(shù)體內(nèi)。
- 閉包函數(shù):定義在一個(gè)函數(shù)體內(nèi),且訪問了外部函數(shù)變量 的函數(shù)。
例:
function handle(msg, time) {
setInterval(function callback() {
console.log(msg);
}, time)
}
handle("哈哈哈哈", 5000)
對于setInterval函數(shù)來說,callback函數(shù)是回調(diào)函數(shù)。
對于handle函數(shù)來說,callback函數(shù)是閉包函數(shù)。
十一、說一下this的指向?
普通函數(shù):普通函數(shù)中this是動(dòng)態(tài)的,在調(diào)用函數(shù)時(shí)確定,一般誰調(diào)用指向誰。
調(diào)用方式 this指向。
普通函數(shù)調(diào)用 window。
構(gòu)造函數(shù)調(diào)用 實(shí)例對象。
對象方法調(diào)用 該方法所屬對象。
事件綁定方法 綁定事件的對象。
定時(shí)器函數(shù) window。
立即執(zhí)行函數(shù) window。
箭頭函數(shù):
箭頭函數(shù)沒有自己的this、arguments。
箭頭函數(shù)的this是靜態(tài)的,在定義函數(shù)時(shí)確定,一般和箭頭函數(shù)所在父作用域的this指向一致。
十二、說一下什么是防抖、節(jié)流?
作用:
都是可以限制函數(shù)的執(zhí)行頻次,避免函數(shù)觸發(fā)頻率過高導(dǎo)致響應(yīng)速度跟不上觸發(fā)頻率,因而出現(xiàn)延遲、假死或卡頓的現(xiàn)象。
都使用定時(shí)器實(shí)現(xiàn)。
防抖(debounce):【多次重新計(jì)時(shí)】。
在事件被觸發(fā)n秒后再執(zhí)行回調(diào),如果在這n秒內(nèi)又被觸發(fā),則重新計(jì)時(shí)。
典型的案例:輸入框搜索,輸入結(jié)束后n秒才進(jìn)行搜索請求,n秒內(nèi)又輸入內(nèi)容,則重新計(jì)時(shí)。
節(jié)流(throttle):【多次只一次生效】。
規(guī)定在一個(gè)單位時(shí)間內(nèi),只能觸發(fā)一次函數(shù),如果這個(gè)單位時(shí)間內(nèi)觸發(fā)多次函數(shù),只有一次生效。
典型的案例:鼠標(biāo)不斷點(diǎn)擊按鈕觸發(fā)事件,規(guī)定在n秒內(nèi)多次點(diǎn)擊只生效一次。
十三、說一下ES6新特性有哪些?
- 新的聲明方式,let、const。
- 新的數(shù)組方法,如:for of、find()、findIndex()。
- 解構(gòu)賦值。
- 擴(kuò)展運(yùn)算符。
- 箭頭函數(shù)。
- 模板字符串。
- symbol數(shù)據(jù)類型。
- 函數(shù)參數(shù)允許設(shè)置默認(rèn)值,引入了rest參數(shù)(...變量名)。
- 鏈判斷運(yùn)算符 (?.)
- Set集合(偽數(shù)組)。
- Map集合(對象)。
- Promise。
- 模塊化,import、export。
- 類。
十四、說一下var、let、const的區(qū)別?
var
- var聲明的變量在全局內(nèi)有效。
- 可以重復(fù)聲明。
- var聲明的變量存在變量提升。
let
- 遇到{}可開啟塊級作用域。
- 不能重復(fù)聲明 --- 可以防止變量重復(fù)定義產(chǎn)生的沖突,會直接報(bào)錯(cuò)。
- let聲明的變量不存在變量提升。
const
- const聲明的常量是一個(gè)只讀屬性,必須初始化。
- 遇到{}可開啟塊級作用域。
- 不能重復(fù)聲明。
- 不存在變量提升。
- const定義的基本數(shù)據(jù)類型不可以修改,但復(fù)雜數(shù)據(jù)類型可以修改。
原因:const指針指向的地址是不可以改變的,但地址指向的內(nèi)容是可以改變的。
十五、說一下for in 和 for of 區(qū)別?
for in
- 可以直接遍歷對象,得到屬性。
- 遍歷數(shù)組,得到下標(biāo)。
- 不能遍歷map集合對象。
for of
- 不可以直接遍歷對象,因?yàn)闆]有引入iterable,必須加上 Object.key(對象) 才能使用。
- 遍歷數(shù)組,得到內(nèi)容。
- 能遍歷map集合對象,得到屬性和值。
十六、說一下對Promise理解?
Promise對象:
描述:
- 用于封裝異步操作并返回其結(jié)果的一個(gè)構(gòu)造函數(shù)。
- 為了將 異步操作 變 同步操作 執(zhí)行。
三種狀態(tài):
- pending 待定狀態(tài)。
- fulfilled 成功狀態(tài)。
- rejected 失敗狀態(tài)。
九種方法:
對象上有resolve、reject、all、allSettled、race、any方法:
- resolve():異步操作成功回調(diào),并將異步操作的結(jié)果作為參數(shù)傳遞出去。
- reject():異步操作失敗回調(diào),并將異步操作的結(jié)果作為參數(shù)傳遞出去。
- all():所有的Promise對象均成功后,才會執(zhí)行all中的then回調(diào),否則返回的是最先rejected狀態(tài)的值。
- allSettled():所有的Promise對象均出現(xiàn)結(jié)果(無論成功或失敗)后,才會執(zhí)行allSettled中的then回調(diào)(只會進(jìn)入then回調(diào))。
- any():和all相反,所有的Promise對象均失敗后,才會執(zhí)行any中的失敗回調(diào),否則當(dāng)任意一個(gè)Promise對象成功就會直接進(jìn)入then回調(diào)。
- race():返回執(zhí)行最快的一個(gè)Promise的結(jié)果。
原型上有then、catch、finally方法:
- then():獲取成功回調(diào)結(jié)果,進(jìn)行邏輯處理。
- catch(): 獲取失敗回調(diào)結(jié)果,拋出異常并處理。
- finally():無論成功或者失敗都會執(zhí)行。
async與await:
出現(xiàn)目的:
- await的出現(xiàn)是為了簡化多個(gè)then鏈的傳參問題。
async:
- 是Promise對象的語法糖,async function A 相當(dāng)于Promise.resolve(function A)。
await:
必須放在async定義的函數(shù)內(nèi)部去使用。
作用:
- 等待當(dāng)前函數(shù)執(zhí)行完畢。
- 獲取promise中的resolve回調(diào)的結(jié)果 --- 此處作用同then。
異步變同步的解決,經(jīng)歷了四個(gè)階段:
回調(diào)函數(shù)
描述:
回調(diào)里面嵌入回調(diào),導(dǎo)致層次很深,代碼維護(hù)起來特別復(fù)雜,產(chǎn)生回調(diào)地獄問題。
示例代碼:
getData(){
//獲取分類列表id
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
success:res=>{
let id=res.data[0].id
// 根據(jù)分類id獲取該分類下的所有文章
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
data:{
cid:id
},
success:res2=>{
//獲取到一篇文章的id,根據(jù)文章id找到該文章下的評論
let id=res2.data[0].id;
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/comment.php",
data:{
aid:id
},
success:res3=>{
//找到該文章下所有的評論
console.log(res3)
}
})
}
})
}
})
}
回調(diào)函數(shù)封裝
描述:
- 把每一個(gè)request請求封裝出一個(gè)函數(shù),將結(jié)果進(jìn)行返回。
- 代碼條理清晰了,但還是回調(diào)里面嵌套回調(diào),并沒有解決回調(diào)地獄的問題。
示例代碼:
//在onload初始化后調(diào)用相應(yīng)的函數(shù)
onLoad() {
//調(diào)用導(dǎo)航函數(shù),并拿到函數(shù)的返回值
this.getNav(res=>{
let id=res.data[0].id;
//拿到分類id作為參數(shù)
this.getArticle(id,res2=>{
//拿到文章id作為參數(shù)
let id=res2.data[0].id;
this.getComment(id,res3=>{
//最終獲取到第一個(gè)分類下,第一篇文章下,所有評論
console.log(res3)
})
})
});
}
methods: {
//先獲取導(dǎo)航分類接口,將結(jié)果進(jìn)行返回,到調(diào)用函數(shù)的地方獲取
getNav(callback){
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
success:res=>{
callback(res)
}
})
},
//獲取文章數(shù)據(jù),將文章列表進(jìn)行返回
getArticle(id,callback){
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
data:{
cid:id
},
success:res=>{
callback(res)
}
})
},
//獲取文章下的所有評論
getComment(id,callback){
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/comment.php",
data:{
aid:id
},
success:res=>{
callback(res)
}
})
}
}
promise then
示例代碼:
//promise鏈?zhǔn)秸{(diào)用
this.getNav()
.then(res=>{
let id=res.data[0].id;
return this.getArticle(id);
})
.then(res=>{
let id=res.data[0].id;
return this.getComment(id)
})
.then(res=>{
console.log(res)
})
methods: {
//先獲取導(dǎo)航分類接口,將結(jié)果進(jìn)行返回,到調(diào)用函數(shù)的地方獲取
getNav(callback){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
},
//獲取文章數(shù)據(jù),將文章列表進(jìn)行返回
getArticle(id){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
data:{
cid:id
},
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
},
//獲取文章下的所有評論
getComment(id){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/comment.php",
data:{
aid:id
},
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
}
}
promise await
描述:
await / async 這兩個(gè)命令是成對出現(xiàn)的,如果使用await沒有在函數(shù)中使用async命令,那就會報(bào)錯(cuò),如果直接使用async沒有使用await不會報(bào)錯(cuò),只是返回的函數(shù)是個(gè)promise
示例代碼:
async onLoad() {
let id,res;
res=await this.getNav();
id=res.data[0].id;
res=await this.getArticle(id);
id=res.data[0].id;
res=await this.getComment(id);
console.log(res)
}
methods: {
//先獲取導(dǎo)航分類接口,將結(jié)果進(jìn)行返回,到調(diào)用函數(shù)的地方獲取
getNav(callback){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/navlist.php",
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
},
//獲取文章數(shù)據(jù),將文章列表進(jìn)行返回
getArticle(id){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/newslist.php",
data:{
cid:id
},
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
},
//獲取文章下的所有評論
getComment(id){
return new Promise((resolve,reject)=>{
uni.request({
url:"https://ku.qingnian8.com/dataApi/news/comment.php",
data:{
aid:id
},
success:res=>{
resolve(res)
},
fail:err=>{
reject(err)
}
})
})
}
}
十七、說一下偽數(shù)組轉(zhuǎn)為真數(shù)組的方法?
- Array.prototype.slice.call(偽數(shù)組)。
- Array.from(偽數(shù)組)。
- 剩余運(yùn)算符...
十八、說一下三種緩存方式的區(qū)別?
- cookie:用來保存登錄信息,大小限制為4KB左右。
- localStorage:用于本地?cái)?shù)據(jù)存儲,保存的數(shù)據(jù)沒有過期時(shí)間,一般瀏覽器大小限制在5MB。
- sessionStorage:接口方法和localStorage類似,但保存的數(shù)據(jù)的只會在當(dāng)前會話中保存下來,頁面關(guān)閉后會被清空。
十九、說一下創(chuàng)建Ajax的基本步驟?
- 創(chuàng)建XMLHttpRequest對象。
- 創(chuàng)建http請求。
- 發(fā)送http請求。
- 設(shè)置http請求狀態(tài)變化的函數(shù)。
- 獲取服務(wù)器返回的數(shù)據(jù)。
示例代碼:
// 1
const xhr = new XMLHttpRequest();
// 2
xhr.open('POST', "http://localhost:xxx");
// 3
xhr.send("a=100&b=200");
// 4
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
// 5
if(xhr.status >= 200 && xhr.status < 300){
result.innerHTML = xhr.response;
}
}
}
二十、說一下HTTP與HTTPS的區(qū)別?
- HTTP是超文本傳輸協(xié)議,信息是明文傳輸,HTTPS是由SSL協(xié)議 + HTTP協(xié)議,信息是加密傳輸。
- HTTPS協(xié)議需要花錢申請證書,免費(fèi)證書少。
- HTTP和HTTPS默認(rèn)使用的端口不同,前者是80,后者是443。
二十一、說一下請求方式post和get的區(qū)別?
安全性
- get請求參數(shù)會被拼接到地址欄上,信息會暴露。
- post請求參數(shù)不可見。
數(shù)據(jù)傳輸量
- get有長度限制。
- post不會。
緩存
- get數(shù)據(jù)會被緩存。
- post不會。
后端的習(xí)慣
- 查用用get,因?yàn)橐猪摚虚L度限制
- 增刪改用post
二十二、說一下常見的http狀態(tài)碼?
- 4xx表示客戶端錯(cuò)誤。
- 401表示請求格式錯(cuò)誤。
- 402表示請求未授權(quán)。
- 403表示禁止訪問。
- 404表示請求的資源不存在,一般是路徑寫錯(cuò)了。
- 5xx表示服務(wù)器錯(cuò)誤。
- 500表示最常見的服務(wù)器錯(cuò)誤,一般是前端參數(shù)傳錯(cuò)了、或后端代碼寫錯(cuò)了。
- 503表示服務(wù)器構(gòu)建。
二十三、說一下js的模塊化?
作用:
一個(gè)模塊就是實(shí)現(xiàn)某個(gè)特定功能的文件,在文件中定義的變量、函數(shù)、類都是私有的,對其他文件不可見。
為了解決引入多個(gè)js文件時(shí),出現(xiàn) 命名沖突、污染作用域 等問題。
AMD:
瀏覽器端模塊解決方案。
AMD即是“異步模塊定義”。
在AMD規(guī)范中,我們使用define定義模塊,使用require加載模塊。
提前執(zhí)行:它采用異步方式加載模塊,一邊加載一邊執(zhí)行。
依賴前置:依賴必須在定義時(shí)引入。
CMD:
瀏覽器端模塊解決方案。
CMD即是“通用模塊定義”。
在CMD規(guī)范中,我們使用define定義模塊,使用require加載模塊。
延遲執(zhí)行:它采用異步方式加載模塊,先加載完畢再按需執(zhí)行。
依賴就近:依賴可以在代碼的任意一行引入。
CommonJS:
服務(wù)器端模塊解決方案。
在CommonJS規(guī)范中,我們使用module.exports導(dǎo)出模塊,使用require加載模塊。
立即執(zhí)行:它采用同步方式加載模塊,先加載后執(zhí)行,執(zhí)行完畢會被緩存。
依賴就近:依賴可以在代碼的任意一行引入。
ESModule:
瀏覽器端 和 服務(wù)器端 通用的模塊解決方案。
在ESModule規(guī)范中,我們使用export導(dǎo)出模塊,使用import加載模塊。
延遲執(zhí)行:它采用異步方式加載模塊,先加載完畢再按需執(zhí)行。
依賴就近:依賴可以在代碼的任意一行引入。
二十四、說一下DOM的操作有哪些?
查:
- document.querySelector('選擇器') --- 獲取單個(gè)節(jié)點(diǎn)。
- document.querySelectorAll('選擇器') --- 獲取多個(gè)節(jié)點(diǎn),偽數(shù)組。
- parentNode:獲取父節(jié)點(diǎn)。
- children: 獲取子節(jié)點(diǎn) --- 偽數(shù)組。
- nextElementSibling:獲取下一個(gè)兄弟。
- previousElementSibling:獲取上一個(gè)兄弟。
增:
- appendChild:添加節(jié)點(diǎn)到最后。
- insertBefore:在某個(gè)元素前面插入。
- cloneNode:克隆節(jié)點(diǎn)。
刪:
- removeChild:刪除子節(jié)點(diǎn)。
- remove:刪除節(jié)點(diǎn)。
改:
- replaceChild:修改子節(jié)點(diǎn)
屬性操作:
- getAttribute:獲取屬性。
- setAttribute:設(shè)置屬性。
內(nèi)容操作:
- innerHTML:獲取/設(shè)置代碼內(nèi)容。
- innerText:獲取/設(shè)置文本內(nèi)容。
二十五、說一下對象創(chuàng)建模式有哪些?
對象字面量(花括號)。
工廠模式(對象字面量 + return新對象)。
Object構(gòu)造函數(shù)(new Object)。
構(gòu)造函數(shù)模式(new function + 屬性、方法都在構(gòu)造函數(shù)上)。
原型模式(new function + 屬性、方法都在原型上)。
組合模式(屬性在構(gòu)造函數(shù)上 + 方法在原型上)。
類(底層就是對 組合模式 進(jìn)行了封裝)。
二十六、說一下對象繼承模式有哪些?
原型鏈繼承(子類原型指向父類實(shí)例)。
構(gòu)造函數(shù)繼承(借助 call)。
組合繼承(原型鏈繼承 + 構(gòu)造函數(shù)繼承)。
原型式繼承(借助 Object.create)。
寄生式繼承(原型式繼承 + 添加子類方法)。
寄生組合繼承(寄生式繼承 + 組合繼承)
extends(底層就是對 寄生組合繼承 進(jìn)行了封裝)
二十七、說一下執(zhí)行上下文的理解?
在 代碼執(zhí)行前 產(chǎn)生。
產(chǎn)生變量提升、函數(shù)提升的原因。
定義:
- 全局執(zhí)行上下文對象:在執(zhí)行全局代碼前,創(chuàng)建對應(yīng)的全局執(zhí)行上下文對象,即window對象,進(jìn)行預(yù)處理
- 函數(shù)執(zhí)行上下文對象:在調(diào)用函數(shù)后、準(zhǔn)備執(zhí)行函數(shù)體之前,創(chuàng)建對應(yīng)的函數(shù)執(zhí)行上下文對象,進(jìn)行預(yù)處理
- 塊級私有執(zhí)行上下文對象:在執(zhí)行塊級代碼前,創(chuàng)建對應(yīng)的塊級私有執(zhí)行上下文對象,進(jìn)行預(yù)處理
執(zhí)行上下文棧:
存放執(zhí)行上下文對象的棧。
按照上下文對象創(chuàng)建的次序進(jìn)棧,然后從棧頂依次執(zhí)行出棧。
二十八、說一下什么是作用域、作用域鏈?
在代碼編寫時(shí)產(chǎn)生。
定義:
- 全局作用域:全局執(zhí)行上下文對象的有效作用范圍。
- 函數(shù)作用域:函數(shù)執(zhí)行上下文對象的有效作用范圍。
- 塊作用域:塊級私有執(zhí)行上下文對象的有效作用范圍。
作用域鏈:
在某一作用域內(nèi)找某一變量時(shí),先在自身作用域內(nèi)的執(zhí)行上下文對象中找,找不到再去父作用域內(nèi)的執(zhí)行上下文對象中找,依次向上找,直到全局作用域內(nèi)的執(zhí)行上下文對象為止。這個(gè)過程稱為作用域鏈。