• 探究js数据类型和底层原理


    数据类型

    JS 的数据类型分为:基本数据类型和引用类型

    1. 数字(number)
    2. 字符串(string)
    3. 空值(null)
    4. 未定义(undefined)
    5. 布尔值(boolean)
    6. 符号(symbol, ES6 中新增)
    7. 大整数(BigInt, ES2020 引入)
    8. 对象 (object)

    其中基本数据类型存放在栈内存中,引用类型存放在堆内存

    • :原始数据类型(Undefined、Null、Boolean、Number、String、symbol、BigInt)
    • :引用数据类型(对象、数组和函数)

    两种类型的区别在于 存储位置的不同

    • 栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
    • 堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

    堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:

    数据结构中:

    • 栈中数据的存取方式为先进后出。
    • 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。

    操作系统中,内存被分为栈区和堆区:

    • 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    • 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收

    如何判断数据类型

    1. typeof

      typeof基本数据类型function 判断是准的,但对于 []、object 和 null就会判断成object

      console.log(typeof 2);           //number
      console.log(typeof NaN);         //number
      console.log(typeof "2");         //string
      console.log(typeof true);        //boolean
      console.log(typeof undefined);   //undefined
      console.log(typeof 123n);        //bigint
      console.log(typeof Symbol('张三'));  // symbol
      console.log(typeof function () {}); //function
      
      console.log(typeof []); //object
      console.log(typeof {}); //object
      console.log(typeof null); //object
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      那么,typeof 是根据什么判断的呢?

      在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:

      码值类型
      000对象
      010浮点数
      100字符串
      110布尔
      1整数

      有两种特殊数据类型:

      • undefined的值是 (-2)30(一个超出整数范围的数字);
      • null 的值是机器码 NULL 指针(null 指针的值全是 0)

      那也就是说 null 的类型标签也是 000,和 Object 的类型标签一样,所以会被判定为 Object。所以 typeof null 的结果是 object。

    2. instanceof

      instanceof对引用类型的判断是准确的,对于基本数据类型都是 false.

      console.log(2 instanceof Number);       // false
      console.log(NaN instanceof Number);     // false
      console.log("2" instanceof String);     // false
      console.log(true instanceof Boolean);   // false
      console.log(Symbol('张三') instanceof Symbol);      // false
      
      console.log(Object instanceof Object);              // true
      console.log(function () {} instanceof Function);    // true
      console.log([] instanceof Array);                   // true
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      如何实现instanceof ?

      function myInstanceof(left, right) {
        // 获取对象的原型
        let proto = Object.getPrototypeOf(left)
        // 获取构造函数的 prototype 对象
        let prototype = right.prototype;
      
        // 判断构造函数的 prototype 对象是否在对象的原型链上
        while (true) {
          if (!proto) return false;
          if (proto === prototype) return true;
          // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
          proto = Object.getPrototypeOf(proto);
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    3. constructor

      一般的数据类型和引用的都可以判断,但是 undefined 和 null 除外

      	console.log(('').constructor == String)
      	console.log((true).constructor == Boolean)
      	console.log(({}).constructor == Object)
      	console.log(([]).constructor == Array)
      	
      	console.log((undefined).constructor == undefined)   //报错
      	console.log((null).constructor == null)  //报错
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    但是注意,constructor 是可以被改变的。

    1. Object.prototype.toString.call()

      可以判断任何数据类型。
      原理:使用 Object 对象的原型方法 toString 来判断数据类型:

      var a = Object.prototype.toString;
      
      console.log(a.call(2));                 // [object Number]
      console.log(a.call(true));              // [object Boolean]
      console.log(a.call('str'));             // [object String]
      console.log(a.call([]));                // [object Array]
      console.log(a.call(function () {}));    // [object Function]
      console.log(a.call({}));                // [object Object]
      console.log(a.call(undefined));         // [object Undefined]
      console.log(a.call(null));              // [object Null]
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      同样是检测对象 obj 调用 toString 方法,obj.toString()的结果和 Object.prototype.toString.call(obj)的结果不一样,这是为什么?

      这是因为 toString 是 Object 的原型方法,而 Array、function 等类型作为 Object 的实例,都重写了 toString 方法。不同的对象类型调用 toString 方法时,根据原型链的知识,调用的是对应的重写之后的 toString 方法(function 类型返回内容为函数体的字符串,Array 类型返回元素组成的字符串…),而不会去调用 Object 上原型 toString 方法(返回对象的具体类型),所以采用 obj.toString()不能得到其对象类型,只能将 obj 转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用 Object 原型上的 toString 方法。

    2. 原型链

      obj.__proto__ === Array.prototype; // true
      
      • 1
    3. 通过 isPrototypeOf

      Array.prototype.isPrototypeOf(obj)
      
      • 1

    数组判断类型

    1. 通过 ES6 的 Array.isArray()做判断

      Array.isArrray(obj);
      
      • 1
    2. 通过 instanceof 做判断

      obj instanceof Array
      
      • 1
    3. 通过 Object.prototype.toString.call()做判断

      Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
      
      • 1
    4. 通过原型链做判断

      obj.__proto__ === Array.prototype;
      
      • 1
    5. 通过 Array.prototype.isPrototypeOf

      Array.prototype.isPrototypeOf(obj)
      
      • 1
  • 相关阅读:
    浙大中控ECS700学习笔记一硬件
    中间件 | Redis - [安装 & 基本信息]
    ZTree自定义不可展开节点的折叠图标
    89.(前端)商品分类显示优化——关闭选择框、下拉框、修改间隔、显示层级为tag标签、添加操作栏、添加索引
    Android kotlin在实战过程问题总结与开发技巧详解
    PHP低代码开发引擎—流程引擎
    Python类中的property的用法
    RabbitMQ(四):RabbitMQ高级特性
    day12 多线程02
    刷爆力扣之子数组最大平均数 I
  • 原文地址:https://blog.csdn.net/KID963931445/article/details/128000339