JS
Q:常用es6語法
A:let、const餐禁、promise、模板字符串模暗、解構(gòu)賦值岸晦、拓展運(yùn)算符欧啤、箭頭函數(shù)
Q:有哪些遍歷方法?
A:for,foreach,for in,for of,fillter,sort,reduce,map,every,some,Object.keys,Object.values
Q:get启上、post的區(qū)別
A:關(guān)鍵詞:傳參邢隧,大小,緩存冈在,作用倒慧,安全性,編碼格式包券,
1.get傳參方式是通過地址欄URL傳遞纫谅,是可以直接看到get傳遞的參數(shù),post傳參方式參數(shù)URL不可見溅固,get把請(qǐng)求的數(shù)據(jù)在URL后通過付秕?連接,通過&進(jìn)行參數(shù)分割侍郭。psot將參數(shù)存放在HTTP的包體內(nèi)
2.get傳遞數(shù)據(jù)是通過URL進(jìn)行傳遞询吴,對(duì)傳遞的數(shù)據(jù)長(zhǎng)度是受到URL大小的限制掠河,URL最大長(zhǎng)度是2048個(gè)字符。post沒有長(zhǎng)度限制
3.get后退不會(huì)有影響猛计,post后退會(huì)重新進(jìn)行提交
4.get請(qǐng)求可以被瀏覽器自動(dòng)緩存唠摹,post不可以被自動(dòng)緩存,只能通過手動(dòng)設(shè)置緩存
5.get請(qǐng)求只支持URL編碼,
post支持多種編碼方式
如:application/x-www-form-urlencoded
multipart/form-data
application/json
text/xml
6.get請(qǐng)求的記錄會(huì)留在歷史記錄中有滑,post請(qǐng)求不會(huì)留在歷史記錄
7.get只支持ASCII字符跃闹,post沒有字符類型限制
8.get多用于請(qǐng)求數(shù)據(jù),post多用了增刪改查
Q:簡(jiǎn)單說一下事件委托和事件冒泡
A:事件冒泡是指當(dāng)點(diǎn)擊子元素的時(shí)毛好,會(huì)觸發(fā)父元素的方法望艺,可以通過e.stopPropagation()來阻止;
事件委托是指給最高級(jí)的元素添加點(diǎn)擊時(shí)間事件肌访,利用事件冒泡機(jī)制找默,來給其他子元素添加事件
Q:什么是回流和重繪?
A:當(dāng)render tree中的一部分(或全部)因?yàn)樵氐囊?guī)模尺寸吼驶,布局惩激,隱藏等改變而需要重新構(gòu)建。這就稱為回流(reflow)蟹演。每個(gè)頁面至少需要一次回流风钻,就是在頁面第一次加載的時(shí)候,這時(shí)候是一定會(huì)發(fā)生回流的酒请,因?yàn)橐獦?gòu)建render tree骡技。在回流的時(shí)候,瀏覽器會(huì)使渲染樹中受到影響的部分失效羞反,并重新構(gòu)造這部分渲染樹布朦,完成回流后,瀏覽器會(huì)重新繪制受影響的部分到屏幕中昼窗,該過程成為重繪是趴。
當(dāng)render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀澄惊,風(fēng)格唆途,而不會(huì)影響布局的,比如background-color掸驱。則就叫稱為重繪窘哈。
區(qū)別:
他們的區(qū)別很大:
回流必將引起重繪,而重繪不一定會(huì)引起回流亭敢。比如:只有顏色改變的時(shí)候就只會(huì)發(fā)生重繪而不會(huì)引起回流
當(dāng)頁面布局和幾何屬性改變時(shí)就需要回流
比如:添加或者刪除可見的DOM元素滚婉,元素位置改變,元素尺寸改變——邊距帅刀、填充让腹、邊框远剩、寬度和高度,內(nèi)容改變
Q:js的new操作符到底做了什么骇窍?
A:
1瓜晤、創(chuàng)建了一個(gè)空的js對(duì)象(即{})
2、將空對(duì)象的原型prototype指向構(gòu)造函數(shù)的原型
3腹纳、將空對(duì)象作為構(gòu)造函數(shù)的上下文(改變this指向)
4痢掠、對(duì)構(gòu)造函數(shù)有返回值的判斷
在new的時(shí)候,會(huì)對(duì)構(gòu)造函數(shù)的返回值做一些判斷:
1嘲恍、如果返回值是基礎(chǔ)數(shù)據(jù)類型足画,則忽略返回值;
2佃牛、如果返回值是引用數(shù)據(jù)類型淹辞,則使用return 的返回,也就是new操作符無效俘侠;
/*
create函數(shù)要接受不定量的參數(shù)象缀,第一個(gè)參數(shù)是構(gòu)造函數(shù)(也就是new操作符的目標(biāo)函數(shù)),其余參數(shù)被構(gòu)造函數(shù)使用爷速。
new Create() 是一種js語法糖央星。我們可以用函數(shù)調(diào)用的方式模擬實(shí)現(xiàn)
*/
function create(Con,...args){
//1、創(chuàng)建一個(gè)空的對(duì)象
let obj = {}; // let obj = Object.create({});
//2惫东、將空對(duì)象的原型prototype指向構(gòu)造函數(shù)的原型
Object.setPrototypeOf(obj,Con.prototype); // obj.__proto__ = Con.prototype
//3莉给、改變構(gòu)造函數(shù)的上下文(this),并將剩余的參數(shù)傳入
let result = Con.apply(obj,args);
//4、在構(gòu)造函數(shù)有返回值的情況進(jìn)行判斷
return result instanceof Object?result:obj;
}
Q:bind凿蒜,apply,call三者的區(qū)別
A:1.三者都可以改變函數(shù)的this對(duì)象指向胁黑。
2.三者第一個(gè)參數(shù)都是this要指向的對(duì)象废封,如果如果沒有這個(gè)參數(shù)或參數(shù)為undefined或null,則默認(rèn)指向全局window丧蘸。
3.三者都可以傳參漂洋,但是apply是數(shù)組,而bind,call是參數(shù)列表力喷,且apply和call是一次性傳入?yún)?shù)刽漂。
4bind 是返回綁定this之后的函數(shù),便于稍后調(diào)用弟孟;apply 贝咙、call 則是立即執(zhí)行 。
Q:forEach和map方法的區(qū)別
A:1.map()會(huì)分配內(nèi)存空間存儲(chǔ)新數(shù)組并返回拂募,forEach()不會(huì)返回?cái)?shù)據(jù)庭猩。
2.forEach()允許callback更改原始數(shù)組的元素窟她。map()返回新的數(shù)組。
Q:什么是閉包蔼水?
A:1.閉包是指有權(quán)訪問另外一個(gè)函數(shù)作用域中的變量的函數(shù)震糖。可以理解為(能夠讀取另一個(gè)函數(shù)作用域的變量的函數(shù))
2.閉包內(nèi)存泄露只在IE中出現(xiàn)
3.閉包的使用場(chǎng)景:當(dāng)我們需要使一個(gè)函數(shù)訪問外部的變量時(shí)趴腋,可以使用閉包把目標(biāo)函數(shù)嵌套在一個(gè)新函數(shù)中吊说,調(diào)用該新函數(shù),傳入需訪問的變量优炬,則目標(biāo)函數(shù)可以訪問到傳入的變量
Q:原型鏈?zhǔn)鞘裁矗?br> A:每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性颁井,該屬性是函數(shù)的原型對(duì)象,prototype上有constructor穿剖,該屬性指向了函數(shù)本身蚤蔓;構(gòu)造函數(shù)生成一個(gè)實(shí)例對(duì)象后,該實(shí)例對(duì)象上有proto屬性糊余,它指向了函數(shù)的prototype屬性(即原型對(duì)象)秀又;
在訪問對(duì)象的某個(gè)元屬性時(shí)會(huì)先在對(duì)象中找是否存在,
如果當(dāng)前對(duì)象中沒有就在構(gòu)造函數(shù)的原型對(duì)象中找贬芥,
如果原型對(duì)象中沒有找到就到原型對(duì)象的原型上找吐辙,
直到Object的原型對(duì)象的原型是null為止,
這種一層層往上找的關(guān)系就叫原型鏈蘸劈,主要的特性是屬性的共享和繼承
prototype與proto的關(guān)系
prototype是構(gòu)造函數(shù)的屬性昏苏,
proto是實(shí)例對(duì)象的屬性,
這兩者都指向同一個(gè)對(duì)象
Q:webpack打包原理
A:
<ol>
<li>初始化參數(shù):從配置文件和 Shell 語句中讀取與合并參數(shù),得出最終的參數(shù)威沫。</li>
<li>開始編譯:用上一步得到的參數(shù)初始化 Compiler 對(duì)象,加載所有配置的插件,執(zhí)行對(duì)象的 run 方法開始執(zhí)行編譯贤惯。</li>
<li>確定入口:根據(jù)配置中的 entry 找出所有的入口文件。</li>
<li>編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 Loader 對(duì)模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經(jīng)過了本步驟的處理棒掠。</li>
<li>完成模塊編譯:在經(jīng)過第 4 步使用 Loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系孵构。</li>
<li>輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個(gè)個(gè)包含多個(gè)模塊的 Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成一個(gè)單獨(dú)的文件加入到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì)。</li>
<li>輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)烟很。</li>
</ol>
Q:淺拷貝和深拷貝的區(qū)別
A:1.就是假設(shè)B復(fù)制了A颈墅,當(dāng)修改A時(shí),看B是否會(huì)發(fā)生變化雾袱,如果B也跟著變了恤筛,說明這是淺拷貝;反之則是深拷貝
淺拷貝的實(shí)現(xiàn)方法:
1.Object.assign方法
var obj = {
a: 1,
b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
2.直接用=賦值
let a=[0,1,2,3,4],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
**深拷貝的實(shí)現(xiàn)方法:
1.采用遞歸去拷貝所有層級(jí)屬性
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判斷ojb子元素是否為對(duì)象芹橡,如果是毒坛,遞歸復(fù)制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,簡(jiǎn)單復(fù)制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
2.通過JSON對(duì)象來實(shí)現(xiàn)深拷貝
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone;
}
不足:1.無法拷貝 對(duì)象中的方法屬性
2.無法拷貝 對(duì)象中值為undefined的屬性
Q:promise和async/await的區(qū)別
A:async函數(shù)會(huì)隱式地返回一個(gè)promise林说,該promise的reosolve值就是函數(shù)return的值
Q:數(shù)組去重方法
A:1.indexOf查找
function uniq(array){
var temp = []; //一個(gè)新的臨時(shí)數(shù)組
for(var i = 0; i < array.length; i++){
if(temp.indexOf(array[i]) == -1){
temp.push(array[i]);
}
}
return temp;
}
2.includes
function uniq(array){
var temp = []; //一個(gè)新的臨時(shí)數(shù)組
for(var i = 0; i < array.length; i++){
if(!array.include(array[i])){
temp.push(array[i]);
}
}
return temp;
}
3.es6 set去重
let set6 = new Set([1, 2, 2, 3, 4, 3, 5])
console.log('distinct 1:', set6)
Q:垃圾回收機(jī)制
A:一般來說沒有被引用的對(duì)象就屬于垃圾粘驰,瀏覽器會(huì)回收這些對(duì)象
Q:防抖和節(jié)流是什么屡谐?
A:1.防抖:當(dāng)持續(xù)觸發(fā)事件時(shí),一定時(shí)間段內(nèi)沒有再觸發(fā)事件蝌数,事件處理函數(shù)才會(huì)執(zhí)行一次愕掏,如果設(shè)定時(shí)間到來之前,又觸發(fā)了事件顶伞,就重新開始延時(shí)饵撑。也就是說當(dāng)一個(gè)用戶一直觸發(fā)這個(gè)函數(shù),且每次觸發(fā)函數(shù)的間隔小于既定時(shí)間唆貌,那么防抖的情況下只會(huì)執(zhí)行一次滑潘。
function debounce(fn, wait) {
var timeout = null; //定義一個(gè)定時(shí)器
return function() {
if(timeout !== null)
clearTimeout(timeout); //清除這個(gè)定時(shí)器
timeout = setTimeout(fn, wait);
}
}
// 處理函數(shù)
function handle() {
console.log(Math.random());
}
// 滾動(dòng)事件
window.addEventListener('scroll', debounce(handle, 1000));
2.節(jié)流:當(dāng)持續(xù)觸發(fā)事件時(shí),保證在一定時(shí)間內(nèi)只調(diào)用一次事件處理函數(shù)锨咙,意思就是說语卤,假設(shè)一個(gè)用戶一直觸發(fā)這個(gè)函數(shù),且每次觸發(fā)小于既定值酪刀,函數(shù)節(jié)流會(huì)每隔這個(gè)時(shí)間調(diào)用一次
//時(shí)間戳實(shí)現(xiàn)
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this; //this指向window
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
//計(jì)時(shí)器實(shí)現(xiàn)
var throttle = function(func, delay) {
var timer = null;
return function() {
var context = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
Q:說一下什么是跨域粹舵?怎么去解決?
A:跨域是指請(qǐng)求資源的地址與發(fā)起請(qǐng)求的地址不符合同源策略時(shí)骂倘,則為跨域(同源策略眼滤,就是指兩個(gè)地址必須具有相同的協(xié)議、域名历涝、端口號(hào))
解決跨域的方法:
1.jsonp跨域:即在頁面中動(dòng)態(tài)創(chuàng)建<script>標(biāo)簽诅需,然后利用src屬性不受同源策略限制的特性請(qǐng)求資源;
缺點(diǎn):只能發(fā)送get請(qǐng)求
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
2.跨域資源共享(CORS):
CORS是一個(gè)W3C標(biāo)準(zhǔn)荧库,全稱是"跨域資源共享"(Cross-origin resource sharing)堰塌。它允許瀏覽器向跨源服務(wù)器,發(fā)出XMLHttpRequest請(qǐng)求分衫,從而克服了AJAX只能同源使用的限制场刑。
3.vue proxy:
將域名發(fā)送給本地的服務(wù)器(啟動(dòng)vue項(xiàng)目的服務(wù),loclahost:8080),再由本地的服務(wù)器去請(qǐng)求真正的服務(wù)器丐箩。
Q:前端常見的設(shè)計(jì)模式
A:
1.單例模式 :
定義:是保證一個(gè)類只有一個(gè)實(shí)例摇邦,并且提供一個(gè)訪問它的全局訪問點(diǎn)恤煞。
需求:一些對(duì)象我們往往只需要一個(gè)屎勘,比如線程池、全局緩存居扒、瀏覽器中的window對(duì)象概漱、登錄浮窗等。
實(shí)現(xiàn):用一個(gè)變量標(biāo)識(shí)當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對(duì)象喜喂,如果是瓤摧,則在下一次獲取這個(gè)類的實(shí)例時(shí)竿裂,直接返回之前創(chuàng)建的對(duì)象。
優(yōu)點(diǎn):可以用來劃分命名空間照弥,減少全局變量的數(shù)量;可以被實(shí)例化腻异,且實(shí)例化一次,再次實(shí)例化生成的也是第一個(gè)實(shí)例
// 單例模式
var Singleton = function(name){
this.name = name;
this.instance = null;
};
Singleton.prototype.getName = function(){
return this.name;
};
// 獲取實(shí)例對(duì)象
Singleton.getInstance = function(name) {
if(!this.instance) {
this.instance = new Singleton(name);
}
return this.instance;
};
// 測(cè)試單例模式的實(shí)例
var a = Singleton.getInstance("aa");
var b = Singleton.getInstance("bb");
console.log(a===b) // true
2.觀察者模式:
定義:對(duì)象間的一種一對(duì)多的依賴關(guān)系这揣。
需求:當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí)悔常,所有依賴于他的對(duì)象都將得到通知。
優(yōu)點(diǎn):時(shí)間上的解耦给赞,對(duì)象之間的解耦机打。
實(shí)現(xiàn):首先,指定好誰充當(dāng)發(fā)布者片迅;
然后残邀,給發(fā)布者添加一個(gè)緩存列表,用于存放回調(diào)函數(shù)以便通知訂閱者柑蛇;
最后芥挣,發(fā)布消息的時(shí)候,發(fā)布者會(huì)遍歷這個(gè)緩存列表唯蝶,依次觸發(fā)里面存放的訂閱者回調(diào)函數(shù)九秀。
var salesOffices = {}; // 定義售樓處
salesOffices.clientList = []; // 緩存列表,存放訂閱者的回調(diào)函數(shù)
salesOffices.listen = function( fn ){ // 增加訂閱者
this.clientList.push( fn ); // 訂閱的消息添加進(jìn)緩存列表
};
salesOffices.trigger = function(){ // 發(fā)布消息
for( var i = 0, fn; fn = this.clientList[ i++ ]; ){
fn.apply( this, arguments ); // arguments 是發(fā)布消息時(shí)帶上的參數(shù)
}
};
//調(diào)用
salesOffices.listen( function( price, squareMeter ){//訂閱消息
console.log( '價(jià)格= ' + price );
console.log( 'squareMeter= ' + squareMeter );
});
salesOffices.trigger( 2000000, 88 ); // 輸出:200 萬粘我,88 平方米
3.工廠模式:
定義:將其成員對(duì)象的實(shí)例化推遲到子類來實(shí)現(xiàn)的類鼓蜒。
需求:創(chuàng)建對(duì)象的流程賦值的時(shí)候,比如依賴于很多設(shè)置文件等 征字;處理大量具有相同屬性的小對(duì)象都弹;注:不能濫用
優(yōu)點(diǎn):不暴露創(chuàng)建對(duì)象的具體邏輯,而是將將邏輯封裝在一個(gè)函數(shù)中匙姜。
分類:簡(jiǎn)單工廠畅厢,工廠方法和抽象工廠。
3.1.簡(jiǎn)單工廠模式(創(chuàng)建單一對(duì)象氮昧,需要的類比較少)
let UserFactory = function (role) {
function SuperAdmin() {
this.name = "超級(jí)管理員",
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁', '應(yīng)用數(shù)據(jù)', '權(quán)限管理']
}
function Admin() {
this.name = "管理員",
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁', '應(yīng)用數(shù)據(jù)']
}
function NormalUser() {
this.name = '普通用戶',
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁']
}
switch (role) {
case 'superAdmin':
return new SuperAdmin();
break;
case 'admin':
return new Admin();
break;
case 'user':
return new NormalUser();
break;
default:
throw new Error('參數(shù)錯(cuò)誤, 可選參數(shù):superAdmin框杜、admin、user');
}
}
3.2 工廠方法模式 (創(chuàng)建多類對(duì)象袖肥,需要的類比較多)
為方便后續(xù)新增類方便咪辱,只需改一處代碼,封裝了工廠方法而已椎组。并且把類都放在工廠類原型中實(shí)現(xiàn)油狂。
//安全模式創(chuàng)建的工廠方法函數(shù)
let UserFactory = function(role) {
if(this instanceof UserFactory) {
var s = new this[role]();
return s;
} else {
return new UserFactory(role);
}
}
//工廠方法函數(shù)的原型中設(shè)置所有對(duì)象的構(gòu)造函數(shù)
UserFactory.prototype = {
SuperAdmin: function() {
this.name = "超級(jí)管理員",
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁', '應(yīng)用數(shù)據(jù)', '權(quán)限管理']
},
Admin: function() {
this.name = "管理員",
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁', '應(yīng)用數(shù)據(jù)']
},
NormalUser: function() {
this.name = '普通用戶',
this.viewPage = ['首頁', '通訊錄', '發(fā)現(xiàn)頁']
}
}
//調(diào)用
let superAdmin = UserFactory('SuperAdmin');
let admin = UserFactory('Admin')
let normalUser = UserFactory('NormalUser')
前端簡(jiǎn)單算法
冒泡排序
比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換它們兩個(gè)专筷;
對(duì)每一對(duì)相鄰元素作同樣的工作弱贼,從開始第一對(duì)到結(jié)尾的最后一對(duì),這樣在最后的元素應(yīng)該會(huì)是最大的數(shù)磷蛹;
針對(duì)所有的元素重復(fù)以上的步驟吮旅,除了最后一個(gè);
重復(fù)步驟1~3味咳,直到排序完成鸟辅。
function bubble(arr) {
for(var i=0;i<arr.length;i++){
for(j=0;j<arr.length-i-1;j++){
if(arr[j]> arr[j+1]){
var temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
console.log(arr);
return arr;
}
bubble([9,4,2,3,8,0])
選擇排序
選擇排序(Selection-sort)是一種簡(jiǎn)單直觀的排序算法。它的工作原理:首先在未排序序列中找到最休汉(大)元素匪凉,存放到排序序列的起始位置,然后捺檬,再從剩余未排序元素中繼續(xù)尋找最性俨恪(大)元素,然后放到已排序序列的末尾堡纬。以此類推聂受,直到所有元素均排序完畢。
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 尋找最小的數(shù)
minIndex = j; // 將最小數(shù)的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
插入排序
1烤镐、從第一個(gè)元素開始蛋济,該元素可以認(rèn)為已經(jīng)被排序;
2炮叶、取出下一個(gè)元素碗旅,在已經(jīng)排序的元素序列中從后向前掃描;
3镜悉、如果該元素(已排序)大于新元素祟辟,將該元素移到下一位置;
4侣肄、重復(fù)步驟3旧困,直到找到已排序的元素小于或者等于新元素的位置;
5稼锅、將新元素插入到該位置后吼具;
重復(fù)步驟2~5。
function insertionSort(arr) {
var len = arr.length;
var preIndex, current;
for (var i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
Vue
Q:說一下vue的響應(yīng)式原理矩距,怎么實(shí)現(xiàn)拗盒?
A:當(dāng)生成一個(gè)新的vue實(shí)例時(shí),vue會(huì)調(diào)用_init方法進(jìn)行初始化剩晴,這個(gè)過程中會(huì)對(duì)vue實(shí)例中的data調(diào)用Object.defindeProperty方法設(shè)置get和set方法锣咒,get方法用來獲取值,set方法用來監(jiān)聽data中的值的變化赞弥;
當(dāng)需要獲取data中的值時(shí)毅整,會(huì)觸發(fā)getter;當(dāng)修改data中的值時(shí)绽左,setter會(huì)將值的變化告訴watcher悼嫉,watcher在得知變化之后會(huì)去觸發(fā)update方法更新視圖。
Object.defindeProperty的實(shí)現(xiàn)
function render () {
console.log('模擬視圖渲染')
}
let data = {
name: '浪里行舟',
location: { x: 100, y: 100 }
}
observe(data)
function observe (obj) { // 我們來用它使對(duì)象變成可觀察的
// 判斷類型
if (!obj || typeof obj !== 'object') {
return
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
function defineReactive (obj, key, value) {
// 遞歸子屬性
observe(value)
Object.defineProperty(obj, key, {
enumerable: true, //可枚舉(可以遍歷)
configurable: true, //可配置(比如可以刪除)
get: function reactiveGetter () {
console.log('get', value) // 監(jiān)聽
return value
},
set: function reactiveSetter (newVal) {
observe(newVal) //如果賦值是一個(gè)對(duì)象拼窥,也要遞歸子屬性
if (newVal !== value) {
console.log('set', newVal) // 監(jiān)聽
render()
value = newVal
}
}
})
}
}
data.location = {
x: 1000,
y: 1000
} //set {x: 1000,y: 1000} 模擬視圖渲染
data.name // get 浪里行舟
原理圖解
Q:為什么要在v-for中加上key戏蔑?
A:需要使用key來給每個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識(shí),Diff算法就可以正確的識(shí)別此節(jié)點(diǎn)鲁纠。
作用主要是為了高效的更新虛擬DOM总棵。
Q:請(qǐng)?jiān)敿?xì)說下你對(duì)vue生命周期的理解?
A:總共分為8個(gè)階段創(chuàng)建前/后改含,載入前/后情龄,更新前/后,銷毀前/后捍壤。
創(chuàng)建前/后: 在beforeCreated階段骤视,vue實(shí)例的掛載元素el還沒有盗扇。
載入前/后:在beforeMount階段祷肯,vue實(shí)例的$el和data都初始化了,但還是掛載之前為虛擬的dom節(jié)點(diǎn)疗隶,data.message還未替換躬柬。在mounted階段,vue實(shí)例掛載完成抽减,data.message成功渲染允青。
更新前/后:當(dāng)data變化時(shí),會(huì)觸發(fā)beforeUpdate和updated方法卵沉。
銷毀前/后:在執(zhí)行destroy方法后颠锉,對(duì)data的改變不會(huì)再觸發(fā)周期函數(shù),說明此時(shí)vue實(shí)例已經(jīng)解除了事件監(jiān)聽以及和dom的綁定史汗,但是dom結(jié)構(gòu)依然存在琼掠。
Q:介紹虛擬DOM
A:(1)讓我們不用直接操作DOM元素,只操作數(shù)據(jù)便可以重新渲染頁面
(2)虛擬dom
虛擬dom是為了解決瀏覽器性能問題而被設(shè)計(jì)出來的
當(dāng)操作數(shù)據(jù)時(shí)停撞,將改變的dom元素緩存起來瓷蛙,都計(jì)算完后再通過比較映射到真實(shí)的dom樹上
(3)diff算法比較新舊虛擬dom
如果節(jié)點(diǎn)類型相同悼瓮,則比較數(shù)據(jù),修改數(shù)據(jù)
如果節(jié)點(diǎn)不同艰猬,直接干掉節(jié)點(diǎn)及所有子節(jié)點(diǎn)横堡,插入新的節(jié)點(diǎn)
如果給每個(gè)節(jié)點(diǎn)都設(shè)置了唯一的key,就可以準(zhǔn)確的找到需要改變的內(nèi)容冠桃,否則就會(huì)出現(xiàn)修改一個(gè)地方導(dǎo)致其他地方都改變的情況命贴。
比如A-B-C-D, 我要插入新節(jié)點(diǎn)A-B-M-C-D,實(shí)際上改變的了C和D。但是設(shè)置了key食听,就可以準(zhǔn)確的找到B C并插入
Q:組件中 data 為什么是一個(gè)函數(shù)胸蛛?
// data
data() {
return {
message: "子組件",
childName:this.name
}
}
// new Vue
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App}
})
A:
因?yàn)榻M件是用來復(fù)用的,且 JS 里對(duì)象是引用關(guān)系樱报,如果組件中 data 是一個(gè)對(duì)象葬项,那么這樣作用域沒有隔離,子組件中的 data 屬性值會(huì)相互影響迹蛤,如果組件中 data 選項(xiàng)是一個(gè)函數(shù)玷室,那么每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立的拷貝,組件實(shí)例之間的 data 屬性值不會(huì)互相影響笤受;而 new Vue 的實(shí)例穷缤,是不會(huì)被復(fù)用的,因此不存在引用對(duì)象的問題
Q:prefetching和preloading
A:
prefetch 是一種resource hint箩兽,用來告訴瀏覽器在頁面加載完成后津肛,利用空閑時(shí)間提前獲取用戶未來可能會(huì)訪問的內(nèi)容。
import(/* webpackPrefetch: true */ './someAsyncComponent.vue')
preloading是一種resource hint汗贫,用來指定頁面加載后很快會(huì)被用到的資源身坐,所以在頁面加載的過程中,我們希望在瀏覽器開始主體渲染之前盡早 preload落包。preloading用于提高資源加載的優(yōu)先級(jí)部蛇,當(dāng)頁面開始加載時(shí),我們總是想核心的代碼或資源得到優(yōu)先處理咐蝇,因此可以通過preloading提高優(yōu)先級(jí)
import(/* webpackPreload: true */ 'ChartingLibrary');
resource Hints(資源預(yù)加載)是非常好的一種性能優(yōu)化方法涯鲁,可以大大降低頁面加載時(shí)間,給用戶更加流暢的用戶體驗(yàn)有序。
Q:什么是mixin抹腿?
A:當(dāng)我們需要將一些函數(shù)和屬性復(fù)用到兩個(gè)類似的組件中去使用時(shí),可以通過組件中的mixin屬性去引入,mixin中的生命周期在組件中也可以使用旭寿;如果mixin中的方法與組件中的方法命名重復(fù)了警绩,則組件中方法會(huì)重寫mixin中的方法
const toggle = {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
const Modal = {
template: '#modal',
mixins: [toggle],
components: {
appChild: Child
}
};
const Tooltip = {
template: '#tooltip',
mixins: [toggle],
components: {
appChild: Child
}
};
Q:computed 和 watch 的區(qū)別和運(yùn)用的場(chǎng)景?
A:
computed: 是計(jì)算屬性盅称,依賴其它屬性值肩祥,并且 computed 的值有緩存后室,只有它依賴的屬性值發(fā)生改變,下一次獲取 computed 的值時(shí)才會(huì)重新計(jì)算 computed 的值混狠;
watch: 更多的是「觀察」的作用岸霹,類似于某些數(shù)據(jù)的監(jiān)聽回調(diào) ,每當(dāng)監(jiān)聽的數(shù)據(jù)變化時(shí)都會(huì)執(zhí)行回調(diào)進(jìn)行后續(xù)操作檀蹋;運(yùn)用場(chǎng)景:
當(dāng)我們需要進(jìn)行數(shù)值計(jì)算,并且依賴于其它數(shù)據(jù)時(shí)云芦,應(yīng)該使用 computed俯逾,因?yàn)榭梢岳?computed 的緩存特性,避免每次獲取值時(shí)舅逸,都要重新計(jì)算桌肴;
當(dāng)我們需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開銷較大的操作時(shí),應(yīng)該使用 watch琉历,使用 watch 選項(xiàng)允許我們執(zhí)行異步操作 ( 訪問一個(gè) API )坠七,限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前旗笔,設(shè)置中間狀態(tài)彪置。這些都是計(jì)算屬性無法做到的。
Q:SPA 單頁面的理解蝇恶,它的優(yōu)缺點(diǎn)分別是什么拳魁?
SPA( single-page application )僅在 Web 頁面初始化時(shí)加載相應(yīng)的 HTML、JavaScript 和 CSS撮弧。一旦頁面加載完成潘懊,SPA 不會(huì)因?yàn)橛脩舻牟僮鞫M(jìn)行頁面的重新加載或跳轉(zhuǎn);取而代之的是利用路由機(jī)制實(shí)現(xiàn) HTML 內(nèi)容的變換贿衍,UI 與用戶的交互授舟,避免頁面的重新加載。優(yōu)點(diǎn):
用戶體驗(yàn)好贸辈、快释树,內(nèi)容的改變不需要重新加載整個(gè)頁面,避免了不必要的跳轉(zhuǎn)和重復(fù)渲染擎淤;
基于上面一點(diǎn)躏哩,SPA 相對(duì)對(duì)服務(wù)器壓力小揉燃;
前后端職責(zé)分離扫尺,架構(gòu)清晰,前端進(jìn)行交互邏輯炊汤,后端負(fù)責(zé)數(shù)據(jù)處理正驻;
缺點(diǎn):
初次加載耗時(shí)多:為實(shí)現(xiàn)單頁 Web 應(yīng)用功能及顯示效果弊攘,需要在加載頁面的時(shí)候?qū)?JavaScript、CSS 統(tǒng)一加載姑曙,部分頁面按需加載襟交;
前進(jìn)后退路由管理:由于單頁應(yīng)用在一個(gè)頁面中顯示所有的內(nèi)容,所以不能使用瀏覽器的前進(jìn)后退功能伤靠,所有的頁面切換需要自己建立堆棧管理捣域;
SEO 難度較大:由于所有的內(nèi)容都在一個(gè)頁面中動(dòng)態(tài)替換顯示,所以在 SEO 上其有著天然的弱勢(shì)宴合。
Q:Vue 的父組件和子組件生命周期鉤子函數(shù)執(zhí)行順序焕梅?
A:Vue 的父組件和子組件生命周期鉤子函數(shù)執(zhí)行順序可以歸類為以下 4 部分:
加載渲染過程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子組件更新過程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父組件更新過程
父 beforeUpdate -> 父 updated
銷毀過程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
Q:vue的自定義指令怎么使用
A:
全局綁定
// 注冊(cè)一個(gè)全局自定義指令 `v-focus`
Vue.directive('focus', {
// 當(dāng)被綁定的元素插入到 DOM 中時(shí)……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
頁面綁定
directives: {
focus: {
// 指令的定義
inserted: function (el) {
el.focus()
}
}
}
自定義指令的鉤子函數(shù)
bind
:只調(diào)用一次,指令第一次綁定到元素時(shí)調(diào)用卦洽。在這里可以進(jìn)行一次性的初始化設(shè)置贞言。
inserted
:被綁定元素插入父節(jié)點(diǎn)時(shí)調(diào)用 (僅保證父節(jié)點(diǎn)存在,但不一定已被插入文檔中)阀蒂。
update
:所在組件的 VNode 更新時(shí)調(diào)用该窗,但是可能發(fā)生在其子 VNode 更新之前。指令的值可能發(fā)生了改變蚤霞,也可能沒有酗失。但是你可以通過比較更新前后的值來忽略不必要的模板更新 (詳細(xì)的鉤子函數(shù)參數(shù)見下)。
componentUpdated
:指令所在組件的 VNode 及其子 VNode 全部更新后調(diào)用昧绣。
unbind
:只調(diào)用一次级零,指令與元素解綁時(shí)調(diào)用。
指令鉤子函數(shù)會(huì)被傳入以下參數(shù):
-
el
:指令所綁定的元素滞乙,可以用來直接操作 DOM奏纪。 -
binding
:一個(gè)對(duì)象,包含以下 property: -
name
:指令名斩启,不包括v-
前綴序调。 -
value
:指令的綁定值,例如:v-my-directive="1 + 1"
中兔簇,綁定值為2
发绢。 -
oldValue
:指令綁定的前一個(gè)值棠赛,僅在update
和componentUpdated
鉤子中可用巷挥。無論值是否改變都可用黑滴。 -
expression
:字符串形式的指令表達(dá)式毅贮。例如v-my-directive="1 + 1"
中,表達(dá)式為"1 + 1"
录择。 -
arg
:傳給指令的參數(shù)勺阐,可選绊谭。例如v-my-directive:foo
中翻擒,參數(shù)為"foo"
氓涣。 -
modifiers
:一個(gè)包含修飾符的對(duì)象牛哺。例如:v-my-directive.foo.bar
中,修飾符對(duì)象為{ foo: true, bar: true }
劳吠。 -
vnode
:Vue 編譯生成的虛擬節(jié)點(diǎn)引润。移步 VNode API 來了解更多詳情。 -
oldVnode
:上一個(gè)虛擬節(jié)點(diǎn)痒玩,僅在update
和componentUpdated
鉤子中可用淳附。
除了 el
之外,其它參數(shù)都應(yīng)該是只讀的蠢古,切勿進(jìn)行修改奴曙。如果需要在鉤子之間共享數(shù)據(jù),建議通過元素的 dataset 來進(jìn)行便瑟。如以下例子:
Q:vue有幾種傳參方式
A:
通過路由的params/query傳參
父?jìng)髯?父組件通過子組件標(biāo)簽綁定屬性缆毁,子組件通過props接收
子傳父:子組件通過$emit發(fā)送參數(shù)番川,父組件通過子組件標(biāo)簽上綁定方法接收
爺孫之間:爺組件通過provide將參數(shù)暴露子孫級(jí)組件里到涂,后代通過inject接收
//爺組件
provide(){
return {
message:'name'
}
}
//后代組件
inject:['message']
兄弟通信eventbus:
1、創(chuàng)建公共bus文件
import Vue from 'Vue'
export default new Vue
傳遞參數(shù)的兄弟組件:
import Bus from "@/utils/bus"; //注意引入
export default {
data(){
return {
num:1
}
},
methods: {
handle(){
Bus.$emit("brother", this.num++, "子組件向兄弟組件傳值");
}
},
}
接收參數(shù)的兄弟組件
import Bus from "@/utils/bus"; //注意引入
export default {
data(){
return {
data1:'',
data2:''
}
},
mounted() {
Bus.$on("brother", (val, val1) => { //取 Bus.$on
this.data1 = val;
this.data2 = val1;
});
},
}
Q:談?wù)勀銓?duì) keep-alive 的了解颁督?
A:keep-alive 是 Vue 內(nèi)置的一個(gè)組件践啄,可以使被包含的組件保留狀態(tài),避免重新渲染 沉御,其有以下特性:
一般結(jié)合路由和動(dòng)態(tài)組件一起使用屿讽,用于緩存組件;
提供 include 和 exclude 屬性吠裆,兩者都支持字符串或正則表達(dá)式伐谈, include 表示只有名稱匹配的組件會(huì)被緩存,exclude 表示任何名稱匹配的組件都不會(huì)被緩存 试疙,其中 exclude 的優(yōu)先級(jí)比 include 高诵棵;
對(duì)應(yīng)兩個(gè)鉤子函數(shù) activated 和 deactivated ,當(dāng)組件被激活時(shí)祝旷,觸發(fā)鉤子函數(shù) activated履澳,當(dāng)組件被移除時(shí),觸發(fā)鉤子函數(shù) deactivated怀跛。
Q:你使用過 Vuex 嗎距贷?
A:Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。每一個(gè) Vuex 應(yīng)用的核心就是 store(倉庫)吻谋≈一龋“store” 基本上就是一個(gè)容器,它包含著你的應(yīng)用中大部分的狀態(tài) ( state )漓拾。
(1)Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的什湘。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候长赞,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新闽撤。
(2)改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation得哆。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化。
主要包括以下幾個(gè)模塊:
State:定義了應(yīng)用狀態(tài)的數(shù)據(jù)結(jié)構(gòu)哟旗,可以在這里設(shè)置默認(rèn)的初始狀態(tài)贩据。
Getter:允許組件從 Store 中獲取數(shù)據(jù),mapGetters 輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性闸餐。
Mutation:是唯一更改 store 中狀態(tài)的方法饱亮,且必須是同步函數(shù)。
Action:用于提交 mutation舍沙,而不是直接變更狀態(tài)近上,可以包含任意異步操作。
Module:允許將單一的 Store 拆分為多個(gè) store 且同時(shí)保存在單一的狀態(tài)樹中拂铡。
Q:能說下 vue-router 中常用的 hash 和 history 路由模式實(shí)現(xiàn)原理嗎壹无?
A:(1)hash 模式的實(shí)現(xiàn)原理
早期的前端路由的實(shí)現(xiàn)就是基于 location.hash 來實(shí)現(xiàn)的。其實(shí)現(xiàn)原理很簡(jiǎn)單感帅,location.hash 的值就是 URL 中 # 后面的內(nèi)容斗锭。比如下面這個(gè)網(wǎng)站,它的 location.hash 的值為 '#search':
hash 路由模式的實(shí)現(xiàn)主要是基于下面幾個(gè)特性:
URL 中 hash 值只是客戶端的一種狀態(tài)失球,也就是說當(dāng)向服務(wù)器端發(fā)出請(qǐng)求時(shí)岖是,hash 部分不會(huì)被發(fā)送;
hash 值的改變实苞,都會(huì)在瀏覽器的訪問歷史中增加一個(gè)記錄豺撑。因此我們能通過瀏覽器的回退、前進(jìn)按鈕控制hash 的切換黔牵;
可以通過 a 標(biāo)簽聪轿,并設(shè)置 href 屬性,當(dāng)用戶點(diǎn)擊這個(gè)標(biāo)簽后荧止,URL 的 hash 值會(huì)發(fā)生改變屹电;或者使用 JavaScript 來對(duì) loaction.hash 進(jìn)行賦值,改變 URL 的 hash 值跃巡;
我們可以使用 hashchange 事件來監(jiān)聽 hash 值的變化危号,從而對(duì)頁面進(jìn)行跳轉(zhuǎn)(渲染)。
(2)history 模式的實(shí)現(xiàn)原理
HTML5 提供了 History API 來實(shí)現(xiàn) URL 的變化素邪。其中做最主要的 API 有以下兩個(gè):history.pushState() 和 history.repalceState()外莲。這兩個(gè) API 可以在不進(jìn)行刷新的情況下,操作瀏覽器的歷史紀(jì)錄。唯一不同的是偷线,前者是新增一個(gè)歷史記錄磨确,后者是直接替換當(dāng)前的歷史記錄,如下所示:
window.history.pushState(null, null, path);
history 路由模式的實(shí)現(xiàn)主要基于存在下面幾個(gè)特性:
pushState 和 repalceState 兩個(gè) API 來操作實(shí)現(xiàn) URL 的變化 声邦;
我們可以使用 popstate 事件來監(jiān)聽 url 的變化乏奥,從而對(duì)頁面進(jìn)行跳轉(zhuǎn)(渲染);
history.pushState() 或 history.replaceState() 不會(huì)觸發(fā) popstate 事件亥曹,這時(shí)我們需要手動(dòng)觸發(fā)頁面跳轉(zhuǎn)(渲染)邓了。
Q:你有對(duì) Vue 項(xiàng)目進(jìn)行哪些優(yōu)化?
A:
代碼層面的優(yōu)化:
v-if 和 v-show 區(qū)分使用場(chǎng)景
computed 和 watch 區(qū)分使用場(chǎng)景
圖片資源懶加載
路由懶加載
第三方插件的按需引入
使用節(jié)流防抖
減少回流與重繪的:
不要頻繁操作元素的樣式媳瞪,對(duì)于靜態(tài)頁面骗炉,可以修改類名,而不是樣式蛇受。
操作DOM時(shí)句葵,盡量在低層級(jí)的DOM節(jié)點(diǎn)進(jìn)行操作
Webpack 層面的優(yōu)化:
如何提?webpack的打包速度?
(1)優(yōu)化 Loader
對(duì)于 Loader 來說,影響打包效率首當(dāng)其沖必屬 Babel 了兢仰。因?yàn)?Babel 會(huì)將代碼轉(zhuǎn)為字符串生成 AST乍丈,然后對(duì) AST 繼續(xù)進(jìn)行轉(zhuǎn)變最后再生成新的代碼,項(xiàng)目越大旨别,轉(zhuǎn)換代碼越多诗赌,效率就越低汗茄。當(dāng)然了秸弛,這是可以優(yōu)化的。
首先我們優(yōu)化 Loader 的文件搜索范圍
module.exports = {
module: {
rules: [
{
// js 文件才使用 babel
test: /\.js$/,
loader: 'babel-loader',
// 只在 src 文件夾下查找
include: [resolve('src')],
// 不會(huì)去查找的路徑
exclude: /node_modules/
}
]
}
}
(2)HappyPack
受限于 Node 是單線程運(yùn)行的洪碳,所以 Webpack 在打包的過程中也是單線程的递览,特別是在執(zhí)行 Loader 的時(shí)候,長(zhǎng)時(shí)間編譯的任務(wù)很多瞳腌,這樣就會(huì)導(dǎo)致等待的情況绞铃。
HappyPack 可以將 Loader 的同步執(zhí)行轉(zhuǎn)換為并行的,這樣就能充分利用系統(tǒng)資源來加快打包效率了
module: {
loaders: [
{
test: /\.js$/,
include: [resolve('src')],
exclude: /node_modules/,
// id 后面的內(nèi)容對(duì)應(yīng)下面
loader: 'happypack/loader?id=happybabel'
}
]
},
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader?cacheDirectory'],
// 開啟 4 個(gè)線程
threads: 4
})
]
(3)DllPlugin
DllPlugin 可以將特定的類庫提前打包然后引入嫂侍。這種方式可以極大的減少打包類庫的次數(shù)儿捧,只有當(dāng)類庫更新版本才有需要重新打包,并且也實(shí)現(xiàn)了將公共代碼抽離成單獨(dú)文件的優(yōu)化方案挑宠。DllPlugin的使用方法如下:
// 單獨(dú)配置在一個(gè)文件中
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
// 想統(tǒng)一打包的類庫
vendor: ['react']
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].dll.js',
library: '[name]-[hash]'
},
plugins: [
new webpack.DllPlugin({
// name 必須和 output.library 一致
name: '[name]-[hash]',
// 該屬性需要與 DllReferencePlugin 中一致
context: __dirname,
path: path.join(__dirname, 'dist', '[name]-manifest.json')
})
]
}
然后需要執(zhí)行這個(gè)配置文件生成依賴文件菲盾,接下來需要使用 DllReferencePlugin 將依賴文件引入項(xiàng)目中
// webpack.conf.js
module.exports = {
// ...省略其他配置
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
// manifest 就是之前打包出來的 json 文件
manifest: require('./dist/vendor-manifest.json'),
})
]
}
(4)代碼壓縮
在 Webpack3 中,一般使用 UglifyJS 來壓縮代碼各淀,但是這個(gè)是單線程運(yùn)行的懒鉴,為了加快效率,可以使用 webpack-parallel-uglify-plugin 來并行運(yùn)行 UglifyJS,從而提高效率临谱。
在 Webpack4 中璃俗,不需要以上這些操作了,只需要將 mode 設(shè)置為 production 就可以默認(rèn)開啟以上功能悉默。代碼壓縮也是我們必做的性能優(yōu)化方案城豁,當(dāng)然我們不止可以壓縮 JS 代碼,還可以壓縮 HTML抄课、CSS 代碼钮蛛,并且在壓縮 JS 代碼的過程中,我們還可以通過配置實(shí)現(xiàn)比如刪除 console.log 這類代碼的功能剖膳。
- 如何減少 Webpack 打包體積
(1)按需加載
(2)Scope Hoisting
Scope Hoisting 會(huì)分析出模塊之間的依賴關(guān)系魏颓,盡可能的把打包出來的模塊合并到一個(gè)函數(shù)中去。
module.exports = {
optimization: {
concatenateModules: true
}
}
(3)Tree Shaking
Tree Shaking 可以實(shí)現(xiàn)刪除項(xiàng)目中未被引用的代碼
如果使用 Webpack 4 的話吱晒,開啟生產(chǎn)環(huán)境就會(huì)自動(dòng)啟動(dòng)這個(gè)優(yōu)化功能甸饱。
Vue 3.0
Q:3.0更新了那些內(nèi)容?
A:http://www.reibang.com/p/e073909239ed
Q:什么是Composition-API?怎么使用仑濒?
A:https://segmentfault.com/a/1190000020205747
https://blog.csdn.net/qq_42941302/article/details/107819669
Q:什么是proxy叹话?
A:http://www.reibang.com/p/c2a1aa2e2b14
React
Q:react的特點(diǎn)
A:?jiǎn)蜗驍?shù)據(jù)流,虛擬dom墩瞳,組件化
Q:什么是hook驼壶?
A:指在不使用類組件的情況下使用state和props的函數(shù)
Q:什么是redux,什么時(shí)候使用,怎么用喉酌?
A:redux是一種設(shè)計(jì)模式热凹,通過將數(shù)據(jù)統(tǒng)一存放在store中,再通過訂閱subsribe去更新數(shù)據(jù)
1.組件需要共享數(shù)據(jù)
2.某個(gè)狀態(tài)需要在任何時(shí)候都需要被訪問
3.某個(gè)組件需要改變另一組件的狀態(tài)
Q:列出React的一些主要優(yōu)點(diǎn)泪电。
A:React的一些主要優(yōu)點(diǎn)是:
它提高了應(yīng)用的性能
可以方便地在客戶端和服務(wù)器端使用
由于 JSX般妙,代碼的可讀性很好
React 很容易與 Meteor,Angular 等其他框架集成
使用React相速,編寫UI測(cè)試用例變得非常容易