【重学前端】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

      • 优点:使用简单,能判断出所有基本数据类型+object(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

原文地址:https://www.cnblogs.com/AlubNoBug/p/13911382.html