個(gè)人面試總結(jié)

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 浪里行舟

原理圖解

image.png

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和數(shù)據(jù)對(duì)象data都為undefined,還未初始化鹃觉。在created階段专酗,vue實(shí)例的數(shù)據(jù)對(duì)象data有了,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è)值棠赛,僅在 updatecomponentUpdated 鉤子中可用巷挥。無論值是否改變都可用黑滴。
  • 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)痒玩,僅在 updatecomponentUpdated 鉤子中可用淳附。

除了 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 這類代碼的功能剖膳。

  1. 如何減少 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?怎么使用仑濒?
Ahttps://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è)試用例變得非常容易

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碟渺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子突诬,更是在濱河造成了極大的恐慌苫拍,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旺隙,死亡現(xiàn)場(chǎng)離奇詭異绒极,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)催束,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門集峦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事塔淤≌” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵高蜂,是天一觀的道長(zhǎng)聪黎。 經(jīng)常有香客問我,道長(zhǎng)备恤,這世上最難降的妖魔是什么稿饰? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮露泊,結(jié)果婚禮上喉镰,老公的妹妹穿的比我還像新娘。我一直安慰自己惭笑,他們只是感情好侣姆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沉噩,像睡著了一般捺宗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上川蒙,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天蚜厉,我揣著相機(jī)與錄音,去河邊找鬼畜眨。 笑死昼牛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的胶果。 我是一名探鬼主播匾嘱,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼斤斧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼早抠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撬讽,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蕊连,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后游昼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甘苍,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年烘豌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了载庭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖囚聚,靈堂內(nèi)的尸體忽然破棺而出靖榕,到底是詐尸還是另有隱情,我是刑警寧澤顽铸,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布茁计,位于F島的核電站,受9級(jí)特大地震影響谓松,放射性物質(zhì)發(fā)生泄漏星压。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一鬼譬、第九天 我趴在偏房一處隱蔽的房頂上張望娜膘。 院中可真熱鬧,春花似錦优质、人聲如沸劲绪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贾富。三九已至,卻和暖如春牺六,著一層夾襖步出監(jiān)牢的瞬間颤枪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工淑际, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畏纲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓春缕,卻偏偏與公主長(zhǎng)得像盗胀,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锄贼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容