前端面試總結

一、CSS相關問題

1、 行內元素,塊級元素,空元素

  • 行內元素有:a b span select strong(強調的語氣)
  • 塊級元素有:div ul ol li dl dt dd h1 h2 h3 h4…p
  • 行內塊元素:img, input, textarea
  • 常見的空元素:
    <br> <hr> <img> <input> <link> <meta>
    鮮為人知的是:
    <area> <base> <col> <command> <embed> <keygen> <param> <source> <track> <wbr>

2、選擇器優先級

important(1,0,0,0) > 內聯 > id(0,1,0,0) > class(0,0,1,0) = 屬性 = 偽類( 0,0,1,0) >標簽(0,0,0,1) = 偽元素(0,0,0,1) > 通配符(* 0,0,0,0)

3、水平垂直居中

  • 定位 + transform
//父元素設置position: relative;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
  • 行內塊元素 + 標尺

1.給它的父元素寫text-align屬性;
2.要居中的元素將其類型轉為inline-block;
3.要居中的元素加vertical-align屬性;
4.添加一個“標尺”,既同級元素(span等),要居中的元素與其互相垂直居中
注意在編輯時標尺與需要居中的元素之間不能有空格回車;
標尺須加:

  display:inline-block;
  //目的是隱藏標尺
  width:0;
  //與父元素等高,中線位置既是居中位置
  height:100%;
  vertical-align:middle;
<style>
  *{
      margin: 0;
      padding: 0;
  }
  .div1{
      width: 200px;
      height: 150px;
      background: blue;
      margin: 20px 20px;
      text-align: center;
  }
  .div1-1{
      width: 100px;
      height: 100px;
      background: red;
      display: inline-block;
      vertical-align: middle;
  }
  .div1 span{
      display: inline-block;
      width: 0px;
      height: 100%;
      background: #0681D0;
      vertical-align: middle; 
  }
</style>
<div class="div1">div1
    <div class="div1-1">div2</div><span></span>
</div>

4、動畫問題

5、寫個左右布局,左邊固定寬度,右邊自適應

  • 左浮動 + 右不設寬(使用float需要注意清除浮動造成父元素塌陷的問題)
  • 左定位 + 右不設寬
  • flex布局

6、寫六點篩子布局

image.png
  • flex布局
<style>
h2{
    text-align: center;
}

.main{
    display: flex;
    flex-wrap: wrap;
    width: 680px;
    justify-content: space-between;
}

.container{
    display: flex;
    width: 320px;
    height: 320px;
    flex-wrap: wrap;
    justify-content: space-between;
    align-content:space-between;
}

.box{
    width: 90px;
    height: 90px;
    background-color: #EEEEEE;
    padding: 5px;
    border-radius: 5px;
    display: flex;
    flex-wrap: wrap;            
}

.row{
    display: flex;
    flex-basis: 100%;
}

.item{
    width: 24px;
    height: 24px;
    background-color: #000000;
    margin: 3px;
    border-radius: 50%;
}
    

/*排列方向*/
.flex-direction-column{
     flex-direction: column;
}

/*水平排列*/
.justify-content-center{
    justify-content: center;
}

.justify-content-flex-end{
    justify-content: flex-end;
}

.justify-content-space-between{
    justify-content: space-between;
}
    
/*垂直排列*/
 .align-items-center{
     align-items: center;
 }

 .align-items-flex-end{
     align-items: flex-end;
 }

 .align-items-space-between{
     align-items: space-between;
 }

/*多軸對齊*/
 .align-content-space-between{
    align-content: space-between;
 }

 /*項目排列*/
 .align-self-center{
    align-self: center;
 }

 .align-self-flex-end{
    align-self: flex-end;
 }
</style>
<div class="container">
    <div class="box justify-content-center align-items-center">
        <span class="item"></span>
    </div>
    
    <div class="box justify-content-space-between">
        <span class="item"></span>
        <span class="item align-self-flex-end"></span>
    </div>
    
    <div class="box">
            <span class="item"></span>
            <span class="item align-self-center"></span>
            <span class="item align-self-flex-end"></span>
    </div>
    
    <div class="box align-content-space-between">
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
        
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
    </div>

    <div class="box">
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
        
        <div class="row justify-content-center">
            <span class="item"></span>
        </div>

        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
    </div>

    <div class="box align-content-space-between flex-direction-column">
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
    </div>
</div>


二、JS

1、js基本類型,如何判別類型

數據類型分為基本類型和引用類型:

  • 基本類型:String、Number、Boolean、Null、Undefined、symbol(ES6)

  • 引用類型:Object、Array、Date、Function、Error、RegExp、Math、Number、String、Boolean、Globle。

  • js內置類型有七種:String、Number、Boolean、Null、Undefined、Symbol(ES6)、Object

判斷數據類型的幾種方式優缺點對比
不同類型的優缺點 typeof instanceof constructor object.prototype.toString.call()
優點 使用簡單 能檢測出引用類型 基本能檢測出所有類型(null和Undefined除外) 所有類型
缺點 基本類型(null不行) 基本類型不行,且不能跨iframe constructor易修改,且不能跨iframe IE6以下null和Undefined為Object

2、js數組的方法都看下

image.png

注意: 可參考https://www.cnblogs.com/sqh17/p/8529401.html

數組方法 作用 返回值 備注
arr.push() 從后面添加元素 添加完后的數組的長度
arr.pop() 從后面刪除元素 刪除的元素 只能刪除一個
arr.shift() 從前面刪除元素 刪除的元素 只能刪除一個
arr.unshift() 從前面添加元素 添加完后的數組的長度
arr.splice(i,n) 刪除從i(索引值)開始之后的那個元素 刪除的元素
arr.concat(i,n) 連接兩個數組 連接后的新數組
arr.split() 將字符串轉化為數組 數組
arr.sort() 將數組進行排序 排好的數組 默認是按照最左邊的數字進行排序(1,10,2)
arr.reverse() 將數組反轉 反轉后的數組
arr.slice(start,end) 切去索引值start到索引值end的數組,不包含end索引的值 切出來的數組
arr.forEach(callback) 遍歷數組,無return 會影響原來的數組
arr.map(callback) 映射數組(遍歷數組) 返回一個新數組 數組長度與原數組相同(不滿足同條件的為空)
arr.filter(callback) 過濾數組 返回一個新數組 實際滿足條件的數組
arr.every(callback) 依據判斷條件,數組的元素是否全滿足 ture/false 全滿足返回true
arr.some() 依據判斷條件,數組的元素是否全滿足 ture/false 若有一個滿足則返回ture
arr.find(callback) 找到第一個符合條件的數組成員
arr.reduce(callback, initialValue) 迭代數組的所有項,累加器,數組中的每個值(從左到右)合并,最終計算為一個值 返回一個值
arr.indexOf() 查找某個元素的索引值 若有重復的,則返回第一個查到的索引值若不存在,則返回 -1 從前向后查找
arr.lastIndexOf() 查找某個元素的索引值 若有重復的,則返回第一個查到的索引值若不存在,則返回 -1 從后往前查找
Array.from() 將偽數組變成數組 數組 就是只要有length的就可以轉成數組(ES6)
Array.of() 將一組值轉換成數組,類似于聲明數組
arr.copyWithin() 在當前數組內部,將制定位置的數組復制到其他位置 返回當前數組 會覆蓋原數組項
arr.findIndex(callback) 找到第一個符合條件的數組成員的索引值
arr.fill(target, start, end) 使用給定的值,填充一個數組 填充完后會改變原數組
arr.includes() 判斷數中是否包含給定的值 返回的是布爾值
arr.keys() 遍歷數組的鍵名
arr.values() 遍歷數組鍵值
arr.entries() 遍歷數組的鍵名和鍵值
    let a = [1,2,3,4];
    let b = [1,2,3,4];
    let c = [1,2,3,4];
    let d = [1,2,3,4];
    let e = [1,2,3,4];
    let newA = [];

    a.forEach(item => {
        if (item > 2){
            newA.push(item)
        }
    })
    console.log(newA, a);

    let newB = b.map(item => {
        if (item > 2){
            return item
        }
    })
    console.log(newB, b);

    let newC = c.filter(item => {
        if (item > 2){
            return item
        }
    })
    console.log(newC, c)

    let D= d.every(item => {
        return item > 2
    })
    console.log(D, d)

    let E = e.some(item => {
        return item > 2
    })
    console.log(E, e)
image.png

3、原型鏈 new的作用

3.1、原型鏈

每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。那么假如我們讓原型對象等于另一個類型的實例,結果會怎樣?顯然,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。假如另一個原型又是另一個類型的實例,那么上述關系依然成立。如此層層遞進,就構成了實例與原型的鏈條。這就是所謂的原型鏈的基本概念。——摘自《javascript高級程序設計》

image.png
3.2、new的作用

1.創建一個空對象 p
2.把這個空對象 p 的屬性 __proto__ 指向函數 Person 的 prototype
3.將構造函數 Person 的作用域賦給新對象 p,即 this 指向了 p
4.執行Person 中的代碼,為p添加屬性 name
5.返回新對象。

4、js有哪些作用域 閉包問題 寫防抖函數

4.1 作用域

1、定義:作用域是在運行時代碼中的某些特定部分中變量,函數和對象的可訪問性。換句話說,能夠訪問另一個函數作用域的變量的函數
2、全局作用域、函數作用域、塊級作用域(ES6)

4.2 閉包
4.2.1、定義

當內部函數被保存到外部時,會形成閉包;閉包會導致原始作用域鏈不釋放,造成內存泄漏(占用);

function a() {
    var i = '初始值';
    i = i + "—_執行a"
    // 此處的函數b訪問了父級函數a中的局部變量i,成為了一個閉包
    function b() {
        i = i + "_執行b"
        console.log(i)
    }
    return b;
}
var c = a(); // 此時 i 的值為 :初始值—_執行a
c()          // 此時 i 的值為 :初始值—_執行a_執行b
c()          // 此時 i 的值為 :初始值—_執行a_執行b_執行b

以上方代碼為例:

  • 將函數a賦值給全局變量c時,a會執行一次,局部變量 i 的值變為初始值—_執行a,最終返回函數b,此時全局變量c的值為閉包函數b的引用。
    此時函數a雖然已執行完,但因為內部包含閉包函數b,所以函數 a 的執行期上下文會繼續保留在內存中,不會被銷毀,所以局部變量 i 仍是初始值—_執行a

執行期上下文:當函數執行時,會創建一個執行期上下文的內部對象。每調用一次函數,就會創建一個新的上下文對象,他們之間是相互獨立的。當函數執行完畢,它所產生的執行期上下文會被銷毀

  • 1、第一次執行 c() 時,閉包函數b第一次執行,局部變量 i 的值變為初始值—_執行a_執行b
  • 2、第二次執行 c() 時,閉包函數b第二次執行,局部變量 i 的值變為初始值—_執行a_執行b_執行b
4.2.2、閉包的特點
  • 1.被閉包函數訪問的父級及以上的函數的局部變量(如范例中的局部變量 i )會一直存在于內存中,不會被JS的垃圾回收機制回收。
  • 2.閉包函數實現了對其他函數內部變量的訪問。(函數內部的變量對外是無法訪問的,閉包通過這種變通的方法,實現了訪問。)
4.2.3、Javascript的垃圾回收機制
  • 如果一個對象不再被引用,那么這個對象就會被GC回收。
  • 如果兩個對象互相引用,而不再被第三者所引用,那么這兩個對象都會被回收。
    eg:
function person(name) {
    function say(content) {
        console.log(name + ':' + content)
    }
    return say
}

a = person("張三")
b = person("李四")
a("在干啥?")
b("沒干啥。")
a("出去玩嗎?")
b("去哪啊?")
4.2.4、優缺點
  • 優點:
    可以減少全局變量的定義,避免全局變量的污染
    能夠讀取函數內部的變量
    在內存中維護一個變量,可以用做緩存

  • 缺點:
    1)造成內存泄露
    閉包會使函數中的變量一直保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。(解決方法——使用完變量后,手動將它賦值為null;)
    2)閉包可能在父函數外部,改變父函數內部變量的值。
    3)造成性能損失
    由于閉包涉及跨作用域的訪問,所以會導致性能損失。
    (解決方法——通過把跨作用域變量存儲在局部變量中,然后直接訪問局部變量,來減輕對執行速度的影響)

4.3、函數防抖(debounce)

當持續觸發事件時,一定時間段內沒有再觸發事件,事件處理函數才會執行一次,如果設定的時間到來之前,又一次觸發了事件,就重新開始延時。

實際場景:
連續的事件,只需觸發一次的回調場景有:
1、搜索框搜索輸入。
2、只需要用戶最后一次輸入完再發送請求 手機號、郵箱格式的輸入驗證檢測
3、窗口大小的resize 。只需窗口調整完成后,計算窗口的大小,防止重復渲染

function debounce(fn, wait) {    
    var timeout = null;    
    return function() {        
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 處理函數
function handle() {    
    console.log(Math.random()); 
}
// 滾動事件
window.addEventListener('scroll', debounce(handle, 1000));
//當持續觸發scroll事件時,事件處理函數handle只在停止滾動1000毫秒之后才會調用一次,也就是說在持續觸發scroll事件的過程中,事件處理函數handle一直沒有執行。
4.4、 函數節流(throttle)

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

間隔一段時間執行一次回調的場景有:
1、滾動加載,加載更多或滾動到底部監聽;
2、谷歌搜索框,搜索聯想功能;
3、高頻點擊提交,表單重復提交
4、省市信息對應字母快速選擇

//節流 時間戳的方式實現
var throttle = function(func, delay) {            
  var prev = Date.now();            
  return function() {                
    var context = this;                
    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));


// 節流throttle代碼(定時器):
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));

5、promise的使用 原理 所擁有的方法

1、Promise 的含義
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise對象。

2、基本用法
ES6 規定,Promise對象是一個構造函數,用來生成Promise實例。
Promise構造函數接受一個函數作為參數,該函數的兩個參數分別是resolve(成功)和reject(失敗)。它們是兩個函數,將異步操作的結果,作為參數傳遞出去

3、所擁有的方法
Promise.prototype.catch() catch方法是.then(null, rejection)的別名,用于指定發生錯誤時的回調函數
Promise.prototype.finally() finally方法用于指定不管 Promise 對象最后狀態如何,都會執行的操作
Promise.all() all方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例(所有的都成功了才執行)
Promise.race()race方法同樣是將多個 Promise 實例,包裝成一個新的 Promise 實例
Promise.resolve()將現有對象轉為 Promise 對象,Promise.resolve方法就起到這個作用
Promise.reject()將現有對象轉為 Promise 對象,Promise.reject方法就起到這個作用(參數作為reject的理由)
Promise.try()為所有操作提供了統一的處理機制,可以更好地管理異常
詳情見http://www.lxweimin.com/p/d8a901dd72ac

6、es6有哪些特性 箭頭函數和普通函數區別

1、箭頭函數
1.1 更簡潔的語法
1.2 沒有this
1.3 不能使用new 構造函數
1.4 不綁定arguments,用rest參數...解決
1.5 使用call()和apply()調用
1.6 捕獲其所在上下文的 this 值,作為自己的 this 值
1.7 箭頭函數沒有原型屬性
1.8 不能簡單返回對象字面量
1.9 箭頭函數不能當做Generator函數,不能使用yield關鍵字
1.10 箭頭函數不能換行

//1、沒有形參的時候
let fun = () => console.log('我是箭頭函數'); 
fun();
//2、只有一個形參的時候()可以省略
let fun2 = a => console.log(a); 
fun2('aaa');

//3、倆個及倆個以上的形參的時候
let fun3 = (x,y) =>console.log(x,y);  //函數體只包含一個表達式則省略return 默認返回
fun3(24,44);

//4、倆個形參以及函數體多條語句表達式
let fun4 = (x,y) => {
  console.log(x,y);
  return x+y; //必須加return才有返回值
}
//5、如果要返回對象時需要用小括號包起來,因為大括號被占用解釋為代碼塊了,正確寫法
let fun5 = ()=>({ foo: x })   //如果x => { foo: x }  //則語法出錯

7、函數柯里化 純函數

自己百度吧, 看不懂。
http://www.lxweimin.com/p/2975c25e4d71

8、數據不可變 immutable原理

自己百度吧, 看不懂。
https://segmentfault.com/a/1190000016404944

9、js bind函數的性能問題(https://blog.csdn.net/ywl570717586/article/details/74231402)

10、js怎么定義一個不可改值的對象

Javascipt的數據屬性有一個名為Writable的特征, 可以用于設置屬性值是否可以被修改(Object.defineProperty方法接收三個參數:需要添加或修改屬性的對象,屬性名稱,屬性描述options(writable:false))

11、const 定義常量可以改變嗎

const所說的常量,是指,對應的指針或者說地址是常量
const定義的基本數據類型的變量不可以修改,但其它復雜數據類型是可以修改的
用const定義的數組,里面的元素是可變的

如何定義不可改變的數組:
Object.preventExtendsion(obj) 用來禁止對象可擴展其它屬性(阻止對象新增屬性,但可改變)
Object.seal(obj)用來禁止對象刪除其它屬性和擴展其它屬性(阻止對象刪除屬性,但可改變)
Object.freeze(obj)用來凍結對象,就是所有的屬性不能夠更改和新增(阻止對象更改和新增屬性)

詳情見:https://blog.csdn.net/weixin_33697898/article/details/91371632

12、深拷貝/淺拷貝

  • 1、基本類型--名值存儲在棧內存中,例如let a=1;
  • 2、引用數據類型--名存在棧內存中,值存在于堆內存中,但是棧內存會提供一個引用的地址指向堆內存中的值

三、瀏覽器

1、cookie安全

指某些網站為了辨別用戶身份、進行session跟蹤而存儲在用戶本地終端上的數據(通常經過加密)

生命周期:
創建cookie的時候,會給cookie指定一個值:Expire,它就是指定cookie的有效期,也就是cookie的生命周期,超出設置的這個生命周期,cookie就會被清除。如果給這個值Expire設置為0或者負值,那么這樣的設置就是在關閉瀏覽器時,就會清除cookie,這種方式更加安全。

如何解決cookie安全性問題
第一步:設置cookie有效期不要過長,合適即可
第二步:設置HttpOnly屬性為true(可以防止js腳本讀取cookie信息,有效的防止XSS攻擊)。
第三步:設置復雜的cookie,加密cookie(盡可能使得加密后的cookie更難解密,也是保護了cookie中的信息)
(1)cookie的key使用uuid,隨機生成;
(2)cookie的value可以使用復雜組合,比如:用戶名+當前時間+cookie有效時間+隨機數。
第四步:用戶第一次登錄時,保存ip+cookie加密后的token(每次請求,都去將當前cookie和ip組合起來加密后的token與保存的token作對比,只有完全對應才能驗證成功)
第五步:session和cookie同時使用(sessionId雖然放在cookie中,但是相對的session更安全,可以將相對重要的信息存入session)
第六步:如果網站支持https,盡可能使用https(為cookie設置Secure屬性為true,它的意思是,cookie只能使用https協議發送給服務器,而https比http更加安全)

2、宏任務 微任務

setTimeout(() => {
  //宏任務,放到Event Queue(宏任務隊列)中
  console.log('1')
});

new  Promise((resolve) => {
  //主線程,直接執行
  console.log('2');
  resolve();
}).then(() => {
  //微任務 放到Event Queue(微任務隊列)中
  console.log('3')
});
//主線程,直接執行
 console.log('4');

執行結果: 2,4,3,1
解釋如下:
先看執行的代碼是同步任務還是異步任務,同步的主線程直接執行,異步任務放到任務隊列中。

image.png

任務隊列中,先執行一個宏任務,若有微任務,執行所有的微任務之后,再做新的宏任務。

image.png

image.png

https://www.cnblogs.com/wangziye/p/9566454.html

3、頁面加載過程

  • 1、輸入的網址在通過DNS解析后得到服務器地址瀏覽器向服務器發起http請求,經過TCP/IP三次握手確認鏈接后,服務器將需要的代碼發回給瀏覽器。
  • 2、瀏覽器接收到代碼后進行解析,經過三大步驟:DOM構造、布局以及繪制頁面
  • 2.1、DOM構造
    瀏覽器首先將收到的html代碼,通過html解析器解析構建為一顆DOM樹。數據結構中有許多的樹,而DOM樹就像是一顆倒長著的大樹,這樣的對象模型決定了節點之間都有一定的關聯它們關系可能有父子、有兄弟,我們可以順著這顆樹做出許多操作。
    接著將接收到的css代碼,通過css解析器構建出樣式表規則將這些規則分別放到對應的DOM樹節點上,得到一顆帶有樣式屬性的DOM樹。
  • 2.2、布局
    瀏覽器按從上到下,從左到右的順序,讀取DOM樹的文檔節點,順序存放到一條虛擬的傳送帶上。傳送帶上的盒子就是節點,而這條流動的傳送帶就是文檔流。如果我們讀取到的節點是屬于另一個節點下的子節點,那么在放入傳送帶的時候,就應該按順序放到該節點盒子的內部。如果子節點下還有子節點,在傳送帶上的時候就繼續套到子一級的盒子內部。根據它在DOM樹上的結構,可以嵌套的層級沒有限制的哦。文檔流排完之后,開始獲取計算節點的坐標和大小等CSS屬性,作為盒子的包裝說明。然后把盒子在倉庫里一一擺放,這就將節點布局到了頁面。
  • 2.3、繪制頁面
    布局完成之后,我們在頁面上其實是看不到任何內容的瀏覽器只是計算出了每一個節點對象應該被放到頁面的哪個位置上,但并沒有可視化。因此最后一步就是將所有內容繪制出來,完成整個頁面的渲染。
    https://www.zhihu.com/question/30218438

4、https ssl加密如何實現

5、跨域如何解決

  • 1、 通過jsonp跨域(jsonp缺點:只能實現get一種請求)
  • 2、 document.domain + iframe跨域(此方案僅限主域相同,子域不同的跨域應用場景。)
  • 3、 location.hash + iframe
  • 4、 window.name + iframe跨域(window.name屬性的獨特之處:name值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值2MB)

總結:通過iframe的src屬性由外域轉向本地域,跨域數據即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。

  • 5、 postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是為數不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:
a.) 頁面和其打開的新窗口的數據傳遞
b.) 多窗口之間消息傳遞
c.) 頁面與嵌套的iframe消息傳遞
d.) 上面三個場景的跨域數據傳遞
用法
postMessage(data,origin)方法接受兩個參數
data: html5規范支持任意基本類型或可復制的對象,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化。
origin: 協議+主機+端口號,也可以設置為"*",表示可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/"

  • 6、 跨域資源共享(CORS)

  • 7、 nginx代理跨域

  • 8、 nodejs中間件代理跨域


    image.png
  • 9、 WebSocket協議跨域

https://segmentfault.com/a/1190000011145364

四、框架

4.1、react

1、react生命周期,原理,虛擬dom理解,diff算法原理

2、react版本都更新了什么,最新版本去掉什么生命周期加入什么生命周期,為什么

3、組件渲染優化

4、如何理解高階組件

5、redux理念是什么 單數據流如何改變的

6、webpack有哪些配置屬性 原理 插件如何實現

7、bable的配置屬于有哪些 瀏覽器兼容性

8、AST語法樹

9、小程序父子組件通訊,wepy父子組件通訊

10、react創建組件的方法(React.createClass React.Component 函數定義無狀態組件)

11、react無狀態組件和pureComponent區別

12、react什么時候setstate是同步的(一步操作中調用)

13、react組件間怎么通訊---react原生方法(都是事件機制啊實在找不到)

14、react父組件拿子組件ref(this.refs.xxx.refs.textinput

15、react將組件渲染到指定dom節點(https://blog.csdn.net/neoveee/article/details/57399834

16、webpack插件有哪些(extract-text-webpack-plugin單獨打包css),怎么多個入口,怎么打包成內聯樣式??? ,不打包某個文件??

17、React如何實現vue中的插件模式???

react沒有實際開發經驗,等有經驗了再整理吧

4.2、vue

9、vue的雙向數據流如何實現

vue數據雙向綁定是通過數據劫持結合發布者-訂閱者模式的方式來實現的

Object.defineProperty()這個方法重新定義了對象獲取屬性值(get)和設置屬性值(set)的操作來實現的。


var obj = { };
var name;
//第一個參數:定義屬性的對象。
//第二個參數:要定義或修改的屬性的名稱。
//第三個參數:將被定義或修改的屬性描述符。
Object.defineProperty(obj, "data",  {
//獲取值get: 
function () { return name; },
//設置值set: 
function (val) {
    name = val;
    console.log(val)}
})
//賦值調用
setobj.data = 'aaa';
//取值調用
getconsole.log(obj.data);
// 代碼演示:defineProperty的雙向綁定
var obj = {};
Object.defineProperty(obj, 'val', {
    set: function (newVal) {
        document.getElementById("a").value = newVal == undefined ? '' : newVal;
        document.getElementById("b").innerHTML = newVal == undefined ? '' : newVal;
    }
});
document.getElementById("a").addEventListener("keyup", function (e) {
    obj.val = e.target.value;
})

computed 計算屬性與method方法的區別

computed中的計算屬性可以寫在method中,區別就是method調用要加()而computed不用

computed中必須要加return

computed里面的方法不是通過事件去觸發的,而是當屬性(必須是data中的屬性)發生改變的時候那么當前函數就會被觸發

最大的區別是,computed中有緩存,相同的值會直接拿已經緩存的,提高性能,但是method沒有緩存,一樣的值還是會重新獲取

1、Vue循環為什么要加key

key屬性可以用來提升v-for渲染的效率,vue中使用v-for渲染數據的時候,并不會去改變原有的元素和數據,而是創建新的元素,再把新的數據渲染進去。

2、Vue循環為什么不用index作為key

index 作為 key,和沒寫基本上沒區別,因為不管你數組的順序怎么顛倒,index 都是 0, 1, 2 這樣排列,導致 Vue 虛擬DOM的復用會映射到錯誤的舊子節點,做很多額外的工作,影響效率。

vue原理 數據劫持 路由守衛怎么用 axios怎么寫請求攔截 響應攔截

10vuex如何數據綁定的

11vue有哪些框架優缺點

五、Reactnative

1有哪些坑,怎么解決

2熱更新問題

3性能問題,比如列表

4首屏白屏怎么解決

5自己封裝過什么組件

6js和原生通訊方法有哪些 jsbridge原理

Node

1用來做什么

2用過哪些框架

3express如何解決異步問題

4node從哪個版本開始有Async和Await

5node數據流如何理解

6如何理解中間價

7node如何確保穩定性,進程死了如何自動修復

六、網絡

1tcp三次握手

2分析請求頭

算法

1隨機一個數組,數組每個值區間2-32

2最長回文字段

開放性問題

1flutter有使用過嗎,你感覺如何

2全局有console的地方全部換成彈框顯示

3如何優化pc和app

4項目如何發布部署,如何本地開發,git使用等

函數式編程

函數式編程(縮寫為 FP)是一種通過組合純函數來構建軟件的過程,避免狀態共享、可變數據及副作用的產生。

1、函數式編程定義

image.png

2、函數式編程的特點

    1. 函數是"第一等公民"
      把它想象成一個數據類型,可以聲明、賦值給其他變量、當參數傳給函數等等
    1. 只用"表達式",不用"語句"
      "表達式"(expression):是一個單純的運算過程,總是有返回值;
      "語句"(statement):是執行某種操作,沒有返回值。
      函數式編程要求,只使用表達式,不使用語句。也就是說,每一步都是單純的運算,而且都有返回值。
    1. 沒有"副作用"
      所謂"副作用",指的是函數內部與外部互動(最典型的情況,就是修改全局變量的值),產生運算以外的其他結果。
      函數式編程強調沒有"副作用",意味著函數要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。
    1. 不修改狀態
      函數式編程只是返回新的值,不修改系統變量。因此,不修改變量,也是它的一個重要特點。
    1. 引用透明
      引用透明(Referential transparency),指的是函數的運行不依賴于外部變量或"狀態",只依賴于輸入的參數,任何時候只要參數相同,引用函數所得到的返回值總是相同的。
      方法傳入的參數類型與返回值類型是一樣的(類比map,same方法,傳入一個數組同時返回的也是一個數組)
      來自:http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

undenfine 和null 有什么區別 做if判斷會怎樣

http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html

image.png

vue數據劫持

  • 針對 Object 類型,采用 Object.defineProperty() 方法劫持屬性的讀取和設置方法;
  • 針對 Array 類型,采用原型相關的知識劫持常用的函數,從而知曉當前數組發生變化。
    注意: Object.defineProperty() 方法存在以下缺陷:
    每次只能設置一個具體的屬性,導致需要遍歷對象來設置屬性,同時也導致了無法探測新增屬性;
    屬性描述符 configurable 對其的影響是致命的。而 ES6 中的 Proxy 可以完美的解決這些問題

raw-loader:加載文件原始內容(utf-8)
file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件 (處理圖片和字體)
url-loader:與 file-loader 類似,區別是用戶可以設置一個閾值,大于閾值會交給 file-loader 處理,小于閾值時返回文件 base64 形式編碼 (處理圖片和字體)
source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
svg-inline-loader:將壓縮后的 SVG 內容注入代碼中
image-loader:加載并且壓縮圖片文件
json-loader 加載 JSON 文件(默認包含)
handlebars-loader: 將 Handlebars 模版編譯成函數并返回
babel-loader:把 ES6 轉換成 ES5
ts-loader: 將 TypeScript 轉換成 JavaScript
awesome-typescript-loader:將 TypeScript 轉換成 JavaScript,性能優于 ts-loader
sass-loader:將SCSS/SASS代碼轉換成CSS
css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS
postcss-loader:擴展 CSS 語法,使用下一代 CSS,可以配合 autoprefixer 插件自動補齊 CSS3 前綴
eslint-loader:通過 ESLint 檢查 JavaScript 代碼
tslint-loader:通過 TSLint檢查 TypeScript 代碼
mocha-loader:加載 Mocha 測試用例的代碼
coverjs-loader:計算測試的覆蓋率
vue-loader:加載 Vue.js 單文件組件
i18n-loader: 國際化
cache-loader: 可以在一些性能開銷較大的 Loader 之前添加,目的是將結果緩存到磁盤里
有哪些常見的Plugin?你用過哪些Plugin?
define-plugin:定義環境變量 (Webpack4 之后指定 mode 會自動配置)
ignore-plugin:忽略部分文件
html-webpack-plugin:簡化 HTML 文件創建 (依賴于 html-loader)
web-webpack-plugin:可方便地為單頁應用輸出 HTML,比 html-webpack-plugin 好用
uglifyjs-webpack-plugin:不支持 ES6 壓縮 (Webpack4 以前)
terser-webpack-plugin: 支持壓縮 ES6 (Webpack4)
webpack-parallel-uglify-plugin: 多進程執行代碼壓縮,提升構建速度
mini-css-extract-plugin: 分離樣式文件,CSS 提取為獨立文件,支持按需加載 (替代extract-text-webpack-plugin)
serviceworker-webpack-plugin:為網頁應用增加離線緩存功能
clean-webpack-plugin: 目錄清理
ModuleConcatenationPlugin: 開啟 Scope Hoisting
speed-measure-webpack-plugin: 可以看到每個 Loader 和 Plugin 執行耗時 (整個打包耗時、每個 Plugin 和 Loader 耗時)
webpack-bundle-analyzer: 可視化 Webpack 輸出文件的體積 (業務組件、依賴第三方模塊)
Loader和Plugin的區別?
Loader 本質就是一個函數,在該函數中對接收到的內容進行轉換,返回轉換后的結果。 因為 Webpack 只認識 JavaScript,所以 Loader 就成了翻譯官,對其他類型的資源進行轉譯的預處理工作。
Plugin 就是插件,基于事件流框架 Tapable,插件可以擴展 Webpack 的功能,在 Webpack 運行的生命周期中會廣播出許多事件,Plugin 可以監聽這些事件,在合適的時機通過 Webpack 提供的 API 改變輸出結果。
Loader 在 module.rules 中配置,作為模塊的解析規則,類型為數組。每一項都是一個 Object,內部包含了 test(類型文件)、loader、options (參數)等屬性。
Plugin 在 plugins 中單獨配置,類型為數組,每一項是一個 Plugin 的實例,參數都通過構造函數傳入。

const HtmlWebpackPlugin = require('html-webpack-plugin');
// 有時我們會指定打包文件中帶有 hash,那么每次生成的 js 文件名會有所不同,不能讓我們每次都人工去修改 html,
// 我們可以使用 html-webpack-plugin 插件來幫助我們完成這些事情。
// 有時候,我們的腳手架不僅僅給自己使用,也許還提供給其它業務使用,html 文件的可配置性可能很重要,比如:你公司有專門的部門提供M頁的公共頭部/公共尾部,埋點jssdk以及分享的jssdk等等,但是不是每個業務都需要這些內容。
// 一個功能可能對應多個 js 或者是 css 文件,如果每次都是業務自行修改 public/index.html 文件,也挺麻煩的。首先他們得搞清楚每個功能需要引入的文件,然后才能對 index.html 進行修改。
// 此時我們可以增加一個配置文件,業務通過設置 true 或 false 來選出自己需要的功能,我們再根據配置文件的內容,為每個業務生成相應的 html 文件,豈不是美美的。

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    // 每次 clean-webpack-plugin 都會幫我們先清空一波 dist 目錄的插件
const CopyWebpackPlugin = require('copy-webpack-plugin');
    // 靜態資源拷貝插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 抽離CSS,即將CSS文件單獨打包的插件,這可能是因為打包成一個JS文件太大,影響加載速度,也有可能是為了緩存
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');
// 使用 mini-css-extract-plugin,CSS 文件默認不會被壓縮,如果想要壓縮,需要配置 optimization插件

// import() 語法,
// 按需加載
// 需要 @babel/plugin-syntax-dynamic-import 的插件支持,
// 但是因為當前 @babel/preset-env 預設中已經包含了 @babel/plugin-syntax-dynamic-import,因此我們不需要再單獨安裝和配置。

const webpack = require('webpack');
const path = require('path');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];

module.exports = {
    mode: isDev ? 'development' : 'production',
    // mode 配置項,告知 webpack 使用相應模式的內置優化。
    // mode 配置項,支持以下兩個配置:
    // development:將 process.env.NODE_ENV 的值設置為 development,啟用 NamedChunksPlugin 和 NamedModulesPlugin
    // production:將 process.env.NODE_ENV 的值設置為 production,啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin
    
    
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // entry 的值可以是一個字符串,一個數組或是一個對象。
    // 字符串的情況無需多說,就是以對應的文件為入口。
    // 為數組時,表示有“多個主入口”,想要多個依賴文件一起注入時
    
    
    output: {
        path: path.resolve(__dirname, 'dist'), //必須是絕對路徑
        filename: 'bundle.[hash:6].js',
        publicPath: '/' //通常是CDN地址
    },
    // 例如,你最終編譯出來的代碼部署在 CDN 上,資源的地址為: 'https://AAA/BBB/YourProject/XXX',那么可以將生產的 publicPath 配置為: //AAA/BBB/。
// 編譯時,可以不配置,或者配置為 /。可以在我們之前提及的 config.js 中指定 publicPath(config.js 中區分了 dev 和 public), 當然還可以區分不同的環境指定配置文件來設置,或者是根據 isDev 字段來設置。
    

    module: {
        // loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript),用于對源代碼進行轉換
        rules: [
            {
                test: /\.jsx?$/, //匹配規則,針對符合規則的文件進行處理。
                use: {
                    loader: 'babel-loader', 
                    options: {      //這里,我們可以在 .babelrc 中編寫 babel 的配置,也可以在 webpack.config.js 中進行配置。
                        presets: ["@babel/preset-env"],
                        plugins: [
                            [
                                "@babel/plugin-transform-runtime",
                                {
                                    "corejs": 3
                                }
                            ]
                        ]
                    }
                },
                exclude: /node_modules/ //排除 node_modules 目錄
            },
            // 講js轉譯為低版本
            {
                test: /.html$/,
                use: 'html-withimg-loader'
            },
            // 處理在html中引入的本地圖片
            
            // use 字段有幾種寫法
            // 可以是一個字符串,例如上面的 use: 'html-withimg-loader'
            // use 字段可以是一個數組,例如處理CSS文件時,use: ['style-loader', 'css-loader']
            // use 數組的每一項既可以是字符串也可以是一個對象,當我們需要在webpack 的配置文件中對 loader 進行配置,就需要將其編寫為一個對象,
            // 并且在此對象的 options 字段中進行配置。
            // loader 的執行順序是從右向左執行的,也就是后面的 loader 先執行,下面 loader 的執行順序為: less-loader ---> postcss-loader ---> css-loader ---> style-loader
            // 當然,loader 其實還有一個參數,可以修改優先級,enforce 參數,其值可以為: pre(優先執行) 或 post (滯后執行)。
            {
                test: /\.(le|c)ss$/,
                use: [
                    // 'style-loader', 
                    MiniCssExtractPlugin.loader, //替換之前的 style-loader
                    'css-loader', {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')()
                            ]
                        }
                    }
                }, 'less-loader'],
                exclude: /node_modules/
            },
             // style-loader 動態創建 style 標簽,將 css 插入到 head 中.
             // css-loader 負責處理 @import 等語句。
             // postcss-loader 和 autoprefixer,自動生成瀏覽器兼容性前綴 
             // less-loader 負責處理編譯 .less 文件,將其轉為 css
            {
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240, //10K
                            esModule: false,
                            outpath:'assets'
                        }
                    }
                ],
                exclude: /node_modules/
            },
            // 我們可以使用 url-loader 或者 file-loader 來處理本地的資源文件。
            // url-loader 和 file-loader 的功能類似,
            // 但是 url-loader 可以指定在文件大小小于指定的限制時,返回 DataURL,
            // 因此,個人會優先選擇使用 url-loader
            // 當本地資源較多時,我們有時會希望它們能打包在一個文件夾下,這也很簡單,我們只需要在 url-loader 的 options 中指定 outpath,如: outputPath: 'assets'
            // 此處設置 limit 的值大小為 10240,即資源大小小于 10K 時,將資源轉換為 base64,超過 10K,將圖片拷貝到 dist 目錄。
            // esModule 設置為 false,否則,<img src={require('XXX.jpg')} /> 會出現 <img src=[Module Object] />
            // 將資源轉換為 base64 可以減少網絡請求次數,但是 base64 數據較大,如果太多的資源是 base64,會導致加載變慢,
            // 因此設置 limit 值時,需要二者兼顧。

           
        ]
    },
    devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map',
    // devtool 中的一些設置,可以幫助我們將編譯后的代碼映射回原始源代碼。不同的值會明顯影響到構建和重新構建的速度。
    // 能夠定位到源碼的行即可,因此,綜合構建速度,在開發模式下,設置 devtool 的值是 cheap-module-eval-source-map。
    // 生產環境可以使用 none 或者是 source-map,使用 source-map 最終會單獨打包出一個 .map 文件,我們可以根據報錯信息和此 map 文件,進行錯誤解析,定位到源代碼。
    // source-map 和 hidden-source-map 都會打包生成單獨的 .map 文件,區別在于,source-map 會在打包出的js文件中增加一個引用注釋,以便開發工具知道在哪里可以找到它。hidden-source-map 則不會在打包的js中增加引用注釋。
    // 但是我們一般不會直接將 .map 文件部署到CDN,因為會直接映射到源碼,更希望將.map 文件傳到錯誤解析系統,然后根據上報的錯誤信息,直接解析到出錯的源碼位置。


    plugins: [
        //數組 放著所有的webpack插件
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', //打包后的文件名
            config: config.template,  //讀取config配置文件生成不同的文件
            // hash: true //是否加上hash,默認是 false
            chunks: ['index'] //配置此參數僅會將數組中指定的js引入到html文件中,此外,如果你需要引入多個JS文件,僅有少數不想引入,還可以指定 excludeChunks 參數,它接受一個數組。
        }),
        new HtmlWebpackPlugin({
            template: './public/login.html',
            filename: 'login.html', //打包后的文件名
            chunks: ['login']
        }),
        // 多頁面應用打包
        // 如果需要配置多個 HtmlWebpackPlugin,
        // 那么 filename 字段不可缺省,否則默認生成的都是 index.html,
        // 如果你希望 html 的文件名中也帶有 hash,那么直接修改 fliename 字段即可,例如: filename: 'login.[hash:6].html'。

        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns:['**/*', '!dll', '!dll/**'] //不刪除dll目錄下的文件
        }),
        new CopyWebpackPlugin({
            patterns: [
                { 
                    from: 'public/js/*.js',   //將 public/js 目錄拷貝至 dist/js 目錄
                    to: path.resolve(__dirname, 'dist', 'js'),
                    flatten: true, //設置為 true,那么它只會拷貝文件,而不會把文件夾路徑都拷貝上,
                    // ignore: ['other.js'] 忽略掉 js 目錄下的 other.js 文件
                }
            ],
        }),
        new MiniCssExtractPlugin({
            filename: 'css/[name].css'
            //個人習慣將css文件放在單獨目錄下
            //publicPath:'../'   //如果你的output的publicPath配置的是 './' 這種相對路徑,那么如果將css文件放在單獨目錄下,記得在這里指定一下publicPath 
        }),
        new OptimizeCssPlugin(),    //壓縮css插件
        
        new webpack.HotModuleReplacementPlugin(), //熱更新插件

        new webpack.DefinePlugin({              //定義環境變量插件      \
            DEV: JSON.stringify('dev'), //字符串
            //index.js
               // if(DEV === 'dev') {
                //     //開發環境
                // }else {
                //     //生產環境
                // }
            FLAG: 'true' //FLAG 是個布爾類型
        })
     
    ],

    devServer: {
        // port: '8888', //默認是8080
        // quiet: false, //默認不啟用
        // inline: true, //默認開啟 inline 模式,如果設置為false,開啟 iframe 模式
        // stats: "errors-only", //終端僅打印 error
        // overlay: false, //默認不啟用
        // clientLogLevel: "silent", //日志等級
        // compress: true //是否啟用 gzip 壓縮
        hot:true //熱更新
    },
    // 啟用 quiet 后,除了初始啟動信息之外的任何內容都不會被打印到控制臺。這也意味著來自 webpack 的錯誤或警告在控制臺不可見 ,不建議開啟
    // stats: "errors-only" ,終端中僅打印出 error,注意當啟用了 quiet 或者是 noInfo 時,此屬性不起作用。
    // 啟用 overlay 后,當編譯出錯時,會在瀏覽器窗口全屏輸出錯誤,默認是關閉的。
    resolve: {
        modules: ['./src/components', 'node_modules'], //從左到右依次查找
        // resolve 配置 webpack 如何尋找模塊所對應的文件。
        // webpack 內置 JavaScript 模塊化語法解析功能,默認會采用模塊化標準里約定好的規則去尋找,但你可以根據自己的需要修改默認的規則。
        extensions: ['web.js', '.js'] //當然,你還可以配置 .json, .css        
// extensions適配多端的項目中,可能會出現 .web.js, .wx.js,例如在轉web的項目中,我們希望首先找 .web.js,如果沒有,再找 .js。我們可以這樣配置
    }
}

// 區分不同的環境
// 目前為止我們 webpack 的配置,都定義在了 webpack.config.js 中,對于需要區分是開發環境還是生產環境的情況,
// 我們根據 process.env.NODE_ENV 去進行了區分配置,但是配置文件中如果有多處需要區分環境的配置,這種顯然不是一個好辦法。
// 更好的做法是創建多個配置文件,如: webpack.base.js、webpack.dev.js、webpack.prod.js。
// 然后修改我們的 package.json,指定對應的 config 文件

// webpack.base.js 定義公共的配置
// webpack.dev.js:定義開發環境的配置
// webpack.prod.js:定義生產環境的配置

// webpack-merge 專為 webpack 設計,提供了一個 merge 函數,用于連接數組,合并對象。
// const merge = require('webpack-merge');
// merge({
//     devtool: 'cheap-module-eval-source-map',
//     module: {
//         rules: [
//             {a: 1}
//         ]
//     },
//     plugins: [1,2,3]
// }, {
//     devtool: 'none',
//     mode: "production",
//     module: {
//         rules: [
//             {a: 2},
//             {b: 1}
//         ]
//     },
//     plugins: [4,5,6],
// });
// //合并后的結果為
// {
//     devtool: 'none',
//     mode: "production",
//     module: {
//         rules: [
//             {a: 1},
//             {a: 2},
//             {b: 1}
//         ]
//     },
//     plugins: [1,2,3,4,5,6]
// }

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容