前段時間刷掘金發現一篇很不錯的文章(清單),覺得挺有道理的。有些知識點以前看過後,過段時間後發現又忘了,然後又去查詢資料,反反覆覆 感覺知識點永遠不是自己的且學的又比較零散。所以按照 一名【合格】前端工程師的自檢清單去完善自己知識體系(根據自身情況稍作調整)。
這裡說明下大部分知識點詳解都是引用下面連結的,都是很不錯的文章,值得去研究,在此感謝各位作者大大了。 如果引用涉及作者版權之類,請私信我,會盡快刪掉的。
參考
知識體系
一、JavaScript 基礎
變數和型別:
-
JavaScript
規定了幾種語言型別?- 基本資料型別:
Number
,Undefined
,Boolean
,String
,Null
,Symbol
,BigInt
- 引用資料型別:
Object
- 基本資料型別和引用型別的區別?
- 基本資料型別:
-
JavaScript
物件的底層資料結構是什麼?:HashMap
-
Symbol
型別在實際開發中的應用、可手動實現一個簡單的Symbol
-
JavaScript
中的變數在記憶體中的具體儲存形式 -
基本型別對應的內建物件,以及他們之間的裝箱拆箱操作
-
理解值型別和引用型別
-
null
和undefined
的區別- undefined 表示根本不存在定義
- null 表示一個值被定義了,定義為“空值”;
-
至少可以說出三種判斷
JavaScript
資料型別的方式,以及他們的優缺點,如何準確的判斷陣列型別 ES6 有個Array.isArray
可以很好的判斷是否為陣列型別。 判斷 JS 資料型別的四種方法:-
typeof
:- 對於基本型別,除
null
以外,均可以返回正確的結果。 - 對於引用型別,除
function
以外,一律返回object
型別。 - 對於
null
,返回object
型別。 - 對於
function
返回function
型別。
- 對於基本型別,除
-
instanceof
:instanceof
只能用來判斷兩個物件是否屬於例項關係, 而不能判斷一個物件例項具體屬於哪種型別
-
constructor
:- null 和 undefined 是無效的物件,因此是不會有
constructor
存在的,這兩種型別的資料需要通過其他方式來判斷。 - 函式的
constructor
是不穩定的,這個主要體現在自定義物件上,當開發者重寫 prototype 後,原有的constructor
引用會丟失,constructor
會預設為Object
- null 和 undefined 是無效的物件,因此是不會有
-
toString
:-
toString()
是Object
的原型方法,呼叫該方法,預設返回當前物件的[[Class]]
。這是一個內部屬性,其格式為[object Xxx]
,其中 Xxx 就是物件的型別。 此方法也有缺點,不能精確的判斷自定義型別,對於自定義型別只會返回[object Object]
,不過可以用instanceof
代替判斷。function Person () {} const p = new Person(); Object.prototype.toString.call(p); // [object Object] p instanceof Person; // true 複製程式碼
-
-
-
可能發生隱式型別轉換的場景以及轉換原則,應如何避免或巧妙應用。
-
出現小數精度丟失的原因,JavaScript可以儲存的最大數字、最大安全數字,JavaScript處理大數字的方法、避免精度丟失的方法。
- JavaScript可以儲存最大的數字:
Number.MAX_VALUE
它的值可以通過Number.MAX_VALUE得到,在控制檯列印得到值:1.7976931348623157e+308。 - 最大安全數字:
Number.MAX_SAFE_INTEGER
: 9007199254740991
- JavaScript可以儲存最大的數字:
原型及原型鏈
-
理解原型設計模式以及
JavaScript
中的原型規則-
原型規則
- 所有的引用型別(陣列、物件、函式),都具有物件特性,即可自由擴充套件屬性;
var arr = [];arr.a = 1;
- 所有的引用型別(陣列、物件、函式),都有一個_proto_屬性(隱式原型),屬性值是一個普通的物件;
- 所有的函式,都具有一個
prototype
(顯式原型),屬性值也是一個普通物件; - 所有的引用型別(陣列、物件、函式),其隱式原型指向其建構函式的顯式原型;
(obj._proto_ === Object.prototype)
; - 當試圖得到一個物件的某個屬性時,如果這個物件本身沒有這個屬性,那麼會去它的
_proto_
(即它的建構函式的prototype
)中去尋找; - JS中的原型規則與原型鏈
- 所有的引用型別(陣列、物件、函式),都具有物件特性,即可自由擴充套件屬性;
-
-
instanceof
的底層實現原理,手動實現一個instanceof
-
實現繼承的幾種方式以及他們的優缺點
-
至少說出一種開源專案(如
Node
)中應用原型繼承的案例[暫時沒看過原始碼,看了之後再來回答] -
可以描述
new
一個物件的詳細過程,手動實現一個new
操作符 -
理解es6
class
構造以及繼承的底層實現原理es6 引入的
class
類實質上是JavaScript
基於原型繼承的語法糖。class Animal { constructor(name) { this.name = name; } sayHi() { return `Hello ${this.name}`; } } // es5 function Animal(name) { this.name = name; } Animal.prototype.sayHi = () => { return `Hello ${this.name}`; }; 複製程式碼
讓我們來看看通過
babel
轉換的Animal
類,是否跟上面es5類似呢?"use strict"; /** * 判斷left 是否是 right 的例項, 底層利用 instanceof, */ function _instanceof(left, right) { if ( right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance] ) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * 利用Object.defineProperty新增物件屬性 */ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } /** * 給建構函式or建構函式原型新增屬性or方法 */ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Animal = /*#__PURE__*/ (function() { // 建構函式 function Animal(name) { // 檢測 this(this 指向生成的例項)是否是建構函式Animal的例項 _classCallCheck(this, Animal); this.name = name; } // 向建構函式新增方法 _createClass(Animal, [ { key: "sayHi", value: function sayHi() { return "Hello ".concat(this.name); } } ]); return Animal; })(); 複製程式碼
從以上轉義後的程式碼來看,底層還是採用了原型的繼承方式。
作用域和閉包
-
理解詞法作用域和動態作用域
-
理解
JavaScript
的作用域和作用域鏈 -
理解
JavaScript
的執行上下文棧,可以應用堆疊資訊快速定位問題 -
this
的原理以及幾種不同使用場景的取值。this
是什麼?this
就是函式執行時所在的環境物件。 -
閉包的實現原理和作用,可以列舉幾個開發中閉包的實際應用
// 1. 經典閉包面試題 for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }) } for (var i = 0; i < 5; i++) { (function (j) { setTimeout(() => { console.log(j) }) }(i)) } // 2. 模組化方案 const module = (function() { var name = 'rudy'; var getName = function () { return name; } var changeName = function (newName) { name = newName; return name; } return { getName: getName, changeName: changeName } }()) // 私有變數 var privateNum = (function () { var num = 0; return function () { return num++; } }()) privateNum(); // 0 privateNum(); // 1 privateNum(); // 2 複製程式碼
必要應用場景實在是太多了,以上只列舉了部分場景。
-
理解堆疊溢位和記憶體洩漏的原理,如何防止
-
如何處理迴圈的非同步操作;
如果需要簡單的處理下for迴圈的非同步操作,就是讓每個迴圈體擁有自己的作用域,可以利用
es6
中的let
或者閉包來解決。// let for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); // do something }) } // 閉包 for (var i = 0; i <5; i++) { (function (j) { setTimeout(() => { console.log(j); // do something }) }(i)) } 複製程式碼
-
理解模組化解決的實際問題,可列舉幾個模組化方案並理解其中原理
執行機制
- 為何try裡面放return,finally還會執行,理解其內部機制
- JavaScript如何實現非同步程式設計,可以詳細描述EventLoop機制
- 巨集任務和微任務分別有哪些