常見面試題整理(碼字ing)

for in 和 for of 的區別

經過如下例子助你理解

//1. 循環對象
    let obj = {
        name: 'hello',
        age: 25
    }
    for (let i in obj){
        console.log(i)
        // name age
    }
    
    for(let i of obj){
        console.log(i)
        // Uncaught TypeError: obj is not iterable 報錯了,由於對象沒有部署Symbol.iterator 屬性。
    }
    //2. 循環數組
    let arr  = ['a','b','c'];
    for(let i in arr){
        console.log(i) // 0,1,2
    }
    for(let i of arr){
        console.log(i) // a,b,c
    }
複製代碼

for in 的特色

  • for in 比較適合遍歷對象。
  • 遍歷對象返回的都是key值,數組也是,在數組中叫(下標)

for of 的特色

  • for of 循環的對象必須部署symbol.iterator屬性,不然就會報錯。普通對象是沒有symbol.iterator屬性
    • 擁有symbol.iterator屬性的對象以下
      • 數組Array
      • Map
      • Set
      • String
      • argument對象等等
  • for of獲取的值時鍵值對的值

vue-router裏兩個模式的區別,用了哪些原生的API

hash 模式

  • hash模式的原理是onhashchange事件,能夠在window監聽hash的變化
window.onhashchange = function(event){
    consoel.log(event)// 返回一個
    }
複製代碼
  • hash模式實現的路由,連接後面添加#+路由

history 模式

  • history模式用到的原生API有window.history.popState('傳參','標題','跳轉的路由地址')windown.history.pushState()、以及window.history.replaceState('傳參','標題','跳轉的路由地址')
    • window.history.pushState只是改變了後面的路由,頁面並無跳轉,也沒有從新加載。repalceState也是同樣。
    • window.onpopState只有在點擊瀏覽器的前進或者後退按鈕纔會出觸發,或者調用history.back()forward()等方法
  • history模式實現是連接後面直接加路由,網址更好看。
  • history的使用須要後端配合使用,若是後端沒有設置,生產環境下會404。

共有的特色 更新視圖可是不從新加載頁面

  • hash雖然出如今url地址中,但它不被包含在HTTP請求裏,他是用來指示瀏覽器的,對服務器端沒有任何做用,改變hash不會從新加載頁面,我們能夠經過設置onhashchange實現更新視圖可是不從新加載頁面
  • history中pushStatereplaceState這兩個方法雖說修改了瀏覽器的歷史記錄棧,雖然當前的url路由改變了,可是不會從新加載頁面。這就爲了更新視圖但不從新加載頁面提供了基礎。

使用vue-lazyload 插件實現圖片懶加載

  • 使用npm下載lazyload插件npm i vue-lazyload
  • 在main.js中引用文件
    import vueLazy form 'vue-lazyload'
    Vue.use(vueLazy,{
        preLoad: 1, //提早加載的高度,數字1表明一屏的高度
        error: imgUrl, //圖片加載失敗時顯示的圖片
        loading: imgUrl, //圖片加載成功顯示的圖片
        attempt: 2 //圖片加載錯誤後,最大的嘗試次數
    })
    複製代碼

vuex

  • 爲何使用vuex,能夠簡單理解爲,組件中的data屬性須要共享時,可使用vuex進行統一的狀態管理。

vuex的使用

vuex中默認的五種基本對象

state

  • 存儲變量,至關於組件中的data
export default new Store({
    state:{
        count:2
    }
})
複製代碼

mutations

  • 修改state中的變量,而且是同步的,在組件中調用`this.$store.commit('方法名',傳參)
    • 由於vuex中不建議經過this.$store.state直接修改變量。
export default new Store({
    state:{
        count:2
    },
    mutations:{
        changeCount(state,n){
            state.count += n
        }
    }
})

mounted(){
    this.$store.commit('changeCount',5)
}
//在html中用{{$store.state.count}}
複製代碼

actions

  • 異步修改state變量,這個的原理經過actions中的方法去調用mutations中的方法去改變state。
  • actions內部會接收一個context對象,這個對象裏有{dispatch, commit, getters, state, rootGetters...}等等方法,actions方法通常是用來調用mutations的,咱們能夠解構賦值{commit},直接使用。
export default new Store({
    state:{
        count:2
    },
    mutations:{
        changeCount(state,n){
            state.count += n
        }
    },
    actions:{
        yiCount(context,n){
            
        }
    }
    // 項目中通常都是這樣寫的
    actions:{
        yiCount({commit},n){
            commit('changeCount',5)
        }
    }
     
})

mounted(){
    this.$store.dispatch('yiCount',5)
}
複製代碼

getters

  • 它能夠根據state中的變量進行其餘的計算操做,返回的是一個新的變量,咱們能夠經過this.$store.getters.filTodos調用。可是它不會改變state中的變量。
    export default new Store({
    state:{
        count:2,
        todos:todos: [
          { id: 1, text: "你好", done: true },
          { id: 2, text: "世界", done: false },
        ],
    },
    getters:{
        filTodos(state){
           state.todos.filter((item)=>{
               return item.done
           })
        }
    }
     
    })
    
    //組件中調用 
    mounted(){
        let a = this.$store.getters.filTodos
        //{ id: 1, text: "你好", done: true },
    }
    複製代碼

flex佈局

設置flex佈局

  • 塊級元素display:flex
  • 行內塊元素:display:inline-flex

父級元素設置flex後也叫作flex容器,設置容器屬性

設置主軸的方向flex-diretion

  • 水平方向
    • flex-direction:row:主軸水平方向,從左到右
    • flex-diretion:row-reverse:主軸方向,從右到左
  • 垂直方向
    • flex-diretion:column:垂直方向,從上到下css

    • flex-diretion:column-reverse:主軸方向,從下往上html

設置項目是否換行

  • flex-wrap:nowrap //默認,若是不換行,當項目寬度超過之後,它的寬度會失效,變成全部項目在一行內平分寬度。
  • flex-wrap:wrap //換行,第一行在上方
  • flex-wrap:wrap-reverse //換行第一行在下方

設置項目在主軸的對齊方式,以主軸爲水平方向爲例

  • justify-content:flex-start //默認左對齊
  • justify-content:center //居中對齊
  • justify-content:flex-end //右對齊
  • justify-content:space-between // 左右兩個項目貼邊對齊,中間的項目間隔相等。
  • justify-content:space-around //左右兩個項目是中間項目之間間隔的一半。

設置交叉軸(垂直)的對齊方式,以垂直方向爲例

  • align-item:flex-start //從上往下默認
  • align-item:center //居中
  • align-item:flex-end //從下往上
  • align-item:baseline //基線對齊,其實就是項目中全部文字的最底端對齊

設置子元素(項目)的屬性

設置排列順序

  • order屬性必須是單個添加的纔有用,假設ul>li{order:1},全部li項目都是1,它的排列順序是不會有變化的。假設須要第二個li排在最前面,咱們能夠設置li:nth-child(2){order:-10},order的值越小排序越靠前。
    • order:2

設置項目的放大比例

  • flex-grow這個設置項目的比例
  • flex-grow:1

設置項目的縮小比例

  • 當空間不足的時候,縮小的比例
  • flex-shrink:0 // 默認是0

flex-basis默認爲auto,項目自己的大小,項目中就用auto就行

flex屬性

  • flex屬性是flex-grow、flex-shrink、flex-basis的縮寫。
    • 通常都是flex:1 0 auto。

注意

  • 使用flex佈局的時候,最後對寬度進行一個設置反正就尼瑪的設置寬度

垂直居中

<div>
       <p></p>
   </div>
   
   <style> div{ display:flex; justify-content:center; align-item:center; } </style>
複製代碼

深拷貝和淺拷貝

淺拷貝

  • 淺拷貝就是共用一個地址,只要其中一個的屬性值發生改變,這兩個都會改變。最外層的堆內存地址是不同的,可是裏面的的地址是同樣的,以下obj.b的地址是同樣的,因此修改obj.b中的值,因此兩個對象都是聯動的。

實現一個淺拷貝

let obj = {name:'你好',b:{age:25}}
    function shallowClone(obj){
        if(obj===null) return null
        if(obj instance Date) return new Date(obj)
        if(obj instance RegExp) return RegExp(obj)
        let newObj = {}
        for(var i in obj){
            newObj[i] = obj[i]
        }
        return newObj
    }
   let a = shallowColne(obj)
   a.b.age = 55
   console.log(obj)  //{name:'你好',b:{age:55}}
複製代碼

深拷貝

  • 深拷貝開闢兩個徹底不同的堆內存,對對象中的全部子對象進行遞歸拷貝,拷貝先後兩個對象互不影響。

實現深拷貝

let obj = {name:'你好',b:{age:25}}
function deep(obj){
    let newObj = {}
    if(obj === null) return null
    if(obj === Date) return new Date(obj)
    if(obj === RegExp) return new RegExp(obj)
    if(typeof(obj) != 'object') return obj
    for (var i in obj){
        newObj[i] = deep(obj[i])
    }
    return newObj
}
複製代碼

css畫斜線

  • 旋轉法
div{
    border: 1px solid red;
    transform: rotate(45deg)
}
複製代碼
  • 畫兩個三角形,而後另外一個三角形用定位去蓋住三角形
div{
    width: 0
    height: 0
    border: 100px solid
    border-color: transparent yellow transparent transparent
}
複製代碼

兩列布局

用calc加浮動

  • html 部分
    <div class= 'main'>
        <div class= 'left'></div>
        <div class= 'right'></div>
    </div>
    複製代碼
  • css部分
    .main{
        overflow:hidden
        width:100%
        height:100%
    }
    .left{
        height:100%
        width:250px
        float:left
        background:red
    }
    .right{
        height:100%
        width:calc(100% - 250px)
        float:left
        background:yellow
    }
    複製代碼

右邊margin-left,左邊浮動

.main{
       overflow:hidden
       width:100%
       height:100%
   }
   .left{
       height:100%
       width:250px
       float:left
       background:red
   }
   .right{
       width:100%
       height:100%
       margin-left:250px
       background:yellow
   }
複製代碼

左邊絕對定位+右邊浮動

.main{
        overflow:hidden
        width:100%
        height:100%
    }
    .left{
        height:100%
        width:250px
        position:absolute
        background:red
    }
    .right{
        width:100%
        height:100%
        float:right
        background:yellow
    }
複製代碼

利用flex佈局

.main{
        display:flex
        width:100%
        height:100%
    }
    .left{
        height:100%
        width:250px
        background:red
    }
    .right{
        height:100%
        flex:1
        background:yellow
    }
複製代碼

中間自適應,兩邊固定

聖盃佈局

.main{
    position;relative;
    padding: 0 250px
}
.left{
        height:100%
        width:250px
        background:red
        position:absolute
        top:0
        left:0
}
.right{
        width:250px
        height:100%
        background:yellow
        position:absolute
        top:0
        right:0
}
複製代碼

calc+浮動

.main{
        overflow:hidden
        width:100%
        height:100%
    }
.left{
        height:100%
        width:250px
        float:left
        background:red
     }
.right{
        height:100%
        width: 250px
        float:left
        background:yellow
      }
.center{
    height:100%
    float:left
    width:calc(100% - 500px)
    background:blue
}
複製代碼

數組去重的幾種方法

循環+indexOf

let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
    let ary = [];
    arr.forEach((item) => {
      if (ary.indexOf(item) === -1) {
        ary.push(item);
      }
    });
    console.log(ary);//[11, 2, 3, 4, 1, 5, 56]
複製代碼

利用對象屬性名不重名的特性

let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
    let ary = {};
    let a = [];
    arr.forEach((item) => {
      ary[item] = 1;
    });
    Object.keys(ary).forEach((item) => {
      a.push(Number(item));
    });
    console.log(a);//[11, 2, 3, 4, 1, 5, 56]
複製代碼

利用set和Array.from

  • Set對象存儲的對象值都是惟一的
  • Array.from將一個類數組,或者屬性名是數字且有lenth屬性的對象,淺拷貝生成一個新的數組
let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
let a = new Set(arr)
let b = Array.from(a)
console.log(b)//[11, 2, 3, 4, 1, 5, 56]
複製代碼

經常使用的ES6

let const

let const var的區別

  • let const 聲明不會產生變量提高
  • let const 不能重複聲明
  • let const 存在塊級做用域
  • let var 聲明時能夠不賦值

模板字符串

  • 名字:${name}

箭頭函數

箭頭函數和普通函數的區別

  • 箭頭函數沒有argument
  • 箭頭函數沒有this,若是在箭頭函數內部寫this,它是繼承上下文的this
  • 箭頭函數不能new執行
  • 箭頭函數沒有原型

函數形參默認值

Object.assign

  • 合併對象,淺拷貝
let obj = {name:45,age:56}
let a = Object.assign(obj)
a.name = 85
console.log(obj) // {name:85,age:56}
複製代碼

Set對象

  • 將數組轉爲對象,並且對象的值是惟一的。經過用來數組去重

解構賦值

解析url,獲取傳參

let str = "www.baodu.com?name=12&age=13";
    let obj = {};
    function getData(a) {
      let ary = a.split("?");
      let b = ary[1].split("&");
      console.log(b);
      b.forEach((item) => {
        let c = item.split("=");
        obj[c[0]] = c[1];
      });
      console.log(obj);
    }
    getData(str);
複製代碼

柯里化

  • 柯里化就是閉包的高級版
  • add(1)(2)==>3
function add(...arg) {
      let a = [...arg];
      return function(b) {
        a.push(b);
        return a.reduce((total, item) => {
          return total + item;
        });
      };
    }
    console.log(add(1)(2));//3
複製代碼

new 一個函數執行時執行步驟

  • 先建立一個空對象
  • 將this指向這個空對象
  • 函數執行,給這個新對象添加屬性和方法
  • 返回這個新建立的對象(因此構造函數不須要return,若是有return,return的是一個對象,就返回這個對象,若是是個非對象,就返回剛建立的對象)
    function fn(obj){
        this.name = obj
        console.log(obj)
    }
    new fn()
    複製代碼

call bind apply

bind

bind的做用

  • 是改變當前函數的this,返回一個新的函數,並將this進行改變,不當即執行。

手寫bind

  • 由於bind必須是全部函數均可以調用,故myBind得加在函數的公共方法
Function.prototype.myBind = function(){
    //這裏面的this確定是須要更改的函數,由於fn.myBind(),this == fn
    let f = this
    return 
}
複製代碼

連續bind的問題

let obj = { name: 15 };
    let obj2 = { age: 5 };
    function a() {
      console.log(this);
    }
  
    let b = a.bind(obj).bind(obj2);
    b()// 返回的時第一次bind的this
複製代碼
  • 由於將a.bind(obj)=a3
  • b() == a3.bind(obj2) //這樣a3的this指向obj2
  • a3() == 將a的this指向obj

call

call的做用

  • call的做用是改變this指向,並當即執行函數。

手寫call

  • 必須是全部函數均可以調用
    let obj = {name: 15, age: 16}
    Function.prototype.myCall(){
        let [context,...args] = arguments
        if(!context){
            context = window
        }
        context.fuc = this
        let res = context.fuc(...args)
        delete context.fuc
        return res
    }
    function fn(...args){
        return args.reduce((total,item)=>{
            return total+item
        })
    }
    fn.myCall(obj,1,2,3)
    複製代碼

apply

apply的做用

  • 改變this的指向,並當即執行函數,參數爲數組的形式

手寫apply

Function.prototype.myApply = function (){
    let [contxt,...args] = arguments
    context.fuc = this || window
    let res = context.fuc(...args)
    delete context.fuc
    return res
}
複製代碼

vue中$nextTick的原理和應用

vue.$nextTick原理,緣由

  • vue是異步執行dom更新的,一旦觀察到數據變化,Vue就會開啓一個隊列,其實也就是事件循環(Event loop),能夠將事件循環理解爲一個圓圈,同一時間段內更新的Dom被觀察到數據變化後,它會把這些改變Dom操做放到這個隊列中(圓圈中),而後執行,實現DOM更新。
    • 下面例子直觀的表達了vue是異步更新DOM的
      <div @click='fn' ref='str'>{{str}}</div>
      
      data(){
          return {
              str:35
          }
      }
      methods:{
          fn(){
              this.str = '你好'
              console.log(this.$refs[str].innerHTML)// 35 
          }
      }
      複製代碼
  • 爲了肯定在DOM更新完成以後再去作某些事情,就可使用Vue.$nextTick(callback),這樣回調函數會在DOM更新完成以後執行。

vue.$nextTick(callback)應用

  • 最經常使用的應用是在created鉤子函數中操做DOM,因爲created鉤子函數中,DOM尚未更新,因此須要用$nectTick操做DOM,不然就會報錯。
    created(){
        this.$nextTick(()=>{
            console.log(this.$refs[st].innerHTML = '小丑竟是你本身')
        })
    }
    複製代碼
  • 點擊事件須要這個DOM作一些操做時
    <div @click='fn' ref='str'>{{str}}</div>
        
        data(){
            return {
                str:35
            }
        }
        methods:{
            fn(){
                this.str = '你好'
                this.$nextTick(()=>{
                     console.log(this.$refs[str].innerHTML)// 你好 
                })
               
            }
        }
    複製代碼

proxy 和 defineProperty 的區別

proxy

proxy的優點

  • 直接監聽對象而非屬性
  • 直接監聽數組的變化
  • Proxy的攔截方式更多
  • Proxy返回的是一個新的對象,修改值的時候咱們能夠直接操做這個對象,而Object.defineProperty只能經過遍歷對象的屬性就行修改。
  • 直接實現對象的增長、刪除

Object.defineProperty的優點

  • 兼容性強

vue3.0.和2.0的區別

  • vue3.0重構響應式系統,用Proxy替換了Object.defineProperty,使用的優點如上
  • 新增了組合式API(Composition),更好的邏輯複用和組織代碼。固然一樣支持Options API(選項式API)
  • vue3.0的聲明週期也發生了改變
    • 取消了beforCreat和created聲明週期,用setup替換。
    • 全部的聲明週期都寫在setup中。
  • 自動按需引入
  • 重構了虛擬DOM的實現(跳過靜態節點,只處理動態節點),性能獲得了很大的提升。

MVVM的原理

image.png

  • 它的原理就是經過數據劫持(Observer)加發布訂閱模式,主要有observer監聽器,watcher訂閱者,Compile解析器。
  • 首先Observer數據劫持,利用Object.defineProperty給每個數據添加get和set屬性,Compile解析器,給屬性添加訂閱者和綁定更新函數,因爲訂閱者不少,因此就將他們放到Dep中在屬性變化後通知watcher訂閱者,將這些訂閱者放入Dep中統一管理,當數據發生變化時,通知訂閱者執行更新函數觸發視圖更新。

節流、防抖

節流

  • 規定的時間斷內函數只觸發一次,經過用於頁面滾動、發驗證碼。
    let flg = true
    function throttle(fn,delay=500){
        return (...args)=>{
            if(!flg) return 
            flg = false
            setTimeout(()=>{
                flg = truw
            },delay)
            fn.apply(this,args)
        }
    }
    複製代碼

防抖

  • 每次時間觸發後須要等待一段時間的執行,若這段時間內再次觸發,就會從新計時,觸發的時候只觸發最後一次。
let timer = null
function debounce(fn,delay=500){
    return (...args)=>{
         if(timer){
            clearTimeout(timer)
        }
        setTimeout(()=>{
            fn.aplly(this,args)
        },delay)
    }
   
}
複製代碼

Vue中自定義指令

  • 自定義指令有全局註冊和局部註冊兩種

全局自定義指令

  • html部分
    <div v-fous = 'fn'></div>
    複製代碼
  • js部分
    <script>
    Vue.diretive('fous'{
        inserted:function(el,fuc){
            console.log(el,fuc.value)
            //el dom元素; fuc.value返回的是fn函數體
        }
    })
    
    methods:{
        fn(){
            console.log(11111)
        }
    }
    </script>
    複製代碼

局部自定義指令

export default = {
        directiveds:{
            fous:{
                inserted:function(el,fuc){
                    console.log(el,fuc.value)
                }
            }
        }
    }
複製代碼

vue中data爲何必定是一個函數而不是一個對象

  • vue中的組件是能夠被屢次複用的,若是是一個對象,每一次複用都是複用的一個data,這樣就會相互影響,若是是一個函數,每一次複用組件都會生成一個新的data實例,互不影響。

FormData和普通對象有什麼區別

  • FormData通常用來處理表單數據,提交給後臺。
  • FormData數據的增刪改查和普通對象不同
    • FormData增長屬性formDate.append('屬性名','屬性值')
    • FormData獲取屬性值formdata.get('屬性名')
    • FormData修改屬性formData.set('屬性名','屬性值')
    • FormData判斷是否有該屬性formData.has('屬性名')
    • FormData刪除屬性formData.delete('屬性名')

vue多個頁面傳參

  • vuex 和 內存

異步函數都有哪些

  • 事件
  • 發佈訂閱
  • axjax
  • Promise
  • async await
  • 定時器

H5和C3的新增屬性

H5新增屬性

  • 語義化標籤 header、nav、aside、footer
  • 音頻video、音頻audio
  • 畫布canvas
  • 內存localStorage和sesstionStorage
  • 表單的控件,email、url、number、file...

C3新增特性

  • transform轉換vue

  • transition過分vue-router

  • border-radius圓角vuex

  • box-shadow 陰影npm

  • 僞類選擇器canvas

  • 僞元素選擇器後端

  • calc函數數組

  • animations瀏覽器

相關文章
相關標籤/搜索