UDP協(xié)議為什么不可靠?
UDP在傳輸數(shù)據(jù)之前不需要先建立連接,遠(yuǎn)地主機(jī)的運(yùn)輸層在接收到UDP報(bào)文后,不需要確認(rèn),提供不可靠交付。總結(jié)就以下四點(diǎn):
- 不保證消息交付:不確認(rèn),不重傳,無超時(shí)
- 不保證交付順序:不設(shè)置包序號(hào),不重排,不會(huì)發(fā)生隊(duì)首阻塞
- 不跟蹤連接狀態(tài):不必建立連接或重啟狀態(tài)機(jī)
- 不進(jìn)行擁塞控制:不內(nèi)置客戶端或網(wǎng)絡(luò)反饋機(jī)制
瀏覽器是如何對(duì) HTML5 的離線儲(chǔ)存資源進(jìn)行管理和加載?
- 在線的情況下,瀏覽器發(fā)現(xiàn) html 頭部有 manifest 屬性,它會(huì)請(qǐng)求 manifest 文件,如果是第一次訪問頁面 ,那么瀏覽器就會(huì)根據(jù) manifest 文件的內(nèi)容下載相應(yīng)的資源并且進(jìn)行離線存儲(chǔ)。如果已經(jīng)訪問過頁面并且資源已經(jīng)進(jìn)行離線存儲(chǔ)了,那么瀏覽器就會(huì)使用離線的資源加載頁面,然后瀏覽器會(huì)對(duì)比新的 manifest 文件與舊的 manifest 文件,如果文件沒有發(fā)生改變,就不做任何操作,如果文件改變了,就會(huì)重新下載文件中的資源并進(jìn)行離線存儲(chǔ)。
- 離線的情況下,瀏覽器會(huì)直接使用離線存儲(chǔ)的資源。
說一下類組件和函數(shù)組件的區(qū)別?
1. 語法上的區(qū)別:
函數(shù)式組件是一個(gè)純函數(shù),它是需要接受props參數(shù)并且返回一個(gè)React元素就可以了。類組件是需要繼承React.Component的,而且class組件需要?jiǎng)?chuàng)建render并且返回React元素,語法上來講更復(fù)雜。
2. 調(diào)用方式
函數(shù)式組件可以直接調(diào)用,返回一個(gè)新的React元素;類組件在調(diào)用時(shí)是需要?jiǎng)?chuàng)建一個(gè)實(shí)例的,然后通過調(diào)用實(shí)例里的render方法來返回一個(gè)React元素。
3. 狀態(tài)管理
函數(shù)式組件沒有狀態(tài)管理,類組件有狀態(tài)管理。
4. 使用場(chǎng)景
類組件沒有具體的要求。函數(shù)式組件一般是用在大型項(xiàng)目中來分割大組件(函數(shù)式組件不用創(chuàng)建實(shí)例,所有更高效),一般情況下能用函數(shù)式組件就不用類組件,提升效率。
復(fù)制代碼
Set 和 Map有什么區(qū)別?
1、Map是鍵值對(duì),Set是值得集合,當(dāng)然鍵和值可以是任何得值
2、Map可以通過get方法獲取值,而set不能因?yàn)樗挥兄?3、都能通過迭代器進(jìn)行for...of 遍歷
4、Set的值是唯一的可以做數(shù)組去重,而Map由于沒有格式限制,可以做數(shù)據(jù)存儲(chǔ)
復(fù)制代碼
說一說js是什么語言
JavaScript是一種直譯式腳本語言,是一種動(dòng)態(tài)類型、弱類型、基于原型的語言,內(nèi)置支持類型。它的解釋器被稱為JavaScript引擎,為瀏覽器的一部分,廣泛用于客戶端的腳本語言,最早是在HTML(標(biāo)準(zhǔn)通用標(biāo)記語言下的一個(gè)應(yīng)用)網(wǎng)頁上使用,用來給HTML網(wǎng)頁增加動(dòng)態(tài)功能。
js語言是弱語言類型, 因此我們?cè)陧?xiàng)目開發(fā)中當(dāng)我們隨意更該某個(gè)變量的數(shù)據(jù)類型后
有可能會(huì)導(dǎo)致其他引用這個(gè)變量的方法中報(bào)錯(cuò)等等。
復(fù)制代碼
說說瀏覽器緩存
緩存可以減少網(wǎng)絡(luò) IO 消耗,提高訪問速度。瀏覽器緩存是一種操作簡(jiǎn)單、效果顯著的前端性能優(yōu)化手段
很多時(shí)候,大家傾向于將瀏覽器緩存簡(jiǎn)單地理解為“HTTP 緩存”。
但事實(shí)上,瀏覽器緩存機(jī)制有四個(gè)方面,它們按照獲取資源時(shí)請(qǐng)求的優(yōu)先級(jí)依次排列如下:
Memory Cache
Service Worker Cache
HTTP Cache
Push Cache
緩存它又分為強(qiáng)緩存和協(xié)商緩存。優(yōu)先級(jí)較高的是強(qiáng)緩存,在命中強(qiáng)緩存失敗的情況下,才會(huì)走協(xié)商緩存
實(shí)現(xiàn)強(qiáng)緩存,過去我們一直用 expires。 當(dāng)服務(wù)器返回響應(yīng)時(shí),在 Response Headers 中將過期時(shí)間寫入 expires 字段,現(xiàn)在一般使用Cache-Control 兩者同時(shí)出現(xiàn)使用Cache-Control 協(xié)商緩存,Last-Modified 是一個(gè)時(shí)間戳,如果我們啟用了協(xié)商緩存,它會(huì)在首次請(qǐng)求時(shí)隨著 Response Headers 返回:每次請(qǐng)求去判斷這個(gè)時(shí)間戳是否發(fā)生變化。 從而去決定你是304讀取緩存還是給你返回最新的數(shù)據(jù)
復(fù)制代碼
原型
構(gòu)造函數(shù)是一種特殊的方法,主要用來在創(chuàng)建對(duì)象時(shí)初始化對(duì)象。每個(gè)構(gòu)造函數(shù)都有prototype(原型)(箭頭函數(shù)以及Function.prototype.bind()沒有)屬性,
這個(gè)prototype(原型)屬性是一個(gè)指針,指向一個(gè)對(duì)象,這個(gè)對(duì)象的用途是包含特定類型的所有實(shí)例共享的
屬性和方法,即這個(gè)原型對(duì)象是用來給實(shí)例對(duì)象共享屬性和方法的。每個(gè)實(shí)例對(duì)象的__proto__都指向這個(gè)
構(gòu)造函數(shù)/類的prototype屬性。
面向?qū)ο蟮娜筇匦裕豪^承/多態(tài)/封裝
關(guān)于new操作符:
1. new執(zhí)行的函數(shù), 函數(shù)內(nèi)部默認(rèn)生成了一個(gè)對(duì)象
2. 函數(shù)內(nèi)部的this默認(rèn)指向了這個(gè)new生成的對(duì)象
3. new執(zhí)行函數(shù)生成的這個(gè)對(duì)象, 是函數(shù)的默認(rèn)返回值
ES5例子:
function Person(obj) {
this.name = obj.name
this.age= obj.age
}
// 原型方法
Person.prototype.say = function() {
console.log('你好,', this.name )
}
// p為實(shí)例化對(duì)象,new Person()這個(gè)操作稱為構(gòu)造函數(shù)的實(shí)例化
let p = new Person({name: '番茄', age: '27'})
console.log(p.name, p.age)
p.say()
ES6例子:
class Person{
constructor(obj) {
this.name = obj.name
this.age= obj.age
}
say() {
console.log(this.name)
}
}
let p = new Person({name: 'ES6-番茄', age: '27'})
console.log(p.name, p.age)
p.say()
復(fù)制代碼
webpack配置入口出口
module.exports={
//入口文件的配置項(xiàng)
entry:{},
//出口文件的配置項(xiàng)
output:{},
//模塊:例如解讀CSS,圖片如何轉(zhuǎn)換,壓縮
module:{},
//插件,用于生產(chǎn)模版和各項(xiàng)功能
plugins:[],
//配置webpack開發(fā)服務(wù)功能
devServer:{}
}
簡(jiǎn)單描述了一下這幾個(gè)屬性是干什么的。
描述一下npm run dev / npm run build執(zhí)行的是哪些文件
通過配置proxyTable來達(dá)到開發(fā)環(huán)境跨域的問題,然后又可以擴(kuò)展和他聊聊跨域的產(chǎn)生,如何跨域
最后可以在聊聊webpack的優(yōu)化,例如babel-loader的優(yōu)化,gzip壓縮等等
復(fù)制代碼
說一下vue3.0你了解多少?
<!-- 響應(yīng)式原理的改變 Vue3.x 使用Proxy取代 Vue2.x 版本的Object.defineProperty -->
<!-- 組件選項(xiàng)聲明方式Vue3.x 使用Composition API setup 是Vue3.x新增的一個(gè)選項(xiàng),他
是組件內(nèi)使用Composition API 的入口 -->
<!-- 模板語法變化slot具名插槽語法 自定義指令 v-model 升級(jí) -->
<!-- 其它方面的更改Suspense支持Fragment(多個(gè)根節(jié)點(diǎn)) 和Protal (在dom其他部分渲染組建內(nèi)容)組件
針對(duì)一些特殊的場(chǎng)景做了處理。基于treeshaking優(yōu)化,提供了更多的內(nèi)置功能。 -->
復(fù)制代碼
你在工作終于到那些問題,解決方法是什么
經(jīng)常遇到的問題就是Cannot read property ‘prototype’ of undefined
解決辦法通過瀏覽器報(bào)錯(cuò)提示代碼定位問題,解決問題
Vue項(xiàng)目中遇到視圖不更新,方法不執(zhí)行,埋點(diǎn)不觸發(fā)等問題
一般解決方案查看瀏覽器報(bào)錯(cuò),查看代碼運(yùn)行到那個(gè)階段未之行結(jié)束,閱讀源碼以及相關(guān)文檔等
然后舉出來最近開發(fā)的項(xiàng)目中遇到的算是兩個(gè)比較大的問題。
復(fù)制代碼
說一下data為什么是一個(gè)函數(shù)而不是一個(gè)對(duì)象?
JavaScript中的對(duì)象是引用類型的數(shù)據(jù),當(dāng)多個(gè)實(shí)例引用同一個(gè)對(duì)象時(shí),只要一個(gè)實(shí)例對(duì)這個(gè)對(duì)象進(jìn)行操作,其他實(shí)例中的數(shù)據(jù)也會(huì)發(fā)生變化。而在Vue中,我們更多的是想要復(fù)用組件,那就需要每個(gè)組件都有自己的數(shù)據(jù),這樣組件之間才不會(huì)相互干擾。所以組件的數(shù)據(jù)不能寫成對(duì)象的形式,而是要寫成函數(shù)的形式。數(shù)據(jù)以函數(shù)返回值的形式定義,這樣當(dāng)我們每次復(fù)用組件的時(shí)候,就會(huì)返回一個(gè)新的data,也就是說每個(gè)組件都有自己的私有數(shù)據(jù)空間,它們各自維護(hù)自己的數(shù)據(jù),不會(huì)干擾其他組件的正常運(yùn)行。
說一下常見的git操作
git branch 查看本地所有分支
git status 查看當(dāng)前狀態(tài)
git commit 提交
git branch -a 查看所有的分支
git branch -r 查看遠(yuǎn)程所有分支
git commit -am "nit" 提交并且加注釋
git remote add origin git@192.168.1.119:ndshow
git push origin master 將文件給推到服務(wù)器上
git remote show origin 顯示遠(yuǎn)程庫origin里的資源
git push origin master:develop
git push origin master:hb-dev 將本地庫與服務(wù)器上的庫進(jìn)行關(guān)聯(lián)
git checkout --track origin/dev 切換到遠(yuǎn)程dev分支
git branch -D master develop 刪除本地庫develop
git checkout -b dev 建立一個(gè)新的本地分支dev
git merge origin/dev 將分支dev與當(dāng)前分支進(jìn)行合并
git checkout dev 切換到本地dev分支
git remote show 查看遠(yuǎn)程庫
git add .
git rm 文件名(包括路徑) 從git中刪除指定文件
git clone git://github.com/schacon/grit.git 從服務(wù)器上將代碼給拉下來
git config --list 看所有用戶
git ls-files 看已經(jīng)被提交的
git rm [file name] 刪除一個(gè)文件
git commit -a 提交當(dāng)前repos的所有的改變
git add [file name] 添加一個(gè)文件到git index
git commit -v 當(dāng)你用-v參數(shù)的時(shí)候可以看commit的差異
git commit -m "This is the message describing the commit" 添加commit信息
git commit -a -a是代表add,把所有的change加到git index里然后再commit
git commit -a -v 一般提交命令
git log 看你commit的日志
git diff 查看尚未暫存的更新
git rm a.a 移除文件(從暫存區(qū)和工作區(qū)中刪除)
git rm --cached a.a 移除文件(只從暫存區(qū)中刪除)
git commit -m "remove" 移除文件(從Git中刪除)
git rm -f a.a 強(qiáng)行移除修改后文件(從暫存區(qū)和工作區(qū)中刪除)
git diff --cached 或 $ git diff --staged 查看尚未提交的更新
git stash push 將文件給push到一個(gè)臨時(shí)空間中
git stash pop 將文件從臨時(shí)空間pop下來
webpack3和webpack4區(qū)別
1.mode
webpack增加了一個(gè)mode配置,只有兩種值development | production。對(duì)不同的環(huán)境他會(huì)啟用不同的配置。
2.CommonsChunkPlugin
CommonChunksPlugin已經(jīng)從webpack4中移除。
可使用optimization.splitChunks進(jìn)行模塊劃分(提取公用代碼)。
但是需要注意一個(gè)問題,默認(rèn)配置只會(huì)對(duì)異步請(qǐng)求的模塊進(jìn)行提取拆分,如果要對(duì)entry進(jìn)行拆分
需要設(shè)置optimization.splitChunks.chunks = 'all'。
3.webpack4使用MiniCssExtractPlugin取代ExtractTextWebpackPlugin。
4.代碼分割。
使用動(dòng)態(tài)import,而不是用system.import或者require.ensure
5.vue-loader。
使用vue-loader插件為.vue文件中的各部分使用相對(duì)應(yīng)的loader,比如css-loader等
6.UglifyJsPlugin
現(xiàn)在也不需要使用這個(gè)plugin了,只需要使用optimization.minimize為true就行,production mode下面自動(dòng)為true
optimization.minimizer可以配置你自己的壓縮程序
復(fù)制代碼
New操作符做了什么事情?
1、首先創(chuàng)建了一個(gè)新對(duì)象
2、設(shè)置原型,將對(duì)象的原型設(shè)置為函數(shù)的prototype對(duì)象
3、讓函數(shù)的this指向這個(gè)對(duì)象,執(zhí)行構(gòu)造函數(shù)的代碼(為這個(gè)新對(duì)象添加屬性)
4、判斷函數(shù)的返回值類型,如果是值類型,返回創(chuàng)建的對(duì)象。如果是引用類型,就返回這個(gè)引用類型的對(duì)象
復(fù)制代碼
JS閉包,你了解多少?
應(yīng)該有面試官問過你:
- 什么是閉包?
- 閉包有哪些實(shí)際運(yùn)用場(chǎng)景?
- 閉包是如何產(chǎn)生的?
- 閉包產(chǎn)生的變量如何被回收?
這些問題其實(shí)都可以被看作是同一個(gè)問題,那就是面試官在問你:你對(duì)JS閉包了解多少?
來總結(jié)一下我聽到過的答案,盡量完全復(fù)原候選人面試的時(shí)候說的原話。
答案1:
就是一個(gè)function
里面return
了一個(gè)子函數(shù),子函數(shù)訪問了外面那個(gè)函數(shù)的變量。
答案2:
for循環(huán)里面可以用閉包來解決問題。
for(var i = 0; i < 10; i++){
setTimeout(()=>console.log(i),0)
}
// 控制臺(tái)輸出10遍10.
for(var i = 0; i < 10; i++){
(function(a){
setTimeout(()=>console.log(a),0)
})(i)
}
// 控制臺(tái)輸出0-9
復(fù)制代碼
答案3:
當(dāng)前作用域產(chǎn)產(chǎn)生了對(duì)父作用域的引用。
答案4:
不知道。是跟瀏覽器的垃圾回收機(jī)制有關(guān)嗎?
開杠了。請(qǐng)問,小伙伴的答案和以上的內(nèi)容有多少相似程度?
其實(shí),拿著這些問題好好想想,你就會(huì)發(fā)現(xiàn)這些問題都只是為了最終那一個(gè)問題。
閉包的底層實(shí)現(xiàn)原理
1. JS執(zhí)行上下文
我們都知道,我們手寫的js代碼是要經(jīng)過瀏覽器V8進(jìn)行預(yù)編譯后才能真正的被執(zhí)行。例如變量提升、函數(shù)提升。舉個(gè)栗子。
// 栗子:
var d = 'abc';
function a(){
console.log("函數(shù)a");
};
console.log(a); // ? a(){ console.log("函數(shù)a"); }
a(); // '函數(shù)a'
var a = "變量a";
console.log(a); // '變量a'
a(); // a is not a function
var c = 123;
// 輸出結(jié)果及順序:
// ? a(){ console.log("函數(shù)a"); }
// '函數(shù)a'
// '變量a'
// a is not a function
// 栗子預(yù)編后相當(dāng)于:
function a(){
console.log("函數(shù)a");
};
var d;
console.log(a); // ? a(){ console.log("函數(shù)a"); }
a(); // '函數(shù)a'
a = "變量a"; // 此時(shí)變量a賦值,函數(shù)聲明被覆蓋
console.log(a); // "變量a"
a(); // a is not a function
復(fù)制代碼
那么問題來了。 請(qǐng)問是誰來執(zhí)行預(yù)編譯操作的?那這個(gè)誰又是在哪里進(jìn)行預(yù)編譯的?
是的,你的疑惑沒有錯(cuò)。js代碼運(yùn)行需要一個(gè)運(yùn)行環(huán)境,那這個(gè)環(huán)境就是執(zhí)行上下文。 是的,js運(yùn)行前的預(yù)編譯也是在這個(gè)環(huán)境中進(jìn)行。
js執(zhí)行上下文分三種:
-
全局執(zhí)行上下文
: 代碼開始執(zhí)行時(shí)首先進(jìn)入的環(huán)境。 -
函數(shù)執(zhí)行上下文
:函數(shù)調(diào)用時(shí),會(huì)開始執(zhí)行函數(shù)中的代碼。 -
eval執(zhí)行上下文
:不建議使用,可忽略。
那么,執(zhí)行上下文的周期,分為兩個(gè)階段:
-
創(chuàng)建階段
- 創(chuàng)建詞法環(huán)境
- 生成變量對(duì)象(
VO
),建立作用域鏈、作用域鏈、作用域鏈(重要的事說三遍) - 確認(rèn)
this
指向,并綁定this
-
執(zhí)行階段
。這個(gè)階段進(jìn)行變量賦值,函數(shù)引用及執(zhí)行代碼。
你現(xiàn)在猜猜看,預(yù)編譯是發(fā)生在什么時(shí)候?
噢,我忘記說了,其實(shí)與編譯還有另一個(gè)稱呼:執(zhí)行期上下文
。
預(yù)編譯發(fā)生在函數(shù)執(zhí)行之前。預(yù)編譯四部曲為:
- 創(chuàng)建
AO
對(duì)象 - 找形參和變量聲明,將變量和形參作為AO屬性名,值為
undefined
- 將實(shí)參和形參相統(tǒng)一
- 在函數(shù)體里找到函數(shù)聲明,值賦予函數(shù)體。最后程序輸出變量值的時(shí)候,就是從
AO
對(duì)象中拿。
所以,預(yù)編譯真正的結(jié)果是:
var AO = {
a = function a(){console.log("函數(shù)a");};
d = 'abc'
}
復(fù)制代碼
我們重新來。
1. 什么叫變量對(duì)象?
變量對(duì)象是 js
代碼在進(jìn)入執(zhí)行上下文時(shí),js
引擎在內(nèi)存中建立的一個(gè)對(duì)象,用來存放當(dāng)前執(zhí)行環(huán)境中的變量。
2. 變量對(duì)象(VO)的創(chuàng)建過程
變量對(duì)象的創(chuàng)建,是在執(zhí)行上下文創(chuàng)建階段,依次經(jīng)過以下三個(gè)過程:
-
創(chuàng)建
arguments
對(duì)象。對(duì)于函數(shù)執(zhí)行環(huán)境,首先查詢是否有傳入的實(shí)參,如果有,則會(huì)將參數(shù)名是實(shí)參值組成的鍵值對(duì)放入
arguments
對(duì)象中。否則,將參數(shù)名和undefined
組成的鍵值對(duì)放入arguments
對(duì)象中。
//舉個(gè)栗子
function bar(a, b, c) {
console.log(arguments); // [1, 2]
console.log(arguments[2]); // undefined
}
bar(1,2)
復(fù)制代碼
- 當(dāng)遇到同名的函數(shù)時(shí),后面的會(huì)覆蓋前面的。
console.log(a); // function a() {console.log('Is a ?') }
function a() {
console.log('Is a');
}
function a() {
console.log('Is a ?')
}
/**ps: 在執(zhí)行第一行代碼之前,函數(shù)聲明已經(jīng)創(chuàng)建完成.后面的對(duì)之前的聲明進(jìn)行了覆蓋。**/
復(fù)制代碼
- 檢查當(dāng)前環(huán)境中的變量聲明并賦值為
undefined
。當(dāng)遇到同名的函數(shù)聲明,為了避免函數(shù)被賦值為undefined
,會(huì)忽略此聲明
console.log(a); // function a() {console.log('Is a ?') }
console.log(b); // undefined
function a() {
console.log('Is a ');
}
function a() {
console.log('Is a ?');
}
var b = 'Is b';
var a = 10086;
/**這段代碼執(zhí)行一下,你會(huì)發(fā)現(xiàn) a 打印結(jié)果仍舊是一個(gè)函數(shù),而 b 則是 undefined。**/
復(fù)制代碼
根據(jù)以上三個(gè)步驟,對(duì)于變量提升也就知道是怎么回事了。
3. 變量對(duì)象變?yōu)榛顒?dòng)對(duì)象
執(zhí)行上下文的第二個(gè)階段,稱為執(zhí)行階段,在此時(shí),會(huì)進(jìn)行變量賦值,函數(shù)引用并執(zhí)行其他代碼,此時(shí),變量對(duì)象變?yōu)榛顒?dòng)對(duì)象。
我們還是舉上面的例子:
console.log(a); // function a() {console.log('fjdsfs') }
console.log(b); // undefined
function a() {
console.log('Is a');
}
function a() {
console.log('Is a?');
}
var b = 'Is b';
console.log(b); // 'Is b'
var a = 10086;
console.log(a); // 10086
var b = 'Is b?';
console.log(b); // 'Is b?'
復(fù)制代碼
在上面的代碼中,代碼真正開始執(zhí)行是從第一行 console.log() 開始的,自這之前,執(zhí)行上下文是這樣的:
// 創(chuàng)建過程
EC= {
VO: {}; // 創(chuàng)建變量對(duì)象
scopeChain: {}; // 作用域鏈
}
VO = {
argument: {...}; // 當(dāng)前為全局上下文,所以這個(gè)屬性值是空的
a: <a reference> // 函數(shù) a 的引用地址 b: undefiend // 見上文創(chuàng)建變量對(duì)象的第三步}
復(fù)制代碼
詞法作用域(Lexical scope
)
這里想說明,我們?cè)诤瘮?shù)執(zhí)行上下文中有變量,在全局執(zhí)行上下文中有變量。JavaScript
的一個(gè)復(fù)雜之處在于它如何查找變量,如果在函數(shù)執(zhí)行上下文中找不到變量,它將在調(diào)用上下文中尋找它,如果在它的調(diào)用上下文中沒有找到,就一直往上一級(jí),直到它在全局執(zhí)行上下文中查找為止。(如果最后找不到,它就是 undefined
)。
再來舉個(gè)栗子:
1: let top = 0; //
2: function createWarp() {
3: function add(a, b) {
4: let ret = a + b
5: return ret
6: }
7: return add
8: }
9: let sum = createWarp()
10: let result = sum(top, 8)
11: console.log('result:',result)
復(fù)制代碼
分析過程如下:
- 在全局上下文中聲明變量
top
并賦值為0. - 2 - 8行。在全局執(zhí)行上下文中聲明了一個(gè)名為
createWarp
的變量,并為其分配了一個(gè)函數(shù)定義。其中第3-7行描述了其函數(shù)定義,并將函數(shù)定義存儲(chǔ)到那個(gè)變量(createWarp
)中。 - 第9行。我們?cè)谌謭?zhí)行上下文中聲明了一個(gè)名為
sum
的新變量,暫時(shí),值為undefined
。 - 第9行。遇到
()
,表明需要執(zhí)行或調(diào)用一個(gè)函數(shù)。那么查找全局執(zhí)行上下文的內(nèi)存并查找名為createWarp
的變量。 明顯,已經(jīng)在步驟2中創(chuàng)建完畢。接著,調(diào)用它。 - 調(diào)用函數(shù)時(shí),回到第2行。創(chuàng)建一個(gè)新的
createWarp
執(zhí)行上下文。我們可以在createWarp
的執(zhí)行上下文中創(chuàng)建自有變量。js
引擎createWarp
的上下文添加到調(diào)用堆棧(call stack
)。因?yàn)檫@個(gè)函數(shù)沒有參數(shù),直接跳到它的主體部分. - 3 - 6 行。我們有一個(gè)新的函數(shù)聲明,在
createWarp
執(zhí)行上下文中創(chuàng)建一個(gè)變量add
。add
只存在于createWarp
執(zhí)行上下文中, 其函數(shù)定義存儲(chǔ)在名為add
的自有變量中。 - 第7行,我們返回變量
add
的內(nèi)容。js引擎查找一個(gè)名為add
的變量并找到它. 第4行和第5行括號(hào)之間的內(nèi)容構(gòu)成該函數(shù)定義。 -
createWarp
調(diào)用完畢,createWarp
執(zhí)行上下文將被銷毀。add 變量也跟著被銷毀。 但add
函數(shù)定義仍然存在,因?yàn)樗祷夭①x值給了sum
變量。 (ps:這才是閉包產(chǎn)生的變量存于內(nèi)存當(dāng)中的真相
) - 接下來就是簡(jiǎn)單的執(zhí)行過程,不再贅述。。
- ……
- 代碼執(zhí)行完畢,全局執(zhí)行上下文被銷毀。sum 和 result 也跟著被銷毀。
小結(jié)一下
現(xiàn)在,如果再讓你回答什么是閉包,你能答出多少?
其實(shí),大家說的都對(duì)。不管是函數(shù)返回一個(gè)函數(shù),還是產(chǎn)生了外部作用域的引用,都是有道理的。
所以,什么是閉包?
- 解釋一下作用域鏈?zhǔn)侨绾萎a(chǎn)生的。
- 解釋一下js執(zhí)行上下文的創(chuàng)建、執(zhí)行過程。
- 解釋一下閉包所產(chǎn)生的變量放在哪了。
- 最后請(qǐng)把以上3點(diǎn)結(jié)合起來說給面試官聽。
深拷貝淺拷貝
淺拷貝:淺拷貝通過ES6新特性O(shè)bject.assign()或者通過擴(kuò)展運(yùn)算法...來達(dá)到淺拷貝的目的,淺拷貝修改
副本,不會(huì)影響原數(shù)據(jù),但缺點(diǎn)是淺拷貝只能拷貝第一層的數(shù)據(jù),且都是值類型數(shù)據(jù),如果有引用型數(shù)據(jù),修改
副本會(huì)影響原數(shù)據(jù)。
深拷貝:通過利用JSON.parse(JSON.stringify())來實(shí)現(xiàn)深拷貝的目的,但利用JSON拷貝也是有缺點(diǎn)的,
當(dāng)要拷貝的數(shù)據(jù)中含有undefined/function/symbol類型是無法進(jìn)行拷貝的,當(dāng)然我們想項(xiàng)目開發(fā)中需要
深拷貝的數(shù)據(jù)一般不會(huì)含有以上三種類型,如有需要可以自己在封裝一個(gè)函數(shù)來實(shí)現(xiàn)。
復(fù)制代碼
說一下你對(duì)盒模型的理解?
CSS3中的盒模型有以下兩種:標(biāo)準(zhǔn)盒模型、IE盒模型
盒模型都是由四個(gè)部分組成的,分別是margin、border、padding和content
標(biāo)準(zhǔn)盒模型和IE盒模型的區(qū)別在于設(shè)置width和height時(shí), 所對(duì)應(yīng)的范圍不同
1、標(biāo)準(zhǔn)盒模型的width和height屬性的范圍只包含了content
2、IE盒模型的width和height屬性的范圍包含了border、padding和content
可以通過修改元素的box-sizing屬性來改變?cè)氐暮心P停?1、box-sizing:content-box表示標(biāo)準(zhǔn)盒模型(默認(rèn)值)
2、box-sizing:border-box表示IE盒模型(怪異盒模型)
復(fù)制代碼
CDN的作用
CDN一般會(huì)用來托管Web資源(包括文本、圖片和腳本等),可供下載的資源(媒體文件、軟件、文檔等),應(yīng)用程序(門戶網(wǎng)站等)。使用CDN來加速這些資源的訪問。
(1)在性能方面,引入CDN的作用在于:
- 用戶收到的內(nèi)容來自最近的數(shù)據(jù)中心,延遲更低,內(nèi)容加載更快
- 部分資源請(qǐng)求分配給了CDN,減少了服務(wù)器的負(fù)載
(2)在安全方面,CDN有助于防御DDoS、MITM等網(wǎng)絡(luò)攻擊:
- 針對(duì)DDoS:通過監(jiān)控分析異常流量,限制其請(qǐng)求頻率
- 針對(duì)MITM:從源服務(wù)器到 CDN 節(jié)點(diǎn)到 ISP(Internet Service Provider),全鏈路 HTTPS 通信
除此之外,CDN作為一種基礎(chǔ)的云服務(wù),同樣具有資源托管、按需擴(kuò)展(能夠應(yīng)對(duì)流量高峰)等方面的優(yōu)勢(shì)。
代碼輸出結(jié)果
Promise.resolve().then(() => {
return new Error('error!!!')
}).then(res => {
console.log("then: ", res)
}).catch(err => {
console.log("catch: ", err)
})
復(fù)制代碼
輸出結(jié)果如下:
"then: " "Error: error!!!"
復(fù)制代碼
返回任意一個(gè)非 promise 的值都會(huì)被包裹成 promise 對(duì)象,因此這里的return new Error('error!!!')
也被包裹成了return Promise.resolve(new Error('error!!!'))
,因此它會(huì)被then捕獲而不是catch。
Vuex有哪些基本屬性?為什么 Vuex 的 mutation 中不能做異步操作?
有五種,分別是 State、 Getter、Mutation 、Action、 Module
1、state => 基本數(shù)據(jù)(數(shù)據(jù)源存放地)
2、getters => 從基本數(shù)據(jù)派生出來的數(shù)據(jù)
3、mutations => 提交更改數(shù)據(jù)的方法,同步
4、actions => 像一個(gè)裝飾器,包裹mutations,使之可以異步。
5、modules => 模塊化Vuex
1、Vuex中所有的狀態(tài)更新的唯一途徑都是mutation,異步操作通過 Action 來提交 mutation實(shí)現(xiàn),這樣可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而能夠?qū)崿F(xiàn)一些工具幫助更好地了解我們的應(yīng)用。
2、每個(gè)mutation執(zhí)行完成后都會(huì)對(duì)應(yīng)到一個(gè)新的狀態(tài)變更,這樣devtools就可以打個(gè)快照存下來,然后就可以實(shí)現(xiàn) time-travel 了。如果mutation支持異步操作,就沒有辦法知道狀態(tài)是何時(shí)更新的,無法很好的進(jìn)行狀態(tài)的追蹤,給調(diào)試帶來困難。
復(fù)制代碼