讀《前端開發核心知識進階》短記(一) 目錄

目錄

  • 前言
  • 第一部分:JavaScript基礎強化
    • 01. 一網打盡this
      this規則 this優先級 call、bind、apply三者的區別 new操作符的作用 定義實現一個bind函數
    • 02. 閉包
      作用域 執行代碼的兩個階段 執行上下文 閉包 內存管理 內存泄露
    • 03. 實現API
      offset方法和getBoundClientRect方法暫時不寫 數組reduce方法實現 reduce方法實現runPromise reduce方法實現pipe 實現compose 實現apply函數
    • 04. JavaScript高頻考點及基礎題庫
      typeof instanceof Object.prototype.toString.call 判斷類型萬能方法 數據類型轉換 函數參數傳遞 因undefined訪問對象屬性時報錯

前言

侯策寫的這本書,針對中高級前端開發的查漏補缺和麪試很有幫助,所以看過一遍之後將需要記錄的知識點總結一遍。

第一部分:JavaScript基礎強化

01. 一網打盡this

this規則

  1. 簡單調用函數,嚴格模式下爲undefined,非嚴格模式下爲window
  2. New方法構造函數時,指向新創建的對象上,如果返回的是一個對象,則指向返回的對象
  3. 使用call/apply/bind時,指向第一個參數指定的對象
  4. 通過上下文調用函數時,指向對應上下文對象上
  5. 箭頭函數時,對應箭頭函數外的作用域
  6. 如果上下文調用中有嵌套關係,this會指向最後調用它的對象

this優先級

顯式綁定:call、apply、bind、new
隱式綁定:根據調用關係確定this指向的情況
優先級:
顯式綁定 > 隱式綁定
new > call、apply、bind
箭頭函數的this不可變
tips:const聲明的變量不會掛載到window全局對象上

call、bind、apply三者的區別

call和apply直接進行相關函數的調用,bind不會調用而是返回一個新函數,call和bind都需要參數單個傳,apply需要將參數轉爲數組。

new操作符的作用

  1. 定義一個對象
  2. 對象的__proto__屬性指向new構造函數的原型對選哪個
  3. 對象上定義一些屬性和方法
  4. 返回這個對象

定義實現一個bind函數

Function.prototype.bind = Function.prototype.bind || function(context) {
    const _this = this;
    // arguments爲類數組,用call調用數組的slice
    const args = Array.prototype.slice.call(arguments, 1);
    return function () {
        const finalArgs = args.concat(Array.prototype.slice.call(arguments));
        return _this.apply(context, finalArgs);
    }
}

02. 閉包

作用域

ES5:全局作用域,函數作用域
ES6:原有基礎上添加塊級作用域
變量作用域查找是根據作用域鏈,依次跳到上層,終點在全局。

暫時性死區(TDZ):

  • 在聲明(let,const)之前
  • 函數參數複製默認值之前(默認值爲undefined)

執行代碼的兩個階段

執行代碼分爲代碼預編譯階段代碼執行階段

  • 代碼預編譯階段:確定作用域,進行變量聲明
  • 代碼執行階段:創建執行上下文,執行上下文形成作用域鏈

執行上下文

執行上下文指的是當前代碼的執行環境/作用域
執行上下文包括:變量對象、作用域鏈、this

閉包

函數嵌套函數時,內層引用外層變量,且內層函數全局可訪問,形成閉包。(Closure 閉包變量)

閉包基本原理:
外界可以通過返回的函數獲取原函數內部的變量值。

內存管理

  • 生命週期:分配內存,讀寫內存,釋放內存
  • 棧空間由操作系統自動分配釋放(基本數據類型),堆空間由開發者分配釋放(引用類型)

tips:Javascript依賴瀏覽器的垃圾回收機制

內存泄露

空間不再使用卻沒有釋放的現象,會導致程序變慢或崩潰。
解決該問題就需要將該空間使用完手動置爲null

03. 實現API

offset方法和getBoundClientRect方法暫時不寫

數組reduce方法實現

Array.prototype._reduce = function(fn, initval) {
    const arr = this
    let base = typeof initval === 'undefined' ? arr[0] : initval
    let initIndex = typeof initval === 'undefined' ? 1 : 0
    arr.slice(initIndex).forEach((val, index) => {
        base = fn(base, val, initIndex + index, arr)
    })
    return base
}

reduce方法實現runPromise

const runPromisesInSeries = (promiseArr, value) => promiseArr.reduce((result, promiseFnc) => promiseFnc.then(result), Promise.then(value))

reduce方法實現pipe

const pipe = (...fns) => input => fns.reduce((result, val) => val(result), input)

實現compose

const compose = (...fns) => {
    const len = fns.length;
    return function(...args) {
        let index = 0;
        // 先運算出第一個結果,this指向調用的函數
        let result = len ? fns.reverse()[index].apply(this, args) : args[0];
        // 循環運算出其他的結果
        while(++index < len) {
            result = fns[index].call(this,result);
        }
        return result;
    }
}

實現apply函數

Function.prototype.apply = Function.prototype.apply || function(context, ...args) {
    // 判斷參數
    if (typeof args === 'undefined' || args === null) args = [];
    if (typeof context === 'undefined' || context === null) context = window;
    // 在context上定義一個屬性applyKey接收要執行的函數
    context.applyKey = this;
    // 利用上下文調用方式讓this指向context
    const result = context.applyKey(...args);
    // 將多餘的屬性刪除
    delete context.applyKey;
    // 返回運行結果
    return result;
}

04. JavaScript高頻考點及基礎題庫

typeof

只判斷基礎類型(除null以外),引用類型只有‘function’,‘object’
特殊:

typeof null => 'object'
typeof NaN => 'number'
typeof [] => 'object'

instanceof

a instanceof b,是判斷a是否可以在b的原型鏈中找到,所以基本數據類型直接返回false
原理:

function instanceFunc(L,R) {
    // 如果是原始類型直接返回false
    if(typeof L !=== 'object') return false;
    while(true) {
        // 如果原型鏈查找完成直接返回false
        if(L.__proto__ === null) return false;
        // 如果在原型鏈中找到了,返回true
        if(L.__proto__ === R.prototype) return true;
        // 在原型鏈繼續查找
        L = L.__proto__;
    }
}

Object.prototype.toString.call 判斷類型萬能方法

Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('An').slice(8, -1) => 'String'

數據類型轉換

JavaScript是弱類型的語言,或可說動態語言
"+":

  • string + any => string
  • number + undefined => NaN
  • number + number、boolean、null => number
  • NaN + number、boolean、NaN、undefined、null => NaN
  • Infinity + Infinity、number、boolean、null => Infinity
  • Infinity + (-Infinity)、number、boolean、null => -Infinity
  • Infinity + (-Infinity) => NaN
  • 引用類型:先調用valueOf或toString由規範所決定,先轉成基本數據類型再字符串拼接

(tips: 可以通過對對象的valueOf和toString方法重寫,改變 console.log(1+foo) 的結果,隱式轉換更傾向於調用valueOf

優先級:string > undefined(NaN) > number > boolean

函數參數傳遞

  • 函數爲基礎數據類型時,複製參數值,修改不會改變原值
  • 參數爲引用類型時:
    • 修改某值,原值跟着修改(引用同一地址)
    • 修改引用地址,修改值原值不會修改

因undefined訪問對象屬性時報錯

  1. && 短路運算符
  2. || 設置保底默認值
  3. try-catch方法
  4. lodash get方法
  5. ?. 可選鏈操作符
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章