知識點記錄

昭光發表於2019-02-24

一、如何正確判斷一個資料的基本型別?

1、typeof  

typeof 對於原始型別(null undefined string number boolean symbol),除了null  都能顯示正確的型別

typeof null === 'object'
複製程式碼

typeof 對於物件來說,除了函式外其他都是object 型別

typeof [] === 'object'  
typeof console.log === 'function'
複製程式碼

所以typeof 無法正確區分物件和null(陣列和null)

2、instanceof 判斷已知物件型別的方法

MDN 的解釋: instanceof 運算子用來測試一個物件在其原型鏈中是否存在一個建構函式的 prototype 屬性

判斷一個物件是否是資料型別的例項

因而可以衍生出 用constructor 來判斷型別({}).constructor == Object,但是constructor 是可以修改的

function Fn(){};
Fn.prototype=new Array();
var f=new Fn()
console.log(f.constructor===Fn);    // false複製程式碼

,因而不準確。

3、通用型,借用Object.prototype.toString.call 來實現

var gettype=Object.prototype.toString 
    gettype.call('aaaa')        輸出      [object String]    
    gettype.call(2222)         輸出      [object Number]    
    gettype.call(true)          輸出      [object Boolean]     
    gettype.call(undefined)  輸出      [object Undefined]      
複製程式碼

// 進行一層封裝
let Type = (function(){
    let type = {};
    let typeArr = ['String', 'Object', 'Number', 'Array', 'Undefined', 'Null', 'Symbol'];
    for(let i = 0; i < typeArr.length; i++){
        type['Is'+ typeArr[i]] = function(obj){
            return Object.prototype.toString.call(obj) === '[object '+ typeArr[i] +']'
        }
    }
    return type
})()

複製程式碼

eg:(第一個字母小寫,第二個字母大寫)
Type.IsFunction(function() {})      Type.IsObject({}) 這樣使用。複製程式碼

二、物件的深淺拷貝

什麼是淺拷貝?如何實現淺拷貝?什麼是深拷貝?如何實現深拷貝?

淺拷貝

利用Object.assign({}, obj)  or 展開運算子 ... 來實現淺拷貝

let a = {
    age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(a.age) // 1
console.log(b.age) // 2複製程式碼

let a = {
    age: 1
}
let b = { ...a }
a.age = 2複製程式碼

 深拷貝

利用JSON.parse(JSON.stringify(object)) 來解決,(基本夠用了)但這個有侷限性,

  • 會忽略undefined
  • 會忽略symbol
  • 不能序列化函式
  • 不能解決迴圈引用的物件

自個封裝 lodash 深拷貝函式

function deepClone(obj){
    function isObject(o){
        return (typeof o === 'object' || typeof o === 'function') && o !== null
    }
    if(!isObject(obj)){
        throw new Error('not object')
    }
    let isArray = Array.isArray(obj)
    let newObj = isArray? [...obj] : { ...obj }
    Reflect.ownKeys(newObj).forEach((key)=>{
        newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
    })
    return newObj
}
// eg 
let obj = {
    a: [1,2,3],
    b:{
        c:2,
        d:3
    }
}
let newObj = deepClone(obj)
newObj.b.c = 33
console.log(obj.b.c)  // 2複製程式碼

三、call、apply 和 組合繼承

function Product(name, price){
    this.name = name;
    this.price = price;
}
function Food(name, price){
    Product.call(this, name, price)
    this.category = 'food'
}
let foot1 = new Food('chees', 5);
foot1 // 複製程式碼

通過Food 構造方法裡的call(),成功使Food 擴充套件了name 以及price .(借用)

知識點記錄

apply()call() 都是為了改變某個函式執行時的上下文而存在的(就是為了改變函式內部的 this 指向)。然後,因為這兩個方法會立即呼叫,所以為了彌補它們的缺失,還有個方法 bind()

/*apply()方法 引數是已陣列的形式 add.apply(sub, [4,2]) */
function.apply(thisObj[, argArray])

/*call()方法  引數*/
function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);複製程式碼

四、寄生組合繼承(經典例子):

function Parent(value){
    this.val = value
}
Parent.prototype.getValue = function(){
    console.log(this.val)
}
function Child(value){
    Parent.call(this, name)
}
// Child.prototype = new Parent()  組合繼承
// 缺點就是在繼承父類函式的時候呼叫了父類建構函式,導致子類的原型上多了不需要的父類屬性,存在記憶體上的浪費
Child.prototype = Object.assign(Parent.prototype, {
    constructor:{
        value: Child,
        enumerable: false,
        writable: true,
        configurable: true
    }
})
const child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
複製程式碼

繼承實現的核心就是將父類的原型賦值給了子類,並且將建構函式設定為子類,這樣既解決了無用的父類屬性問題,還能正確的找到子類的建構函式。

es6 class 繼承

class Parent{
    constructor(value){
        this.val = value
    }
    getValue(){
        console.log(this.val)
    }
}
class Child extends Parent{
    constructor(value){
        super(value)
        this.val = value
    }
}

let child = new Child(1)
child.getValue()  // 1
child instanceof Parent  //true複製程式碼

js 原型與原型鏈可以參考這個: https://juejin.im/post/5c72a1766fb9a049ea3993e6

五、防抖與節流

防抖即延時執行,指觸發事件後在規定時間內回撥函式只能執行一次,如果在規定時間內又觸發該事件,則會重新開始算規定時間。

應用場景: 輸入聯想功能,使用者不斷輸入時,用防抖來節約資源。

function callFn(content){
    console.log('這是防抖回撥函式')
}
// 利用回撥函式 儲存定時器標識
function debounce(func ,delay = 500){
    let timer = null
    return function(args){
        let that = this
        let _args = args
        if(timer) clearTimeout(timer)
        timer = setTimeout(function(){
            func.call(that, _args)
        }, delay)
    }
}
let currDebounce = debounce(callFn, 500) // 返回延時函式

// 使用
let evtFn= document.querySelector('body')
evtFn.addEventListener('click', function(e){
    currDebounce (e.target.value)
})複製程式碼

節流

當持續觸發事件時,在規定時間段內只能呼叫一次,如再規定時間內又觸發該事件,則return ,什麼也不做。

應用場景,頻繁觸發事件,如滾動、resize 等。

// 定時器版
function throttle(func, delay = 500){
    let timer = null;
    return function(args){
        let that = this;
        let _args = args;
        if(!timer){
            timer = setTimeout(function(){
                timer = null;
                func.apply(that, _args)
            }, delay)
        }
    }
}

// 時間戳版
function throttle(fun, delay = 500){
    let previous = 0;
    return function(args){
        let now = Date.now();
        let that = this;
        let _args = args;
        if(now - previous > delay){ // 如果時間差大於規定時間,則觸發
            fun.apply(that, _args)
            previous = now
        }
    }
}複製程式碼

垃圾回收主要分為:標記清除演算法(主流都是這個)與引用計數演算法。

將cookie設定成HttpOnly是為了防止XSS攻擊,竊取cookie內容,這樣就增加了cookie的安全性。
把cookie設定為secure,只保證 cookie 與伺服器之間的資料傳輸過程加密複製程式碼

六、渲染機制及重繪和迴流

瀏覽器的渲染機制一般分為以下幾個步驟:

    1. 處理 HTML 並構建 DOM 樹。
    2. 處理 CSS 構建 CSSOM 樹。
    3. 將 DOM 與 CSSOM 合併成一個渲染樹(Render Tree)。
    4. 根據渲染樹來佈局,計算每個節點的位置。
    5. 呼叫 GPU 繪製,合成圖層,顯示在螢幕上。
  • 重繪是 當節點需要更改外觀而不會影響佈局的,比如改變 color、background-color、visibility, outline等就叫稱為重繪
  • 迴流是 佈局或者幾何屬性需要改變 就稱為迴流。迴流是影響瀏覽器效能的關鍵因素,因為其變化涉及到部分頁面(或是整個頁面)的佈局更新。

迴流必定會發生重繪,重繪不一定會引發迴流

瀏覽器優化:

現代瀏覽器大多都是通過佇列機制來批量更新佈局,瀏覽器會把修改操作放在佇列中,至少一個瀏覽器重新整理(即16.6ms)才會清空佇列,但當你獲取佈局資訊的時候,佇列中可能有會影響這些屬性或方法返回值的操作,即使沒有,瀏覽器也會強制清空佇列,觸發迴流與重繪來確保返回正確的值

主要包括以下屬性或方法:

  • offsetTopoffsetLeftoffsetWidthoffsetHeight
  • scrollTopscrollLeftscrollWidthscrollHeight
  • clientTopclientLeftclientWidthclientHeight
  • widthheight
  • getComputedStyle()
  • getBoundingClientRect()

所以,我們應該避免頻繁的使用上述的屬性,他們都會強制渲染重新整理佇列。

減少重繪與迴流

1、CSS

  • 使用 transform 替代 top
  • 使用 visibility 替換 display: none ,因為前者只會引起重繪,後者會引發迴流
  • 避免使用table佈局,可能很小的一個小改動會造成整個 table 的重新佈局。
  • 儘可能在DOM樹的最末端改變class,迴流是不可避免的,但可以減少其影響。儘可能在DOM樹的最末端改變class,可以限制了迴流的範圍,使其影響儘可能少的節點。
  • 避免設定多層內聯樣式,CSS 選擇符從右往左匹配查詢,避免節點層級過多。
  • CSS3 硬體加速(GPU加速),使用css3硬體加速,可以讓transformopacityfilters這些動畫不會引起迴流重繪 。但是對於動畫的其它屬性,比如background-color這些,還是會引起迴流重繪的,不過它還是可以提升這些動畫的效能。
2、JavaScript

  • 避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class並一次性更改class屬性。

  • 避免頻繁操作DOM,建立一個documentFragment,在它上面應用所有DOM操作,最後再把它新增到文件中。

  • 避免頻繁讀取會引發迴流/重繪的屬性,如果確實需要多次使用,就用一個變數快取起來。

<script type="text/javascript">
    var pNode,fragment = document.createDocumentFragment();
        
    for(var i=0; i<20; i++){
        pNode = document.createElement('p');
        pNode.innerHTML = i;
        fragment.appendChild(pNode);
    }
    document.body.appendChild(fragment);
    
</script>複製程式碼

documentFragment 節點不屬於文件樹,因此當把建立的節點新增到該物件時,並不會導致頁面的迴流。

重繪和迴流

七、前端安全性XSS 攻擊與CSRF攻擊

Cross-Site Scripting (跨站指令碼攻擊)簡稱XSS,是一種程式碼注入攻擊。攻擊者通過在目標網站上注入惡意指令碼,使之在使用者的瀏覽器上執行,進而實現攻擊。

XSS 常見的注入方法:

  • 在 HTML 中內嵌的文字中,惡意內容以 script 標籤形成注入。
  • 在內聯的 JavaScript 中,拼接的資料突破了原本的限制(字串,變數,方法名等)。
  • 在標籤屬性中,惡意內容包含引號,從而突破屬性值的限制,注入其他屬性或者標籤。
  • 在標籤的 href、src 等屬性中,包含 javascript: (偽協議)等可執行程式碼。
  • 在 onload、onerror、onclick 等事件中,注入不受控制程式碼。
  • 在 style 屬性和標籤中,包含類似 background-image:url("javascript:..."); 的程式碼(新版本瀏覽器已經可以防範)。
  • 在 style 屬性和標籤中,包含類似 expression(...) 的 CSS 表示式程式碼(新版本瀏覽器已經可以防範)。


常用防範方法:

對輸入(和url引數)進行過濾,對輸出進行編碼,cookie 設定成 http-only

使用者輸入、url引數、post 請求引數、ajax

  • httpOnly(服務端設定): 在 cookie 中設定 HttpOnly 屬性後,js指令碼將無法讀取到 cookie 資訊。
  • 輸入過濾: 一般是用於對於輸入格式的檢查,例如:郵箱,電話號碼,使用者名稱,密碼……等,按照規定的格式輸入。不僅僅是前端負責,後端也要做相同的過濾檢查。因為攻擊者完全可以繞過正常的輸入流程,直接利用相關介面向伺服器傳送設定。
  • 轉義 HTML: 如果拼接 HTML 是必要的,就需要對於引號,尖括號,斜槓進行轉義。
function escape(str) {
  str = str.replace(/&/g, '&amp;')
  str = str.replace(/</g, '&lt;')
  str = str.replace(/>/g, '&gt;')
  str = str.replace(/"/g, '&quto;')
  str = str.replace(/'/g, '&#39;')
  str = str.replace(/`/g, '&#96;')
  str = str.replace(/\//g, '&#x2F;')
  return str
}複製程式碼
  • 白名單: 對於顯示富文字來說,不能通過上面的辦法來轉義所有字元,因為這樣會把需要的格式也過濾掉。這種情況通常採用白名單過濾的辦法,當然也可以通過黑名單過濾,但是考慮到需要過濾的標籤和標籤屬性實在太多,更加推薦使用白名單的方式。

跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF

1、驗證碼;強制使用者必須與應用進行互動,才能完成最終請求。此種方式能很好的遏制 csrf,但是使用者體驗比較差。

2、Referer check;請求來源限制,此種方法成本最低,但是並不能保證 100% 有效,因為伺服器並不是什麼時候都能取到 Referer,而且低版本的瀏覽器存在偽造 Referer 的風險。

XSS攻擊與CSRF攻擊

八、Object.assign 模擬實現

if( typeof Object.assign2 !== 'function' ){
    Object.defineProperty(Object, 'assign2', {
        value: function(target){
            if(!target){
                throw new Error('cannot convert undefined or null to object')
            }
            var to = Object(target)
            for(var index = 1; index < arguments.length;index++){
                var nextSource = arguments[index]
                if(nextSource){
                    for( var nextKey in nextSource ){
                        if(Object.prototype.hasOwnProperty.call(nextSource, nextKey)){
                            to[nextKey] = nextSource[nextKey]
                        }
                    }
                }
            }
            return to;
        },
        writable: true,
        configurable: true
    })
}複製程式碼


// 測試用例
let a = {
    name: "advanced",
    age: 18
}
let b = {
    name: "muyiy",
    book: {
        title: "You Don't Know JS",
        price: "45"
    }
}
let c = Object.assign2(a, b);
console.log(c);
// {
//     name: "muyiy",
//  age: 18,
//     book: {title: "You Don't Know JS", price: "45"}
// } 
console.log(a === c);
// true複製程式碼

九、vue 記錄

一般來說,vue 元件分成三類:

1、 由vue-router 產生的每個頁面,它本質上也是一個元件(.vue),主要承載當前頁面的html 結構,會包含資料獲取、資料整理、資料展示等業務操作,在實際專案開發中,我們寫的大部分程式碼都是這類元件,在協同開發時,每人維護自己的路由頁面,很少有交集。這類相對也是最好寫的,能完成需求就行。

2、 不包含業務,是個獨立、具體的功能基礎元件,比如模態框、日期選擇器。獨立元件的開發難度要高於第一類元件,它側重點是API的設計、相容性、效能、以及複雜的功能,也會包含非常多的技巧,比如在不依賴vuex 的情況下,各元件間的通訊。一個具有資料校驗功能的輸入框。

3、 業務元件,在業務中被多個頁面複用,會包含頁面元素,通用性要差一些,(依託於專案,可以使用專案中的技術棧,如vuex、axios等)。通用彈層

一個再複雜的元件,都是由三部分組成:prop、event、slot 。 Props 最好用物件的寫法,這樣可以針對每個屬性設定型別、預設值或自定義校驗屬性值。


十、JavaScript模組化方案

在es6之前,js 並沒有原生的模組。模組化方案的三個階段過程:

1、全域性變數+名稱空間 (window.XX ,以及自執行函式等操作)

2、AMD&commonjs 各類規範帶到前端

AMD模組類似:

define(function(require){
    const bar = require('./bar')
    return function(){}
})複製程式碼

commonJs 規範,它本不適合瀏覽器環境,但依賴現代打包工具進行轉換之後就可以在瀏覽器中執行。commonjs 規範格式更加簡潔,(nodejs 模組正在使用的就是commonjs 規範)

const bar = require('./bar')
module.exports = function(){
// ....
}複製程式碼

3、es6模組

模組化方案

import bar from './bar'
export default function(){
 // ...
}複製程式碼

十一、webpack 與gulp 有什麼本質區別

gulp 是工具鏈,構建工具,可以配合各種外掛做js 壓縮,css 壓縮,less 壓縮,替代手工實現自動化工作。 1、 構建工具 2、自動化、3、提高效率

webpack 是檔案打包工具,把專案的各種js ,css 打包合併成一個或多個檔案,主要用於模組化打包。1、打包工具 2、模組化識別 3、編譯模組程式碼 4、程式碼拆分5、模組熱更新。

十二、常用es6 以及es6 規範

到時候移到掘金

https://blog.csdn.net/u010427666/article/details/54944986

十三、seo 相關知識以及如何優化

文件&文章連結

十四、內部原型繼承原理

需重新整理

https://blog.csdn.net/u010427666/article/details/53244698

十五、你需要知道的css

css 動畫、flex 佈局等

https://juejin.im/post/5c7646e2f265da2d8e70f681

十五、效能優化點

程式碼層面、網路層面、打包依賴等

https://segmentfault.com/a/1190000008273435

十六、瀏覽器快取機制(強快取&協商快取)

知識點記錄

是否過期根據header中的Cache-Control和Expires來判斷,(快取過期後Etag 與last-modify 是由伺服器來判斷)

nginx 開啟強快取

location ~ ^/static/.*(jpg|jpeg|png|gif|ico|js|css|ttf)$ {
   root /home/service/www/web;
   expires 12h;
   add_header Cache-Control "public";
}

複製程式碼

 nginx 開啟gizp 壓縮(壓縮效率特高)

    gzip on; #開啟gzip壓縮輸出
    gzip_min_length 1k;    #最小壓縮檔案大小
    gzip_buffers 4 16k;    #壓縮緩衝區
    # gzip_http_version 1.0;    #壓縮版本(預設1.1,前端如果是squid2.5請使用1.0)
    gzip_comp_level 3;    #壓縮等級
    gzip_types text/plain application/javascript  application/x-javascript text/css application/xml;
    gzip_vary on;
    gzip_disable "MSIE [1-7]\.";
複製程式碼

 十七、陣列亂序

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.sort(function () {
    return Math.random() - 0.5;
});
複製程式碼

洗牌演算法:

function shuffle (arr) {    var len = arr.length    for (var i = 0;i < len - 1;i++) {        var idx = Math.floor(Math.random() * (len - i))        var temp = arr[idx]        arr[idx] = arr[len - i - 1]        arr[len - i - 1] = temp    }    return arr}複製程式碼

十八、BFC(塊級格式化上下文)

產生BFC:

  1. 根元素或包含根元素的元素
  2. 浮動元素 float = left | right 或 inherit(≠ none)
  3. 絕對定位元素 position = absolute 或 fixed
  4. display = inline-block | flex | inline-flex | table-cell 或 table-caption
  5. overflow = hidden | auto 或 scroll (≠ visible)

BFC 作用:

1、 清除浮動,即在容器中建立BFC 

2、導致外邊距摺疊塌陷

我們必須記住的是外邊距摺疊(Margin collapsing)只會發生在屬於同一BFC的塊級元素之間。如果它們屬於不同的 BFC,它們之間的外邊距則不會摺疊。所以通過建立一個不同的 BFC ,就可以避免外邊距摺疊。

https://segmentfault.com/a/1190000013647777


十九、單執行緒的JavaScript引擎是怎麼配合瀏覽器核心處理這些定時器和響應瀏覽器事件的呢?

1、單執行緒,多程式

知識點記錄

https://www.cnblogs.com/joyco773/p/6038022.html

http://www.xuanfengge.com/js-realizes-precise-countdown.html


二十、websocket 實時推送

相關連結: https://juejin.im/post/5c20e5766fb9a049b13e387b


二十一、http2.0的新特性有哪些?(選項是多路複用、頭部壓縮、設定優先順序、服務端推送、二進位制傳輸)

相關連結: https://juejin.im/post/5c8f30606fb9a070ef60996d


別人優質彙總:

https://juejin.im/post/5c64d15d6fb9a049d37f9c20 

相關文章