我的自檢清單---知識體系之一 JavaScript基礎

Rudy24發表於2019-08-19

前段時間刷掘金發現一篇很不錯的文章(清單),覺得挺有道理的。有些知識點以前看過後,過段時間後發現又忘了,然後又去查詢資料,反反覆覆 感覺知識點永遠不是自己的且學的又比較零散。所以按照 一名【合格】前端工程師的自檢清單去完善自己知識體系(根據自身情況稍作調整)。

這裡說明下大部分知識點詳解都是引用下面連結的,都是很不錯的文章,值得去研究,在此感謝各位作者大大了。 如果引用涉及作者版權之類,請私信我,會盡快刪掉的。

參考

知識體系

一、JavaScript 基礎

變數和型別:

  1. JavaScript規定了幾種語言型別?

    • 基本資料型別:Number,Undefined,Boolean,String,Null,Symbol,BigInt
    • 引用資料型別:Object
    • 基本資料型別和引用型別的區別?
  2. JavaScript物件的底層資料結構是什麼?: HashMap

  3. Symbol型別在實際開發中的應用、可手動實現一個簡單的Symbol

  4. JavaScript中的變數在記憶體中的具體儲存形式

  5. 基本型別對應的內建物件,以及他們之間的裝箱拆箱操作

  6. 理解值型別和引用型別

  7. nullundefined的區別

    • undefined 表示根本不存在定義
    • null 表示一個值被定義了,定義為“空值”;
  8. 至少可以說出三種判斷JavaScript資料型別的方式,以及他們的優缺點,如何準確的判斷陣列型別 ES6 有個Array.isArray 可以很好的判斷是否為陣列型別。 判斷 JS 資料型別的四種方法:

    1. typeof:

      • 對於基本型別,除 null 以外,均可以返回正確的結果。
      • 對於引用型別,除 function 以外,一律返回 object 型別。
      • 對於 null ,返回 object 型別。
      • 對於 function 返回 function 型別。
    2. instanceof:

      • instanceof 只能用來判斷兩個物件是否屬於例項關係, 而不能判斷一個物件例項具體屬於哪種型別
    3. constructor:

      • null 和 undefined 是無效的物件,因此是不會有 constructor 存在的,這兩種型別的資料需要通過其他方式來判斷。
      • 函式的 constructor 是不穩定的,這個主要體現在自定義物件上,當開發者重寫 prototype 後,原有的 constructor 引用會丟失,constructor 會預設為 Object
    4. 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
        
        複製程式碼
  9. 可能發生隱式型別轉換的場景以及轉換原則,應如何避免或巧妙應用。

  10. 出現小數精度丟失的原因,JavaScript可以儲存的最大數字、最大安全數字,JavaScript處理大數字的方法、避免精度丟失的方法。

    • JavaScript可以儲存最大的數字:Number.MAX_VALUE 它的值可以通過Number.MAX_VALUE得到,在控制檯列印得到值:1.7976931348623157e+308。
    • 最大安全數字:Number.MAX_SAFE_INTEGER: 9007199254740991

原型及原型鏈

  1. 理解原型設計模式以及JavaScript中的原型規則

    • 原型規則

      • 所有的引用型別(陣列、物件、函式),都具有物件特性,即可自由擴充套件屬性; var arr = [];arr.a = 1;
      • 所有的引用型別(陣列、物件、函式),都有一個_proto_屬性(隱式原型),屬性值是一個普通的物件;
      • 所有的函式,都具有一個prototype(顯式原型),屬性值也是一個普通物件;
      • 所有的引用型別(陣列、物件、函式),其隱式原型指向其建構函式的顯式原型;(obj._proto_ === Object.prototype)
      • 當試圖得到一個物件的某個屬性時,如果這個物件本身沒有這個屬性,那麼會去它的_proto_(即它的建構函式的prototype)中去尋找;
      • JS中的原型規則與原型鏈
    • 深入理解JavaScript系列(42):設計模式之原型模式

  2. instanceof的底層實現原理,手動實現一個instanceof

  3. 實現繼承的幾種方式以及他們的優缺點

  4. 至少說出一種開源專案(如Node)中應用原型繼承的案例[暫時沒看過原始碼,看了之後再來回答]

  5. 可以描述new一個物件的詳細過程,手動實現一個new操作符

  6. 理解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;
    })();
    複製程式碼

    從以上轉義後的程式碼來看,底層還是採用了原型的繼承方式。

作用域和閉包

  1. 理解詞法作用域和動態作用域

  2. 理解JavaScript的作用域和作用域鏈

  3. 理解JavaScript的執行上下文棧,可以應用堆疊資訊快速定位問題

  4. this的原理以及幾種不同使用場景的取值。

    this是什麼?this就是函式執行時所在的環境物件。

  5. 閉包的實現原理和作用,可以列舉幾個開發中閉包的實際應用

    
    // 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
    
    複製程式碼

    必要應用場景實在是太多了,以上只列舉了部分場景。

  6. 理解堆疊溢位和記憶體洩漏的原理,如何防止

  7. 如何處理迴圈的非同步操作;

    如果需要簡單的處理下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))
    }
    
    複製程式碼
  8. 理解模組化解決的實際問題,可列舉幾個模組化方案並理解其中原理

執行機制

  1. 為何try裡面放return,finally還會執行,理解其內部機制
  2. JavaScript如何實現非同步程式設計,可以詳細描述EventLoop機制
  3. 巨集任務和微任務分別有哪些

相關文章