目錄
- 前言
- 第一部分: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訪問對象屬性時報錯
- 01. 一網打盡this
前言
侯策寫的這本書,針對中高級前端開發的查漏補缺和麪試很有幫助,所以看過一遍之後將需要記錄的知識點總結一遍。
第一部分:JavaScript基礎強化
01. 一網打盡this
this規則
- 簡單調用函數,嚴格模式下爲undefined,非嚴格模式下爲window
- New方法構造函數時,指向新創建的對象上,如果返回的是一個對象,則指向返回的對象
- 使用call/apply/bind時,指向第一個參數指定的對象
- 通過上下文調用函數時,指向對應上下文對象上
- 箭頭函數時,對應箭頭函數外的作用域
- 如果上下文調用中有嵌套關係,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操作符的作用
- 定義一個對象
- 對象的
__proto__
屬性指向new構造函數的原型對選哪個 - 對象上定義一些屬性和方法
- 返回這個對象
定義實現一個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訪問對象屬性時報錯
- && 短路運算符
- || 設置保底默認值
- try-catch方法
- lodash get方法
- ?. 可選鏈操作符