1. 程式人生 > 實用技巧 >【重學前端】JS基礎-變數和型別

【重學前端】JS基礎-變數和型別

變數和型別

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

    1.Undefined
    2.Null(js中的資料在底層是以二進位制儲存,如果前三位為0,那麼就會判定為object,而null的所有都為0)
    3.Boolean
    4.String
    5.Number
    6.Symbol(ECMAScript 6 新定義,例項是唯一且不可改變的)
    7.Object
    
  • 2.JavaScript物件的底層資料結構是什麼

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

    • 應用場景1:使用Symbol來作為物件屬性名(key)

      const PROP_NAME = Symbol();
      const PROP_AGE = Symbol();
      
      let obj = {
      	[PROP_NAME]: "一斤程式碼"
      }
      obj[PROP_AGE] = 18;
      
      console.log(obj[PROP_NAME]); // '一斤程式碼'
      console.log(obj[PROP_AGE]); // 18
      

      【注意】Symbol型別的key是不能通過Object.keys()或者for...in來列舉的,利用該特性,我們可以把一些不需要對外操作和訪問的屬性使用Symbol來定義。實現當使用JSON.stringify()將物件轉換成JSON字串的時候,Symbol屬性也會被排除在輸出內容之外。

      獲取以Symbol方式定義的物件屬性
      // 使用Object的API
      Object.getOwnPropertySymbols(obj); // [Symbol(name)]
      
      // 使用新增的反射API
      Reflect.ownKeys(obj); // [Symbol(name), 'age', 'title']
      
    • 應用場景2:使用Symbol來替代常量

      //由於定義const變數的時候需要立即賦值,這樣定義,直接就保證了三個常量的值是唯一的了
      const TYPE_AUDIO = Symbol();
      const TYPE_VIDEO = Symbol();
      const TYPE_IMAGE = Symbol();
      
    • 應用場景3:使用Symbol定義類的私有屬性/方法

      利用Symbol的唯一性以及模組化機制,實現類的私有屬性和方法。

      //a.js
      const PASSWORD = Symbol()
      
      class Login {
        constructor(username, password) {
          this.username = username
          this[PASSWORD] = password
        }
      
        checkPassword(pwd) {
            return this[PASSWORD] === pwd
        }
      }
      export default Login
      
      //b.js
      import Login from './a'
      
      const login = new Login('admin', '123456')
      login.checkPassword('123456')  // true
      login.PASSWORD  // oh!no!
      login[PASSWORD] // oh!no!
      login["PASSWORD"] // oh!no!
      
  • 4.JavaScript中的變數在記憶體中的具體儲存形式

    JavaScript中的變數分為基本型別和引用型別

    • 基本型別是儲存在棧記憶體中的簡單資料段,它們的值都有固定的大小,儲存在棧空間,通過按值訪問

    • 引用型別是儲存在堆記憶體中的物件,值大小不固定,棧記憶體中存放的該物件的訪問地址指向堆記憶體中的物件,JavaScript不允許直接訪問堆記憶體中的位置,因此操作物件時,實際操作物件的引用。

    • //例子:
      let a1 = 0; // 棧記憶體
      let a2 = "this is string" // 棧記憶體
      let a3 = null; // 棧記憶體
      let b = { x: 10 }; // 變數b存在於棧中,{ x: 10 }作為物件存在於堆中
      let c = [1, 2, 3]; // 變數c存在於棧中,[1, 2, 3]作為物件存在於堆中
      

    複製行為

    • 在棧記憶體中的資料發生複製行為時,系統會自動為新的變數分配一個新值,最後這些變數都是相互獨立互不影響的
    • 引用型別的複製,為新的變數分配相同的地址指標,儲存在棧記憶體中,該地址指標在堆記憶體中訪問到的具體物件實際上是同一個,因此一改變數值,雙方都改。

    生存期

    • 當一個方法執行時,會建立自己的棧記憶體,在方法內定義的變數都會放入這塊棧記憶體裡,方法執行結束後,這個記憶體棧也將自然銷燬。
    • 堆記憶體中的物件不會隨方法的結束而銷燬,即使方法結束後,這個物件還可能被另一個引用變數所引用(方法的引數傳遞時很常見)。只有當一個物件沒有任何引用變數引用它時,系統的垃圾回收機制才會在核實的時候回收它。
  • 5.基本型別對應的內建物件,以及他們之間的裝箱拆箱操作

    • 內建物件

      • 資料封裝類物件:Object、Array、Boolean、Number 、String

      • 其他物件:Function、Math、Date、RegExp、Error

        • Error6種錯誤型別(前4個較常見)

           1.SyntaxError: 語法錯誤
           2.ReferenceError: 引用錯誤 要用的東西沒找到
           3.RangeError: 範圍錯誤  專指引數超範圍
           4.TypeError: 型別錯誤  錯誤的呼叫了物件的方法
           5.EvalError: eval()方法錯誤的使用
           6.URIError: url地址錯誤
          
    • 特殊的基本包裝型別(Boolean、Number 、String)

      • 包裝型別:專門封裝原始型別的資料,並提供對資料常用操作的內建物件方法。

      • 生存期:只要用原始型別的資料呼叫方法或者訪問屬性時,js引擎都會自動建立對應的包裝型別物件方法呼叫完,包裝型別物件會自動釋放。

      • 無法直接給基本型別新增屬性和方法,但可以在基本包裝型別物件的原型下面新增,因為每個物件都有原型。

      • 裝箱(把基本資料型別轉化為對應的引用資料型別的操作)

        • 隱式裝箱

          let a = 'sun';
          let b = a.indexof('s');
          // 上面程式碼在後臺實際的步驟為:
          let a = new String('sun')
          let b = a.indexof('s')
          a = null
          
        • 顯式裝箱

          let a = new String('sun	');
          let b = a.indexof('s')
          
      • 拆箱(把引用型別轉化為對應基本資料型別的操作)

        let name = new String('sun')
        let age = new Number(24)
        console.log(typeof name) // object
        console.log(typeof age) //  object
        // 拆箱操作(通常通過引用型別的valueof()和toString()方法實現)
        console.log(typeof age.valueOf()); // number // 24  基本的數字型別
        console.log(typeof name.valueOf()); // string  // 'sun' 基本的字元型別
        console.log(typeof age.toString()); // string  // '24' 基本的字元型別
        console.log(typeof name.toString()); // string  // 'sun' 基本的字元型別
        
  • 6.理解值型別和引用型別

    • 值型別,即基本型別

      • string、number、boolean、undefined、null、symbol

      • 1、佔用空間固定,儲存在棧中
        2、儲存與複製的是值本身
        3、使用typeof檢測資料的型別
        4、基本型別資料是值型別
        
    • 引用型別

      • Object、Array、Function

      • 1、佔用空間不固定,儲存在堆中
        2、儲存與複製的是指向物件的一個指標
        3、使用instanceof檢測資料型別
        4、使用new()方法構造出的物件是引用型
        
  • 7.null和undefined的區別

    • 用法不同

      null表示 “沒有物件”,即該處不應該有值。
      (1)作為函式的引數,表示該函式的引數不是物件。
      (2)作為物件原型鏈的終點。
      
      undefined表示“缺少值”,就是此處應該有一個值,但是還沒有定義。
      (1)變數被聲明瞭,但沒有賦值時,就等於undefined。
      (2)呼叫函式時,應該提供的引數沒有提供,該引數就等於undefined。
      (3)物件沒有賦值的屬性,該屬性的值為undefined。
      (4)函式沒有返回值時,預設返回undefined。
      
    • 型別轉換

      Number(undefined)  // NaN
      Number(undefined + 10)  //NaN
      Number(null)  // 0
      Number(10 + null)  // 10
      
    • 資料型別

      undefined === null  //false   undefined與object
      undefined == null  //true  js規定
      
  • 8.至少可以說出三種判斷JavaScript資料型別的方式,以及他們的優缺點,如何準確的判斷陣列型別

    • typeof

      • 優點:使用簡單,能判斷出所有基本資料型別(null是object)+function

      • 缺點:不能區分object型別的具體型別,比如 Array 、Date 以及自定義類。

      • var arr = [];
        console.log(typeof arr);//object
        
    • instanceof

      • 優點:能判斷出引用型別

      • 缺點:只能判斷出用物件定義的基本資料型別;不能跨iframe

      • var arr = [];
        alert(arr instanceof Array);//true
        
    • constructor

      • 優點: 基本能檢測所有的型別(除了null和undefined,並且會報錯。因為null和undefined是無效的物件,因此是不會有constructor存在的)

      • 缺點:constructor易被修改導致判斷出錯,也不能跨iframe

      • var arr = [];
        alert(arr.constructor == Array);//true
        
    • Object.prototype.toString.call( ) ;

      • 優點:能判斷出所有的型別

      • 缺點:IE6下,undefined和null均為Object

      • var arr = [];
        console.log(Object.prototype.toString.call(arr));//[object Array]
        
  • 9.可能發生隱式型別轉換的場景以及轉換原則,應如何避免或巧妙應用

    • 應用場景

    • 場景一:算術運算子

      • 字串+數字=字串數字

        console.log(10+"abc");//10abc
        
      • 非字串+數字=轉數字+數字

        console.log(10+true);//11
        
      • -*/% 將字元轉換成數字,再進行正常的運算,結果必為數值,若字元不是純數字,則結果為NaN

      • (+字串)轉數字

    • 場景二:關係(比較)運算子

      • <<=>>=!===

        • 任意一邊出現數值,就會把另一邊轉成數值,再進行比較。

          console.log([1] == 1);//true,相當於1 == 1
          console.log([] == true);//false,相當於0 == 1
          console.log({} > true);//false,相當於 NaN > 1
          console.log('true' <= 0);//false,相當於NaN <= 0
          
        • 一個值轉換為另一個值並不意味著兩個值相等

          console.log(new Date() == 'Fri Jul 15 2016 22:12:05 GMT+0800 (中國標準時間)');//true
          
          console.log(Number(null));//0
          console.log(null == 0);//false
          
          console.log(Boolean(NaN));//false
          console.log(NaN == false);//false,NaN與任何值都不等,包括自己
          
        • 兩邊是物件

          console.log({} == {});//false
          console.log([] == []);//false
          
        • 兩邊都是字串,則是按照字串的按位比較法。

    • 場景三:isNaN()

      • 引數轉成數值,嚴格轉換,能識別小數點
    • 場景四:判斷語句if()

      • 隱式轉換,將其他轉成布林值
    • 場景五:邏輯運算子

      • 邏輯非 !
        • 隱式轉換,將其他資料型別轉成布林值
        • 優先順序高於關係運算符
      • 位運算子(&、|、^、&&、||)
        • 隱式轉換,將其他資料型別轉成數字
        • 優先順序低於關係運算符
      • 位運算子(<<等)
        • 隱式轉換,將其他資料型別轉成數字
        • 優先順序高於關係運算符
    • 避免隱式轉換

      • 如果兩遍的值中有 true 或者 false , 千萬不要使用 == (會被轉為數字0,1來進行判斷,會出現一些意外的情況)
      • 如果兩遍的值中有[]、””或者0,儘量不要使用 ==
      • 使用全等=來代替
    • 巧妙應用

      使用一個物件,進行隱式型別轉換
      const a = (function() {
          let i = 1;
          return {
              valueOf: function() {
                  return i++;
              }
          }
      })();
      
      console.log(a == 1 && a == 2 && a == 3); // true
      
  • 10.出現小數精度丟失的原因,JavaScript可以儲存的最大數字、最大安全數字,JavaScript處理大數字的方法、避免精度丟失的方法

    • 小數精度丟失的原因:計算機的二進位制實現和位數限制有些數無法有限表示。

    • JS的基礎型別Number,遵循 IEEE 754 規範,採用雙精度儲存(double precision),佔用 64 bit。符號位(1bit),指數(11bit),尾數(52bit),因此 JS 中能精準表示的最大整數是 Math.pow(2, 53)-1,十進位制即 9007199254740991。

    • 最大安全數字

      console.log(Number.MAX_SAFE_INTEGER); //9007199254740991
      console.log(Number.MIN_SAFE_INTEGER); //-9007199254740991
      
    • JS 處理大數字的方法

      • json-bigint
      • bignumber.js:原理是把所有數字當作字串,重新實現了計算邏輯,缺點是效能比原生的差很多。
      • proposal bigint
      • 大數運算:化為字串再運算
    • 避免精度丟失的方法

      • 小數:小數化整進行運算再化為小數。
      • CalcEval.js引擎

本文作者:AlubNoBug

本文連結:https://www.cnblogs.com/AlubNoBug/p/13911382.html