前端面試題匯總2021


目錄

一:前端頁面樣式

  1.塊標簽和行標簽

  2.盒子模型和IE盒子模型

  3.清除浮動

  4.css動畫

  5.盒子垂直水平居中

  6.css選擇器及優先級

  7.左側寬度固定右側自適應

  8.0.5px的線

  9.什么是BFC

       10.flex:1是什么縮寫

二:js

  1.數據類型

  2.閉包

  3.ajax原理和優缺點

  4.從輸入url到頁面展示的詳細過程

  5.原型和原型鏈區別

  6.sessionStorage,localStorage和cookie的區別

  9.節流和防抖

  10.回流和重繪

  11.instanceof 和 typeof的區別

  12.數組的增刪改查

  13.http和https的區別,常見http狀態碼

  14.get和post區別

  15.前端跨域解決辦法

  16.內存泄漏的幾種情況及解決辦法

   17.promiss與async和await的區別

  18.webstorage怎么賦值(轉化成字符串賦值)

  19.post跨域怎么處理

       20.說一下this關鍵字

三:vue

  1.什么是MVVM

  2.VUE的響應式原理

  3.v-if和v-show的區別

  4.組件之間傳值

  5.vue生命周期及各階段情況

  6.webpack打包原理

   7.keep-alive的生命周期

        8.父子組件created和mounted加載順序

  9.wacth和computer區別

       10.vue的data為什么必須是函數

四:es6

  1.let和const

  2.什么是promiss,promiss有哪幾個方法

  3.箭頭函數

     

 

五:算法

  1.冒泡排序

  2.快速排序和二分查找

  3.數組的翻轉(非reverse())

  4.數組由小到大進行排序

  5.求數組最大值:Math.max.apply(null,arr);

  6.數組去重

  7.判斷一個字符串中出現次數最多的字符,統計這個次數

  8.apply()/call()求數組最值

  9.獲取瀏覽器URL中查詢字符串中的參數

  10.2個對象排序{age:10,name:'lili'}
  11.設計模型

  12.JavaScript將具有父子關系的原始數據格式化成樹形結構數據(id,pid)

 

=============================這是 分割線=======================================

一:前端頁面樣式

  1.塊標簽和行標簽

  塊標簽包括:p、div、ul、ol、li、dl、dt、dd、h1~h6、form、table、td、thread、tr、

  行標簽包括:a、abbr、b(字體加粗)、br、em、input、select、span、strong、sub、textarea、

  行內元素設置width無效,height無效(可以設置line-height),margin上下無效,padding上下無效。

  2.盒子模型和IE盒子模型

 

 

  box-sizing屬性可以指定盒子模型種類,content-box指定盒子模型為W3C(標准盒模型),border-box為IE盒子模型(怪異盒模型)。

  3.清除浮動

  3.1偽類元素(clearfix)    

HTML結構如下,為了慣例相符,在.topDiv的div上再添加一個clearfix類:

<div class="topDiv clearfix">

<div class="textDiv">...</div>

<div class="floatDiv">float left</div>

</div>

<div class="bottomDiv">...</div>

css樣式

// 省略基本的樣式

// 區別在這里

.clearfix:after {

content: '';

height: 0;

display: block;

clear: both;

}

3.2在浮動元素后面加一個空div設置clear:both

<div class="topDiv clearfix">

    <div class="textDiv">...</div>

 <div class="floatDiv">float left</div>

  <div style=clear:both></div>

</div>

3.3給父元素設置overflow:auto

  4.css動畫

  4.1.transform:有4個方法,translate(平移),rotate(旋轉),scale(縮放),skew(斜切)

tranform:translate(10px,10px); //平移

transform:rotate(90deg); //旋轉

transform:scale(1.2); //縮放:參數<1縮小,>1放大

transform:skew(90deg,10deg)//斜切

4.2.transition有4個值(默認是前2個值):property(指定css屬性的name)、duration(動畫持續時間)、timing-function(切換動畫的速度)、動畫執行前的延遲時間。

transitionwidth|height|opacity|all 2s ease-in 2s;

3.perspective:90px; //景深,值越小,表示我們離物體越近,一般使用500-800

       

  5.盒子垂直水平居中

   5.1已知盒子寬高 

方案一:設置父元素為相對定位,給子元素設置絕對定位,top: 0; right: 0; bottom: 0; left: 0; margin: auto;

<style>

    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
    #son {
        width: 100px;
        height: 100px;
        background-color: green;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        margin: auto;
}
</style>
<div id="father">
    <div id="son">我是塊級元素</div>
</div>
方案二:設置父元素為相對定位,給子元素設置絕對定位,left: 50%; top: 50%; margin-left: --元素寬度的一半px; margin-top: --元素高度的一半px;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
       position: relative;
}
     #son {
      width: 100px;
        height: 100px;
        background-color: green;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -50px;
        margin-top: -50px;
}
</style>

5.2未知寬高

方案一:使用定位屬性

設置父元素為相對定位,給子元素設置絕對定位,left: 50%; top: 50%; transform: translateX(-50%) translateY(-50%);// transform: translate(-50%,-50%)
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        position: relative;
}
    #son {
        background-color: green;
        position: absolute;
        left: 50%;
        top: 50%;
        transform: translateX(-50%) translateY(-50%);  // transform: translate(-50%,-50%)
}
</style>
方案二:使用flex布局實現
設置父元素為flex定位,justify-content: center; align-items: center;
<style>
    #father {
        width: 500px;
        height: 300px;
        background-color: skyblue;
        display: flex;
        justify-content: center;
        align-items: center;
}
    #son {
        background-color: green;
}
</style>

  6.css選擇器及優先級 

  !important > 行內樣式>ID選擇器 > 類選擇器 > 標簽 > 通配符 > 繼承 > 瀏覽器默認屬性

  7.左側寬度固定右側自適應

/*左固定列*/
.fixedColumn{
    width: 40px;
    height: 100%;
    background-color: red;
    float: left;
    /*position: absolute; 注釋和float:left選一即可 left: 0;*/
}
/*右自適應列*/
.flexibleColumn{
    height: 100%;
    background-color: blue;    
    margin-left: 40px;
}
<!-- 左側固定列 --> <div class="fixedColumn"></div> <!-- 右側自適應寬度列 --> <div class="flexibleColumn"></div>
~左中右,左右固定寬度,中間自適應(與左定寬,右自適應就多一個右float:right)
<!-- 左側固定列 -->
<div class="fixedColumn"></div>
<!-- 右側固定列 -->
<div class="fixedColumn" style=”float:right”></div>
<!-- 右側自適應寬度列 -->
<div class="flexibleColumn"></div> 
float + overflow:hidden 利用overflow:hidden形成BFC,因為BFC不會與float box重疊。

.left {
    float: left;
    width: 200px;
    height: 100%;
    background-color: red;
}
.right {
    overflow:hidden;     background-color: blue;
}
CSS3 float + calc
.left {
    float: left;
    width: 200px;
    height: 100%;
    background-color: red;
}
.right {
    float: left;
    width: calc(100% - 200px);
    height: 100%;
    background-color: blue;
}
彈性布局
.parent {
    display: flex;
}
.left {
    width: 200px;
    height: 100%;
    background-color: red;
}
.right {
    display: flex; flex: 1;
    height: 100%;
    background-color: blue;
}

  8.0.5px的線

.hr.scale-half {
    height: 1px;
    transform: scaleY(0.5);    transform-origin: 50% 100%;}
方法2:
.hr.gradient {
    height: 1px;
    background: linear-gradient(0deg, #fff, #000);}

  9.什么是BFC

BFC(Block formatting context)直譯為"塊級格式化上下文"它是一個獨立的渲染區域,只有Block-level box參與, 它規定了內部的Block-level Box如何布局,並且與這個區域外部毫不相干。

如何創建BFC

    • 1、float的值不是none。
    • 2、position的值不是static或者relative。
    • 3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
    • 4、overflow的值不是visible

1.兩個兄弟盒子A在上、B在下,A margin-bottom:20px,B margin-top:30px A和B的最終距離是多少?

30px 因為同屬於一個BFC,margin會重疊。可以給B套一個盒子並開啟BFC就變成50px了。

    1. A和B是父子關系A在外、B在內,A margin-top:30px ,B margin-top: 20px,A和B之間的距離是多少?

相同的原因,兩個盒子的margin會重疊,導致子盒子會頂在父盒子邊框。所以距離是0px。

3.A是絕對定位,B是相對定位,A和B是兄弟關系,A和B分別相對什么位置移動,A 和 B 是否脫離文檔流

A相對有定位的父盒子或者根元素移動,脫離文檔流;B相對自己位置移動,不脫離文檔流。

10.flex:1是什么縮寫

flex:1即為flex-grow:1,經常用作自適應布局,將父容器的display:flex,側邊欄大小固定后,將內容區flex:1,內容區則會自動放大占滿剩余空間。

  flex-grow:定義項目的的放大比例;

  •         默認為0,即 即使存在剩余空間,也不會放大;
  •        所有項目的flex-grow為1:等分剩余空間(自動放大占位);
  •         flex-grow為n的項目,占據的空間(放大的比例)是flex-grow為1的n倍。

  11.css3和html5新增屬性

  https://blog.csdn.net/m0_37631322/article/details/81945113

二:js

  1.數據類型  

基本數據類型:booleannumberstringundefinednull 保存在內存中。

引用數據類型:ObjectArrayFunctionDateregexp 保存在堆內存中的對象。與其他語言的不同是,你不可以直接訪問堆內存空間中的位置和操作堆內存空間。只能操作對象在棧內存中的引用地址。

  2.閉包

什么是閉包

簡單來說,閉包是指可以訪問另一個函數作用域變量的函數,一般是定義在外層函數中的內層函數。

為什么需要閉包呢

局部變量無法共享和長久的保存,而全局變量可能造成變量污染,所以我們希望有一種機制既可以長久的保存變量又不會造成全局污染。

特點

占用更多內存

不容易被釋放

何時使用

既想反復使用,又想避免全局污染

如何使用

1.定義外層函數,封裝被保護的局部變量。 2.定義內層函數,執行對外部函數變量的操作。 3.外層函數返回內層函數的對象,並且外層函數被調用,結果保存在一個全局的變量中。

函數生命周期

直接上圖,點擊圖片放大查看。要記住函數對象、作用域鏈對象、執行環境(EC)和活動對象(AO)這幾個東西都啥時候出現,啥時候消失。

 

 

  3.ajax原理和優缺點

1:原理:

Ajax的原理簡單來說通過XmlHttpRequest對象來向服務器發異步請求,從服務器獲得數據,然后用javascript來操作DOM而更新頁面。 
2:ajax的優點: 
    1、最大的一點是頁面無刷新,在頁面內與服務器通信,給用戶的體驗非常好。 
  2、使用異步方式與服務器通信,不需要打斷用戶的操作,具有更加迅速的響應能力。 
  3、可以把以前一些服務器負擔的工作轉嫁到客戶端,利用客戶端閑置的能力來處理,減輕服務器和帶寬的負擔,節約空間和寬帶租用成本。並且減輕服務器的負擔,ajax的原則是“按需取數據”,可以最大程度的減少冗余請求,和響應對服務器造成的負擔。 
    4、基於標准化的並被廣泛支持的技術,不需要下載插件或者小程序。 
3:缺點: 
    1:破壞瀏覽器后退按鈕正常行為 
    2:對搜索引擎不是多好

  4.從輸入url到頁面展示的詳細過程

  • 1、輸入網址
  • 2、DNS解析
  • 3、建立tcp連接
  • 4、客戶端發送HTPP請求
  • 5、服務器處理請求 
  • 6、服務器響應請求
  • 7、瀏覽器展示HTML
  • 8、瀏覽器發送請求獲取其他在HTML中的資源。

  5.原型和原型鏈區別

prototype是函數才有的屬性
__proto__是每個對象都有的屬性

所有對象都會從它的原型上繼承一個 constructor 屬性

obj.__proto__ === obj.constructor.prototype

總結:
1.對象有屬性__proto__,指向該對象的構造函數的原型對象。
2.方法除了有屬性__proto__,還有屬性prototype,prototype指向該方法的原型對象。

大多數情況下,__proto__可以理解為“構造器的原型”,即__proto__===constructor.prototype,但是通過 Object.create()創建的對象有可能不是, Object.create()方法創建一個新對象,使用現有的對象來提供新創建的對象的__proto__。

  6.sessionStorage,localStorage和cookie的區別

共同點:都是保存在瀏覽器端、且同源的 
區別: 
1、cookie數據始終在同源的http請求中攜帶(即使不需要),即cookie在瀏覽器和服務器間來回傳遞,而sessionStorage和localStorage不會自動把數據發送給服務器,僅在本地保存。cookie數據還有路徑(path)的概念,可以限制cookie只屬於某個路徑下 
2、存儲大小限制也不同,cookie數據不能超過4K,同時因為每次http請求都會攜帶cookie、所以cookie只適合保存很小的數據,如會話標識。sessionStorage和localStorage雖然也有存儲大小的限制,但比cookie大得多,可以達到5M或更大 
3、數據有效期不同,sessionStorage:僅在當前瀏覽器窗口關閉之前有效;localStorage:始終有效,窗口或瀏覽器關閉也一直保存,因此用作持久數據;cookie:只在設置的cookie過期時間之前有效,即使窗口關閉或瀏覽器關閉 
4、作用域不同,sessionStorage不在不同的瀏覽器窗口中共享,即使是同一個頁面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的 
5、web Storage支持事件通知機制,可以將數據更新的通知發送給監聽者 
6、web Storage的api接口使用更方便

     9.節流和防抖

在進行窗口的resize、scroll,輸入框內容校驗等操作時,如果事件處理函數調用的頻率無限制,會加重瀏覽器的負擔,導致用戶體驗非常糟糕。此時我們可以采用debounce(防抖)和throttle(節流)的方式來減少調用頻率,同時又不影響實際效果

函數防抖:將幾次操作合並為一此操作進行。原理是維護一個計時器,規定在delay時間后觸發函數,但是在delay時間內再次觸發的話,就會取消之前的計時器而重新設置。這樣一來,只有最后一次操作能被觸發。

函數節流:使得一定時間內只觸發一次函數。原理是通過判斷是否到達一定時間來觸發函數。

區別: 函數節流不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數,而函數防抖只是在最后一次事件后才觸發一次函數。 比如在頁面的無限加載場景下,我們需要用戶在滾動頁面時,每隔一段時間發一次 Ajax 請求,而不是在用戶停下滾動頁面操作時才去請求數據。這樣的場景,就適合用節流技術來實現。

防抖就是:對於段時間內連續觸發的事件,防抖的含義就是讓某個時間段內,事件處理函數只執行一次。

函數節流(throttle):當持續觸發事件時,保證一定時間段內只調用一次事件處理函數。

函數節流主要有兩種實現方法:時間戳和定時器

使用場景:頁面中的返回頂部,當在滾動條位置,點擊鍵盤上下鍵,會多次執行

防抖:在第一次觸發事件時,不立即執行函數,而是給出一個期限值,比如200ms。

如果在200ms內沒有再次觸發滾動事件,那么就執行函數

如果再200ms內再次觸發滾動事件,那么當前計時取消,重新開始計時。

  10.回流和重繪

1、 重繪:元素樣式的改變(但寬高、大小、位置等不變)
如:outline、visibility、color、background-color等

只改變自身樣式,不會影響到其他元素

2、 回流:元素的大小或者位置發生改變(當頁面布局和幾何信息發生改變的時候),觸發了重新布局導致渲染樹重新計算布局和渲染
​ 如添加或刪除可見的DOM元素;元素的位置發生變化;元素的尺寸發生變化、內容發生變化(如文本變化或圖片被另一個不同尺寸的圖片所代替);頁面一開始渲染的時候(無法避免);

​ 因為回流是根據視口大小來計算元素的位置和大小的,所以瀏覽器窗口尺寸變化也會引起回流

注意:回流一定會觸發重繪,而重繪不一定會回流
————————————————
版權聲明:本文為CSDN博主「獨坐空山后」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/pig_is_duck/article/details/105903741

  11.instanceof 和 typeof的區別

typeof用於判斷數據類型,返回值為6個字符串,分別為stringBooleannumberfunctionobjectundefined。對於 Array,Null 等特殊對象使用 typeof 一律返回 object,這正是 typeof 的局限性

instanceof 用於判斷一個變量是否某個對象的實例,如 var a=new Array();alert(a instanceof Array); 會返回 true,同時 alert(a instanceof Object) 也會返回 true;這是因為 Array 是 object 的子類

  12.數組的增刪改查

下面將數組的方法分為5類(官方文檔中可查)

A – 給數組添加元素(增):push(), unshift(),splice()

B – 從數組中刪除元素(刪):pop(), shift(),splice()

C – 修改數組中的元素(改):splice(),reverse(),sort()

D --從已有數組中返回選定的數組(查):slice()

E – 不會改變元素數組的內容的函數:concat(),slice()

————————————————

版權聲明:本文為CSDN博主「銭佳」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

 

原文鏈接:https://blog.csdn.net/weixin_41895038/article/details/105040532

  13.http和https的區別,常見http狀態碼

HTTP協議傳輸的數據都是未加密的,也就是明文的,因此使用HTTP協議傳輸隱私信息非常不安全,為了保證這些隱私數據能加密傳輸,於是網景公司設計了SSLSecure Sockets Layer)協議用於對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。簡單來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。

  HTTPSHTTP的區別主要如下:

  1https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。

  2http是超文本傳輸協議,信息是明文傳輸,https則是具有安全性的ssl加密傳輸協議。

  3httphttps使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443

  4http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

  • 200 - 請求成功
  • 301 - 資源(網頁等)被永久轉移到其它URL
  • 302 - 資源被臨時移動,客戶端應繼續使用
  • 304-如果客戶端發送了一個帶條件的GET 請求且該請求已被允許,而文檔的內容(自上次訪問以來或者根據請求的條件)並沒有改變,則服務器應當返回這個304狀態碼。簡單的表達就是:服務端已經執行了GET,但文件未變化。
  • 404 - 請求的資源(網頁等)不存在
  • 500 - 內部服務器錯誤
  • 502 Bad Gateway:作為網關或者代理工作的服務器嘗試執行請求時,從上游服務器接收到無效的響應。 
  • 504 Gateway Time-out:作為網關或者代理工作的服務器嘗試執行請求時,未能及時從上游服務器(URI標識出的服務器,例如HTTP、FTP、LDAP)或者輔助服務器(例如DNS)收到響應。
     

HTTP狀態碼分類

分類

分類描述

1**

信息,服務器收到請求,需要請求者繼續執行操作

2**

成功,操作被成功接收並處理

3**

重定向,需要進一步的操作以完成請求

4**

客戶端錯誤,請求包含語法錯誤或無法完成請求

5**

服務器錯誤,服務器在處理請求的過程中發生了錯誤

  14.get和post區別

  1. get是從服務器上獲取數據,post是向服務器傳送數據。
  2. 傳送方式:get通過地址欄傳輸,post通過報文傳輸
  3. 傳送長度:get 參數長度有限制(受限於url長度),而post無限制。
  4. GET是表單提交的默認方法
  5. Get產生一個TCP數據包,post產生2TCP數據包,Firefox就只發送一次。
  6. Get在瀏覽器回退時是無害的,而post會再次提交請求。
  7. GET請求參數會被完整保留在瀏覽器歷史記錄里,而POST中的參數不會被保留。

  15.前端跨域解決辦法

  參考鏈接:https://www.jianshu.com/p/451e575a3a8a

  16.內存泄漏的幾種情況及解決辦法

https://www.jianshu.com/p/9af7fa367784
系統進程不再用到的內存,沒有及時釋放,就叫做內存泄漏(memory leak)
當內存占用越來越高,輕則影響系統性能,重則導致進程崩潰

引起內存泄漏的原因
1. 意外的全局變量
由於 js 對未聲明變量的處理方式是在全局對象上創建該變量的引用。如果在瀏覽器中,全局對象就是 window 對象。變量在窗口關閉或重新刷新頁面之前都不會被釋放,如果未聲明的變量緩存大量的數據,就會導致內存泄露。
// 未聲明變量
function fn() {
  a = 'global variable'}fn()
//使用 this 創建的變量(this 的指向是 window)。
function fn() {
  this.a = 'global variable'}fn()
解決方法:
避免創建全局變量
使用嚴格模式,在 JavaScript 文件頭部或者函數的頂部加上 use strict。
2. 閉包引起的內存泄漏
原因:閉包可以讀取函數內部的變量,然后讓這些變量始終保存在內存中。如果在使用結束后沒有將局部變量清除,就可能導致內存泄露。
function fn () {
  var a = "I'm a";
  return function () {
    console.log(a);
  };}
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中。
比如:在循環中的函數表達式,能復用最好放到循環外面。
// badfor (var k = 0; k < 10; k++) {
  var t = function (a) {
    // 創建了10次  函數對象。
    console.log(a)
  }
  t(k)}
// goodfunction t(a) {
  console.log(a)}for (var k = 0; k < 10; k++) {
  t(k)}
t = null
3. 沒有清理的 DOM 元素引用
原因:雖然別的地方刪除了,但是對象中還存在對 dom 的引用。
// 在對象中引用DOMvar elements = {
  btn: document.getElementById('btn'),}function doSomeThing() {
  elements.btn.click()}function removeBtn() {
  // 將body中的btn移除, 也就是移除 DOM樹中的btn
  document.body.removeChild(document.getElementById('button'))
  // 但是此時全局變量elements還是保留了對btn的引用, btn還是存在於內存中,不能被GC回收}
解決方法:手動刪除elements.btn = null。
4. 被遺忘的定時器或者回調
定時器中有 dom 的引用,即使 dom 刪除了,但是定時器還在,所以內存中還是有這個 dom。
// 定時器var serverData = loadData()setInterval(function () {
  var renderer = document.getElementById('renderer')
  if (renderer) {
    renderer.innerHTML = JSON.stringify(serverData)
  }}, 5000)
// 觀察者模式var btn = document.getElementById('btn')function onClick(element) {
  element.innerHTMl = "I'm innerHTML"}
btn.addEventListener('click', onClick)
解決方法:
手動刪除定時器和 dom。
removeEventListener 移除事件監聽
vue 中容易出現內存泄露的幾種情況
在 Vue SPA 開發應用,那么就更要當心內存泄漏的問題。因為在 SPA 的設計中,用戶使用它時是不需要刷新瀏覽器的,所以 JavaScript 應用需要自行清理組件來確保垃圾回收以預期的方式生效。因此開發過程中,你需要時刻警惕內存泄漏的問題。
1. 全局變量造成的內存泄露
聲明的全局變量在切換頁面的時候沒有清空
<template>
  <div id="home">這里是首頁</div></template>
<script>
  export default {
    mounted() {
      window.test = {
        // 此處在全局window對象中引用了本頁面的dom對象
        name: 'home',
        node: document.getElementById('home'),
      }
    },
  }</script>
解決方案:在頁面卸載的時候順便處理掉該引用。
destroyed () {
  window.test = null // 頁面卸載的時候解除引用
 }
2. 監聽在 window/body 等事件沒有解綁
特別注意 window.addEventListener 之類的時間監聽
<template>
  <div id="home">這里是首頁</div></template><script>

export default {
  mounted () {
    window.addEventListener('resize', this.func) // window對象引用了home頁面的方法
  }
}</script>
解決方法:在頁面銷毀的時候,順便解除引用,釋放內存
mounted () {
  window.addEventListener('resize', this.func)},
beforeDestroy () {
  window.removeEventListener('resize', this.func)}
3. 綁在 EventBus 的事件沒有解綁
舉個例子
<template>
  <div id="home">這里是首頁</div></template>
<script>
export default {
  mounted () {
   this.$EventBus.$on('homeTask', res => this.func(res))
  }
}</script>
解決方法:在頁面卸載的時候也可以考慮解除引用
mounted () {
 this.$EventBus.$on('homeTask', res => this.func(res))},destroyed () {
 this.$EventBus.$off()}
4. Echarts
每一個圖例在沒有數據的時候它會創建一個定時器去渲染氣泡,頁面切換后,echarts 圖例是銷毀了,但是這個 echarts 的實例還在內存當中,同時它的氣泡渲染定時器還在運行。這就導致 Echarts 占用 CPU 高,導致瀏覽器卡頓,當數據量比較大時甚至瀏覽器崩潰。
解決方法:加一個 beforeDestroy()方法釋放該頁面的 chart 資源,我也試過使用 dispose()方法,但是 dispose 銷毀這個圖例,圖例是不存在了,但圖例的 resize()方法會啟動,則會報沒有 resize 這個方法,而 clear()方法則是清空圖例數據,不影響圖例的 resize,而且能夠釋放內存,切換的時候就很順暢了。
beforeDestroy () {
  this.chart.clear()}
5. v-if 指令產生的內存泄露
v-if 綁定到 false 的值,但是實際上 dom 元素在隱藏的時候沒有被真實的釋放掉。
比如下面的示例中,我們加載了一個帶有非常多選項的選擇框,然后我們用到了一個顯示/隱藏按鈕,通過一個 v-if 指令從虛擬 DOM 中添加或移除它。這個示例的問題在於這個 v-if 指令會從 DOM 中移除父級元素,但是我們並沒有清除由 Choices.js 新添加的 DOM 片段,從而導致了內存泄漏。
<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div></div><script>
  export default {
    data() {
      return {
        showChoices: true,
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        // 我們來為選擇框載入很多選項,這樣的話它會占用大量的內存
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
        new Choices('#choices-single-default', {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        this.showChoices = false
      },
    },
  }</script>
在上述的示例中,我們可以用 hide() 方法在將選擇框從 DOM 中移除之前做一些清理工作,來解決內存泄露問題。為了做到這一點,我們會在 Vue 實例的數據對象中保留一個屬性,並會使用 Choices API 中的 destroy() 方法將其清除。
<div id="app">
  <button v-if="showChoices" @click="hide">Hide</button>
  <button v-if="!showChoices" @click="show">Show</button>
  <div v-if="showChoices">
    <select id="choices-single-default"></select>
  </div></div>
<script>
  export default {
    data() {
      return {
        showChoices: true,
        choicesSelect: null
      }
    },
    mounted: function () {
      this.initializeChoices()
    },
    methods: {
      initializeChoices: function () {
        let list = []
        for (let i = 0; i < 1000; i++) {
          list.push({
            label: 'Item ' + i,
            value: i,
          })
        }
         // 在我們的 Vue 實例的數據對象中設置一個 `choicesSelect` 的引用
        this.choicesSelect = new Choices("#choices-single-default", {
          searchEnabled: true,
          removeItemButton: true,
          choices: list,
        })
      },
      show: function () {
        this.showChoices = true
        this.$nextTick(() => {
          this.initializeChoices()
        })
      },
      hide: function () {
        // 現在我們可以讓 Choices 使用這個引用,從 DOM 中移除這些元素之前進行清理工作
        this.choicesSelect.destroy()
        this.showChoices = false
      },
    },
  }</script>
ES6 防止內存泄漏
前面說過,及時清除引用非常重要。但是,你不可能記得那么多,有時候一疏忽就忘了,所以才有那么多內存泄漏。
ES6 考慮到這點,推出了兩種新的數據結構:weakset 和 weakmap 。他們對值的引用都是不計入垃圾回收機制的,也就是說,如果其他對象都不再引用該對象,那么垃圾回收機制會自動回收該對象所占用的內存。
const wm = new WeakMap()const element = document.getElementById('example')
vm.set(element, 'something')
vm.get(element)
上面代碼中,先新建一個 Weakmap 實例。然后,將一個 DOM 節點作為鍵名存入該實例,並將一些附加信息作為鍵值,一起存放在 WeakMap 里面。這時,WeakMap 里面對 element 的引用就是弱引用,不會被計入垃圾回收機制。
注冊監聽事件的 listener 對象很適合用 WeakMap 來實現。
// 代碼1
ele.addEventListener('click', handler, false)
// 代碼2const listener = new WeakMap()
listener.set(ele, handler)
ele.addEventListener('click', listener.get(ele), false)
代碼 2 比起代碼 1 的好處是:由於監聽函數是放在 WeakMap 里面,一旦 dom 對象 ele 消失,與它綁定的監聽函數 handler 也會自動消失。

鏈接:https://www.jianshu.com/p/9af7fa367784
View Code

  參考鏈接:https://www.jianshu.com/p/9af7fa367784

 

   17.深拷貝和淺拷貝及怎么實現

淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址, 

深拷貝(deepCopy)是增加了一個指針並且申請了一個新的內存,使這個增加的指針指向這個新的內存,

深拷貝和淺拷貝最根本的區別在於是否真正獲取一個對象的復制實體,而不是引用。

假設B復制了A,修改A的時候,看B是否發生變化:

如果B跟着也變了,說明是淺拷貝,拿人手短!(修改堆內存中的同一個值)

如果B沒有改變,說明是深拷貝,自食其力!(修改堆內存中的不同的值)

https://www.cnblogs.com/williamjie/p/11192895.html

https://juejin.cn/post/6844903493925371917 深拷貝淺拷貝詳細講解(掘金)

淺拷貝只復制一層對象的屬性,並不包括對象里面的為引用類型的數據。

怎么進行深拷貝呢?

思路就是遞歸調用剛剛的淺拷貝,把所有屬於對象的屬性類型都遍歷賦給另一個對象即可。

4-4.深拷貝實現步驟

1. 如果傳入的對象不存在,就返回null;如果是特殊對象,就new一個特殊對象。

2. 創建一個對象objClone,來保存克隆的對象。

3. 然后遍歷對象,如果是基礎數據,就直接放入objClone

4. 如果是對象,就遞歸。

 

深淺拷貝如何實現

https://www.cnblogs.com/echolun/p/7889848.html

http://caibaojian.com/javascript-object-clone.html

 

2、淺拷貝的實現 2.1、簡單的引用復制 function shallowClone(copyObj) {
  var obj = {};
  for ( var i in copyObj) {
    obj[i] = copyObj[i];
  }
  return obj;
}
var x = {
  a: 1,
  b: { f: { g: 1 } },
  c: [ 1, 2, 3 ]
};
var y = shallowClone(x);
console.log(y.b.f === x.b.f);     // true
2.2、Object.assign()
Object.assign() 方法可以把任意多個的源對象自身的可枚舉屬性拷貝給目標對象,然后返回目標對象。
var x = {
  a: 1,
  b: { f: { g: 1 } },
  c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f);     // true
3、深拷貝的實現 3.1、Array的slice和concat方法
Array的slice和concat方法不修改原數組,只會返回一個淺復制了原數組中的元素的一個新數組。之所以把它放在深拷貝里,是因為它看起來像是深拷貝。而實際上它是淺拷貝。原數組的元素會按照下述規則拷貝:
如果該元素是個對象引用 (不是實際的對象),slice 會拷貝這個對象引用到新的數組里。兩個對象引用都引用了同一個對象。如果被引用的對象發生改變,則新的和原來的數組中的這個元素也會發生改變。
對於字符串、數字及布爾值來說(不是 String、Number 或者 Boolean 對象),slice 會拷貝這些值到新的數組里。在別的數組里修改這些字符串或數字或是布爾值,將不會影響另一個數組。
如果向兩個數組任一中添加了新元素,則另一個不會受到影響。例子如下:
var array = [1,2,3]; 
var array_shallow = array; 
var array_concat = array.concat(); 
var array_slice = array.slice(0); 
console.log(array === array_shallow); //true 
console.log(array === array_slice); //false,“看起來”像深拷貝
console.log(array === array_concat); //false,“看起來”像深拷貝
可以看出,concat和slice返回的不同的數組實例,這與直接的引用復制是不同的。而從另一個例子可以看出Array的concat和slice並不是真正的深復制,數組中的對象元素(Object,Array等)只是復制了引用。如下:
var array = [1, [1,2,3], {name:"array"}]; 
var array_concat = array.concat();
var array_slice = array.slice(0);
array_concat[1][0] = 5;  //改變array_concat中數組元素的值 
console.log(array[1]); //[5,2,3] 
console.log(array_slice[1]); //[5,2,3] 
array_slice[2].name = "array_slice"; //改變array_slice中對象元素的值 
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
3.2、JSON對象的parse和stringify
JSON對象是ES5中引入的新的類型(支持的瀏覽器為IE8+),JSON對象parse方法可以將JSON字符串反序列化成JS對象,stringify方法可以將JS對象序列化成JSON字符串,借助這兩個方法,也可以實現對象的深拷貝。
//例1
var source = { name:"source", child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
target.name = "target";  //改變target的name屬性
console.log(source.name); //source 
console.log(target.name); //target
target.child.name = "target child"; //改變target的child 
console.log(source.child.name); //child 
console.log(target.child.name); //target child
//例2
var source = { name:function(){console.log(1);}, child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
//例3
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
console.log(target.child); //Object {}
這種方法使用較為簡單,可以滿足基本的深拷貝需求,而且能夠處理JSON格式能表示的所有數據類型,但是對於正則表達式類型、函數類型等無法進行深拷貝(而且會直接丟失相應的值)。還有一點不好的地方是它會拋棄對象的constructor。也就是深拷貝之后,不管這個對象原來的構造函數是什么,在深拷貝之后都會變成Object。同時如果對象中存在循環引用的情況也無法正確處理。
4、jQuery.extend()方法源碼實現
jQuery的源碼 - src/core.js #L121源碼及分析如下:
jQuery.extend = jQuery.fn.extend = function() { //給jQuery對象和jQuery原型對象都添加了extend擴展方法
  var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
  i = 1,
  length = arguments.length,
  deep = false;
  //以上其中的變量:options是一個緩存變量,用來緩存arguments[i],name是用來接收將要被擴展對象的key,src改變之前target對象上每個key對應的value。
  //copy傳入對象上每個key對應的value,copyIsArray判定copy是否為一個數組,clone深拷貝中用來臨時存對象或數組的src。

  // 處理深拷貝的情況
  if (typeof target === "boolean") {
    deep = target;
    target = arguments[1] || {};
    //跳過布爾值和目標 
    i++;
  }

  // 控制當target不是object或者function的情況
  if (typeof target !== "object" && !jQuery.isFunction(target)) {
    target = {};
  }

  // 當參數列表長度等於i的時候,擴展jQuery對象自身。
  if (length === i) {
    target = this; --i;
  }
  for (; i < length; i++) {
    if ((options = arguments[i]) != null) {
      // 擴展基礎對象
      for (name in options) {
        src = target[name];    
        copy = options[name];

        // 防止永無止境的循環,這里舉個例子,如var i = {};i.a = i;$.extend(true,{},i);如果沒有這個判斷變成死循環了
        if (target === copy) {
          continue;
        }
        if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
          if (copyIsArray) {
            copyIsArray = false;
            clone = src && jQuery.isArray(src) ? src: []; // 如果src存在且是數組的話就讓clone副本等於src否則等於空數組。
          } else {
            clone = src && jQuery.isPlainObject(src) ? src: {}; // 如果src存在且是對象的話就讓clone副本等於src否則等於空數組。
          }
          // 遞歸拷貝
          target[name] = jQuery.extend(deep, clone, copy);
        } else if (copy !== undefined) {
          target[name] = copy; // 若原對象存在name屬性,則直接覆蓋掉;若不存在,則創建新的屬性。
        }
      }
    }
  }
  // 返回修改的對象
  return target;
};
jQuery的extend方法使用基本的遞歸思路實現了淺拷貝和深拷貝,但是這個方法也無法處理源對象內部循環引用,例如: var a = {"name":"aaa"};
var b = {"name":"bbb"};
a.child = b;
b.parent = a;
$.extend(true,{},a);//直接報了棧溢出。Uncaught RangeError: Maximum call stack size exceeded
5、自己動手實現一個拷貝方法 
var $ = (function () {
    'use strict';

    var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');

	function type () {
	   return Object.prototype.toString.call(this).slice(8, -1);
	}

	for (var i = types.length; i--;) {
	    $['is' + types[i]] = (function (self) {
	        return function (elem) {
	           return type.call(elem) === self;
	        };
	    })(types[i]);
	}

    return $;
})();//類型判斷

function copy (obj,deep) { 
    if (obj === null || (typeof obj !== "object" && !$.isFunction(obj))) { 
        return obj; 
    } 

    if ($.isFunction(obj)) {
    	return new Function("return " + obj.toString())();
    }
    else {
        var name, target = $.isArray(obj) ? [] : {}, value; 

        for (name in obj) { 
            value = obj[name]; 
            if (value === obj) {
            	continue;
            }

            if (deep && ($.isArray(value) || $.isObject(value))) {
            	target[name] = copy(value,deep);
            }
            else {
            	target[name] = value;
            } 
        } 
        return target;
    }         
}

 

 深拷貝的三種實現方式是什么:https://www.php.cn/faq/465102.html

1、遞歸遞歸去復制所有層級屬性;

2、用JSON對象的parse和stringify實現;

3、借用JQ的extend方法。

 

function deepClone(obj){

    let objClone = Array.isArray(obj)?[]:{};   
if(obj && typeof obj==="object"){

for(key in obj){

if(obj.hasOwnProperty(key)){ //判斷ojb子元素是否為對象,如果是,遞歸復制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,簡單復制 objClone[key] = obj[key]; } } } } return objClone; } let a=[1,2,3,4], b=deepClone(a); a[0]=2; console.log(a,b);

 

 

  18.promiss與async和await的區別

 

  19.webstorage怎么賦值(轉化成字符串賦值)

  localStorage存儲數組以及取數組方法。

  var weekArray = ['周一'、'周二'、'周三'、'周四'、'周五']
  存:localStorage.setItem('weekDay',JSON.stringify(weekArray));
  取: weekArray = JSON.parse(localStorage.getItem('weekDay'));

 

  120.post跨域怎么處理

三:vue

  1.什么是MVVM

MVVM是Model-View-ViewModel的縮寫。MVVM是一種設計思想。Model 層代表數據模型,也可以在Model中定義數據修改和操作的業務邏輯;View 代表UI 組件,它負責將數據模型轉化成UI 展現出來,ViewModel 是一個同步View 和 Model的對象。

MVVM架構下,View 和 Model 之間並沒有直接的聯系,而是通過ViewModel進行交互,Model 和 ViewModel 之間的交互是雙向的, 因此View 數據的變化會同步到Model中,而Model 數據的變化也會立即反應到View 上。

ViewModel 通過雙向數據綁定把 View 層和 Model 層連接了起來,而View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關注業務邏輯,不需要手動操作DOM, 不需要關注數據狀態的同步問題,復雜的數據狀態維護完全由 MVVM 來統一管理。

  2.VUE的響應式原理

Vue 的響應式原理是核心是通過 ES5 的保護對象的 Object.defindeProperty 中的訪問器屬性中的 get 和 set 方法,data 中聲明的屬性都被添加了訪問器屬性,當讀取 data 中的數據時自動調用 get 方法,當修改 data 中的數據時,自動調用 set 方法,檢測到數據的變化,會通知觀察者 Wacher,觀察者 Wacher自動觸發重新render 當前組件(子組件不會重新渲染),生成新的虛擬 DOM 樹,Vue 框架會遍歷並對比新虛擬 DOM 樹和舊虛擬 DOM 樹中每個節點的差別,並記錄下來,最后,加載操作,將所有記錄的不同點,局部修改到真實 DOM 樹上。

 虛擬DOM (Virtaul DOM): 用 js 對象模擬的,保存當前視圖內所有 DOM 節點對象基本描述屬性和節點間關系的樹結構。用 js 對象,描述每個節點,及其父子關系,形成虛擬 DOM 對象樹結構。

  3.v-if和v-show的區別

共同點:v-if 和 v-show 都能實現元素的顯示隱藏

區別:

    1. v-show 只是簡單的控制元素的 display 屬性,而 v-if 才是條件渲染(條件為真,元素將會被渲染,條件為假,元素會被銷毀);

    2.  v-show 有更高的首次渲染開銷,而 v-if 的首次渲染開銷要小的多;

    3. v-if 有更高的切換開銷,v-show 切換開銷小;

    4. v-if 有配套的 v-else-if 和 v-else,而 v-show 沒有

    5. v-if 可以搭配 template 使用,而 v-show 不行


作者:壞孩子的琉璃
鏈接:https://www.jianshu.com/p/987973460040

  4.組件之間傳值

 

 

  5.vue生命周期及各階段情況

注意:瀏覽器有8個鈎子,但是node中做服務端渲染的時候只有beforeCreatecreated

beforeCreatenew Vue()之后觸發的第一個鈎子,在當前階段datamethodscomputed以及watch上的數據和方法都不能被訪問。

created在實例創建完成后發生,當前階段已經完成了數據觀測,也就是可以使用數據,更改數據,在這里更改數據不會觸發updated函數。可以做一些初始數據的獲取,在當前階段無法與Dom進行交互,如果非要想,可以通過vm.$nextTick來訪問Dom

beforeMount發生在掛載之前,在這之前template模板已導入渲染函數編譯。而當前階段虛擬Dom已經創建完成,即將開始渲染。在此時也可以對數據進行更改,不會觸updated

mounted掛載完成后發生,在當前階段,真實的Dom掛載完畢,數據完成雙向綁定,可以訪問到Dom節點,使用$refs屬性對Dom進行操作。

beforeUpdate發生在更新之前,也就是響應式數據發生更新,虛擬dom重新渲染之前被觸發,你可以在當前階段進行更改數據,不會造成重渲染。

updated發生在更新完成之后,當前階段組件Dom已完成更新。要注意的是避免在此期間更改數據,因為這可能會導致無限循環的更新。

beforeDestroy發生在實例銷毀之前,在當前階段實例完全可以被使用,我們可以在這時進行善后收尾工作,比如清除計時器,銷毀父組件對子組件的重復監聽。beforeDestroy(){Bus.$off("saveTheme")}

destroyed發生在實例銷毀之后,這個時候只剩下了dom空殼。組件已被拆解,數據綁定被卸除,監聽被移出,子實例也統統被銷毀。

  6.webpack打包原理

             1、webpack打包原理

      把所有依賴打包成一個 bundle.js 文件,通過代碼分割成單元片段並按需加載

    2、webpack的優勢

      (1) webpack 是以 commonJS 的形式來書寫腳本滴,但對 AMD/CMD 的支持也很全面,方便舊項目進行代碼遷移。
      (2)能被模塊化的不僅僅是 JS 了。
      (3) 開發便捷,能替代部分 grunt/gulp的工作,比如打包、壓縮混淆、圖片轉base64等。
      (4)擴展性強,插件機制完善

        7.keep-alive的生命周期

  • keep-alive的生命周期
  1. activated: 頁面第一次進入的時候,鈎子觸發的順序是created->mounted->activated
  2. deactivated:  頁面退出的時候會觸發deactivated,當再次前進或者后退的時候只觸發activated

        8.父子組件created和mounted加載順序

  1.組件創建的順序
  父組件先執行,執行到父組件執行到beforeMount之后,然后在去執行子組件的生命周期,beforeMount 和Mount ,執行完成了在執行父組件的Mount。
  例如:

  綜上述說:如果父組件要獲取數據,並使用props傳入子組件中,將數據渲染的話,需要將數據的請求放在父組件的created生命周期中發起請求。
  ————————————————
  版權聲明:本文為CSDN博主「MsimonBlowSnow」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
  原文鏈接:https://blog.csdn.net/MsimonBlowSnow/article/details/110438270

  9.wacth和computer區別  

  計算屬性computed
  1. 支持緩存,只有依賴數據發生改變,才會重新進行計算

  2. 不支持異步,當computed內有異步操作時無效,無法監聽數據的變化

  3.computed 屬性值會默認走緩存,計算屬性是基於它們的響應式依賴進行緩存的,也就是基於data中聲明過的數據通過計算得到的

  4. 如果一個屬性是由其他屬性計算而來的,這個屬性依賴其他屬性,是一個多對一或者一對一,一般用computed

  5.如果computed屬性屬性值是函數,那么默認會走get方法;函數的返回值就是屬性的屬性值;在computed中的,屬性都有一個get和一個set方法,當數據變化時,調用set方法。

  偵聽屬性watch:
  1. 不支持緩存,數據變,直接會觸發相應的操作;

  2.watch支持異步;

  3.監聽的函數接收兩個參數,第一個參數是最新的值;第二個參數是輸入之前的值;

 

  適用場景:
  watch擅長處理的場景:一個數據影響多個數據

  computed擅長處理的場景:一個數據受多個數據影響
  ————————————————
  版權聲明:本文為CSDN博主「宇宙超級無敵博」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
  原文鏈接:https://blog.csdn.net/qq_35410544/article/details/111314397

  9.Vue雙向數據綁定原理 

  vue.js是采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調來渲染視圖。

 

  10.什么情況下Vue使用index作為key會出問題(轉):

  在使用非文本節點的組件,且這個組件沒有依賴於響應式的props,那么此時對於列表的刪除操作會導致視圖錯亂。

       https://www.cnblogs.com/eret9616/p/13642900.html

 

       11.vue 能不能在v-for中嵌套v-if

  v-for 具有比 v-if 更高的優先級,這意味着 v-if 將分別重復運行於每個 v-for 循環中

  所以,不推薦v-if和v-for同時使用,建議用computed計算屬性先對數據列表進行過濾,然后再去渲染 

 

或者:放在計算屬性遍歷

 

 

  12.怎么獲取dom節點?

  我們在vue中需要操作某一個元素的時候,可以在元素上添加ref屬性,使用$refs來獲取到該元素,進而進行一些列操作。

<template>
    <div class="contaier" ref="box" style="width: 100px;height: 100px;">
        這里用來測試元素的ref屬性
    </div>
    <button type="button" @click="showData()">點擊</button>
</template>

<script>
    export default {
        methods: {
            showData() {
                console.log(this.$refs.box);
                console.log(this.$refs.box.style);
            }
        }
    }
</script>
————————————————
版權聲明:本文為CSDN博主「自由如風hsj」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_23366033/article/details/108294032

  13.懶加載

  • 也叫延遲加載,即在需要的時候進行加載,隨用隨載。
  • 個人根據功能划分為圖片的懶加載和組件的懶加載。
  • https://www.jianshu.com/p/d6f8bf71eb11

  14.vue中data為什么必須是個函數?

  1.vue中組件是用來復用的,為了防止data復用,將其定義為函數。

  2.vue組件中的data數據都應該是相互隔離,互不影響的,組件每復用一次,data數據就應該被復制一次,之后,當某一處復用的地方組件內data數據被改變時,其他復用地方組件的data數據不受影響,就需要通過data函數返回一個對象作為組件的狀態。

  3.當我們將組件中的data寫成一個函數,數據以函數返回值形式定義,這樣每復用一次組件,就會返回一份新的data,擁有自己的作用域,類似於給每個組件實例創建一個私有的數據空間,讓各個組件實例維護各自的數據。

  4.當我們組件的date單純的寫成對象形式,這些實例用的是同一個構造函數,由於JavaScript的特性所導致,所有的組件實例共用了一個data,就會造成一個變了全都會變的結果。
  ————————————————
  版權聲明:本文為CSDN博主「DaftJayee」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
  原文鏈接:https://blog.csdn.net/qq_43540219/article/details/109077387

 

四:es6

  1.var和let和const

        let和const必須先聲明后使用,會存在“暫時性死區”,不存在變量提升

  2.什么是promiss

Promise 是異步編程的一種解決方案,比傳統的異步解決方案【回調函數】和【事件】更合理、更強大。

1、主要用於異步計算
2、可以將異步操作隊列化,按照期望的順序執行,返回符合預期的結果
3、可以在對象之間傳遞和操作promise,幫助我們處理隊列

new Promise(

  function (resolve, reject) {

    // 一段耗時的異步操作

    resolve('成功') // 數據處理完成

    // reject('失敗') // 數據處理出錯

  }).then(

  (res) => {console.log(res)},  // 成功

  (err) => {console.log(err)} // 失敗)

 

Promise是最大的好處是為了避免“回調地獄”,就是多層的回調

Promise 是異步編程的一種解決方案,Promise對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。

回調包裝成Promise,他有兩個顯而易見的好處:
1、可讀性好
2、返回 的結果可以加入任何Promise隊列

局限性:

promise狀態一經改變,不會再變。

· 首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。

· 其次,如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。

· 第三,當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

· 當接收到一個代表錯誤的 HTTP 狀態碼時,從 fetch() 返回的 Promise 不會被標記為 reject, 即使響應的 HTTP 狀態碼是 404 或 500。相反,它會將 Promise 狀態標記為 resolve (但是會將 resolve 的返回值的 ok 屬性設置為 false ),僅當網絡故障時或請求被阻止時,才會標記為 reject。

 

  3.箭頭函數

  

 

五:算法

 

  1.冒泡排序  

function bubleSort(arr){
	for (var i=0;i<arr.length-1;i++) {
		for (j=i+1;j<arr.length;j++) {
			if(arr[i]>arr[j]){
				var temp=arr[i];
				arr[i]=arr[j];
				arr[j]=temp;
			}
		}
	}
	return arr;
}
var arr2=[7,2,4,5,1,6];
console.log(bubleSort(arr2));

  

//冒泡排序:即實現數組由小到大進行排序;思路為:每次比較相鄰的兩個數,如果后一個比前一個小,換位置。如果要實現由大到小排序,使用reverse()即可
var arr = [3,2,1,5,4,7,6]; function bubbleSort(arr){ var len = arr.length; for (var i= len;i>=2;--i) { for (var j=0;j<i-1;j++) { if(arr[j+1]<arr[j]){ var temp; temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } return arr; } var arr2 = bubbleSort(arr); console.log(arr2); //從小到大 var arr3 = arr2.reverse(); console.log(arr3); //從大到小

 

  2.快速排序和二分查找

//快速排序:思路:采用二分法,取出中間數,數組每次和中間數比較,小的放到左邊,大的放右邊
var arr = [3,1,4,2,6,5,7];
function quickSort(arr){
    if(arr.length == 0){
        return [];  //返回空數組
    }
    var cIndex = Math.floor(arr.length / 2);
    var c= arr.splice(cIndex,1);
    var l = [];
    var r = [];
    for (var i=0;i<arr.length;i++) {
        if(arr[i]<c){
            l.push(arr[i]);
        }else{
            r.push(arr[i]);
        }
    }
    return quickSort(l).concat(c,quickSort(r));
}
console.log(quickSort(arr));

 

//二分查找,前提是有序數組
function binarySearch(target, arr) {
	var l = 0,
		r = arr.length - 1;
	while(l <= r) {
		var mid = l + parseInt((r - l) / 2);
		if(arr[mid] == target) {
			return mid;
		} else if(target > arr[mid]) {
			l = mid + 1;
		} else if(target < arr[mid]) {
			r = mid - 1;
		}

	}
	return -1;
}
var arr = [1, 2, 4, 6, 8, 9, 11, 34, 67];
console.log(binarySearch(11, arr));

  

 

  3.數組的翻轉(非reverse())

<h2>方法一:</h2>
        <script type="text/javascript">
            var arr = [1,2,3,4];
            var arr2 = [];
            while(arr.length){
                var num = arr.pop();  //刪除數組最后一個元素並返回被刪除的元素
                arr2.push(num);
            }
            console.log(arr2);
        </script>
        <h2>方法二:</h2>
        <script type="text/javascript">
            var arr = [1,2,3,4];
            var arr2 = [];
            while(arr.length){
                var num = arr.shift();  //刪除數組第一個元素並返回被刪除的元素;
                arr2.unshift(num);   //unshift() 方法可向數組的開頭添加一個或更多元素,並返回新的長度。
            }
            console.log(arr2);
        </script>

 

 

  4.數組由小到大進行排序

//a-b是從小到大;b-a是從大到小
var arr = [3,43,25,30,65,90];
function sortnum(a,b){
    return a-b;
}
arr = arr.sort(sortnum);
console.log(arr);

 

 

  5.數組去重

<p>方法一:</p>
        <script type="text/javascript">
            var arr = [0,2,3,4,4,0,2];
            var obj = {};
            var tmp = [];
            for (var i=0;i<arr.length;i++) {
                if(!obj[arr[i]]){
                    obj[arr[i]] = 1;
                    tmp.push(arr[i]);
                }
            }
            console.log(tmp);
        </script>
        <p>方法二:indexOf() 方法可返回某個指定的字符串值在字符串中首次出現的位置。</p>
        <script type="text/javascript">
            var arr = [2,3,4,4,5,2,3,6],
                arr2 = [];
            for (var i=0;i<arr.length;i++) {
                if(arr2.indexOf(arr[i])<0){
                    arr2.push(arr[i]);
                }
            }
            console.log(arr2);
        </script>
        <p>方法三:</p>
        <script type="text/javascript">
            var arr = [2,3,4,4,5,2,3,6];
            var arr2 = arr.filter(function(element,index,self){
                return self.indexOf(element) === index;
            });
            console.log(arr2);
        </script>

 

  6.判斷一個字符串中出現次數最多的字符,統計這個次數

var str = 'asdfssaaasasasasaa';
var json = {};
for (var i=0;i<str.length;i++) {  //charAt() 方法可返回指定位置的字符。
    if(!json[str.charAt(i)]){
        json[str.charAt(i)] = 1;
    }else{
        json[str.charAt(i)]++;
    }
};
var iMax = 0;
var iIndex = '';
for (var i in json) {
    if(json[i]>iMax){
        iMax = json[i];
        iIndex = i;
    }
}
console.log('出現次數最多的是:'+iIndex+'出現'+iMax+'次');

 

  7.apply()/call()求數組最值

<script type="text/javascript">
                var numbers = [5,458,120,-215];
                var maxNumber= Math.max.apply(this,numbers);
                console.log(maxNumber);  //458
                var maxnumber = Math.max.call(this,5,458,120,-215);
                console.log(maxnumber);  //458
            </script>

 

  8.獲取瀏覽器URL中查詢字符串中的參數

function showWindowHref (){
	var sHref = window.location.href;
	var args = sHref.split('?');
	if(args[0] == sHref){
		return "";
	}
	var arr = args[1].split("&");
	var obj = {};
	for (var i=0;i<arr.length;i++) {
		var arg = arr[i].split('=');
		obj[arg[0]] = arg[1];
	}
	return obj;
}
var href = showWindowHref();  //obj
console.log(href['name']);  //xiaoming

   10.2個對象排序{age:10,name:'lili'}

       var a={age:10,name:"lili"}

  var a={age:13,name:"lisi"}

   function(a,b){

             if(a.age==b.age){

                   if(a.name.toString()>b.name.toString()){

                        return true;

              }else{return false;}

             }else{

                   if(a.age>b.age){

                        return true

                    }else{return false;}

             }

        }
  11.設計模型

   https://www.jianshu.com/p/4f3014fb8b8b

  12.JavaScript將具有父子關系的原始數據格式化成樹形結構數據(id,pid)

  

// 方法一while
var data=[
{id:1,pid:0,text:'A'},
{id:2,pid:4,text:"E[父C]"},
{id:3,pid:7,text:"G[父F]"},
{id:4,pid:1,text:"C[父A]"},
{id:5,pid:6,text:"D[父B]"},
{id:6,pid:0,text:'B'},
{id:7,pid:4,text:"F[父C]"}
];
function toTreeData(data){
    var pos={};
    var tree=[];
    var i=0;
    while(data.length!=0){
        if(data[i].pid==0){
            tree.push({
                id:data[i].id,
                text:data[i].text,
                children:[]
            });
            pos[data[i].id]=[tree.length-1];
            data.splice(i,1);
            i--;
        }else{
            var posArr=pos[data[i].pid];
            if(posArr!=undefined){

                var obj=tree[posArr[0]];
                for(var j=1;j<posArr.length;j++){
                    obj=obj.children[posArr[j]];
                }

                obj.children.push({
                    id:data[i].id,
                    text:data[i].text,
                    children:[]
                });
                pos[data[i].id]=posArr.concat([obj.children.length-1]);
                data.splice(i,1);
                i--;
            }
        }
        i++;
        if(i>data.length-1){
            i=0;
        }
    }
    console.log(tree)
    return tree;
    
}
toTreeData(data)

 

// 方法二:遞歸
        var data1= [{
    id: 1,
    name: '1',
}, {
    id: 2,
    name: '1-1',
    parentId: 1
}, {
    id: 3,
    name: '1-1-1',
    parentId: 2
}, {
    id: 4,
    name: '1-2',
    parentId: 1
}, {
    id: 5,
    name: '1-2-2',
    parentId: 4
}, {
    id: 6,
    name: '1-1-1-1',
    parentId: 3
}, {
    id: 7,
    name: '2',
}]
/**
 * 該方法用於將有父子關系的數組轉換成樹形結構的數組
 * 接收一個具有父子關系的數組作為參數
 * 返回一個樹形結構的數組
 */
function translateDataToTree(data) {
  //沒有父節點的數據
  let parents = data.filter(value => value.parentId == 'undefined' || value.parentId == null)
  //有父節點的數據
  let children = data.filter(value => value.parentId !== 'undefined' && value.parentId != null)
  //定義轉換方法的具體實現
  let translator = (parents, children) => {
    //遍歷父節點數據
    parents.forEach((parent) => {
      //遍歷子節點數據
      children.forEach((current, index) => {
        //此時找到父節點對應的一個子節點
        if (current.parentId === parent.id) {
          //對子節點數據進行深復制,這里只支持部分類型的數據深復制,對深復制不了解的童靴可以先去了解下深復制
          let temp = JSON.parse(JSON.stringify(children))
          //讓當前子節點從temp中移除,temp作為新的子節點數據,這里是為了讓遞歸時,子節點的遍歷次數更少,如果父子關系的層級越多,越有利
          temp.splice(index, 1)
          //讓當前子節點作為唯一的父節點,去遞歸查找其對應的子節點
          translator([current], temp)
          //把找到子節點放入父節點的children屬性中
          typeof parent.children !== 'undefined' ? parent.children.push(current) : parent.children = [current]
        }
      }
      )
    }
    )
  }
  //調用轉換方法
  translator(parents, children)
  //返回最終的結果
  console.log(parents)
  return parents
  
}
translateDataToTree(data1)

 

 

----------聲明:此文章是方便自己面試總結,一些解答是學習其他博主內容,我記錄過原文鏈接的都放出來了,沒記錄過得不是故意沒備注原文鏈接,望體諒,若有侵權,聯系我改,謝謝--------

 

https://www.cnblogs.com/star91/p/5659134.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM