数据类型

112 阅读4分钟

基础数据类型

  • number数字
  • string字符串
  • boolean布尔值
  • null空
  • undefined未定义
  • symbol唯一值(es6)
    • 给对象设置“唯一值”的属性名
      • 字符串
      • Symbol类型
      • Map新的数据类型:可以允许属性名是对象
    • Symbol.asyncIterator/iterator/hasInstance/toPrimitive/toStringTag...是某些JS知识底层实现的机制
    • 在派发行为标识统一进行管理的时候,可以基于symbol类型的值,保证行为标识的唯一性
  • BigInt大数(es6)
    • Number.MAX_SAFE_INTEGER 9007199254740991 JS中的最大安全数
    • Number.MIN_SAFE_INTEGER -9007199254740991 最小安全数
    • 超过安全数后,进行运算或者访问,结果会不准确!!!
  • 解决方案
    1. 服务器返回给客户端的大数,按照“字符串”格式返回!
    2. 客户端把其变为 BigInt ,然后按照BigInt进行运算
    3. 最后把运算后的BigInt转换为字符串,在传递给服务器即可
// console.log(BigInt('90071992547409912434234') + BigInt(12345));
// console.log((90071992547409912446579n).toString());

对象类型 【引用数据类型】

  • 标准普通对象 例如:{x:10,y:20}
  • 标准特殊对象
  • new Array数组
  • new RegEXp正则
  • Math数学函数UI想
  • new Date日期对象
  • new Error错误对象
  • Set/Map (es6 新增的数据结构)

非标准特殊对象

  • 例如:new Number(1) ->原始值类型对应的“对象类型”实例

  • 函数对象 function

  • 创建一个数字

  • 字面量(创建的是原始值) var num1 = 10;

  • 构造函数(创建出来的是非标准特殊对象) var num2 = new Number(10);

num1 VS num2
一个是原始值、一个是对象
num2是Number类的一个实例,可以直接调用Number.prototype上的方法;从严格意义角度来讲,num1不是Number类的实例(因为实例都是对象类型的),按理来说num1应该是无法调用Number.prototype上的方法的,
但是实际操作中,是可以调用的,所以也可以称num1是Number累的实例;
num1.toFixed(2) -> new Number(num1)默认会把原始值转换为对象,然后再去调用toFixed方法。我们把这种操作(“把原始值转换为实例对象”)称之为“装箱”!!
num2+10 -> 20 浏览器会默认把实例对象转换为对应的原始值,然后再进行数学运算,这个过程称之为“拆箱”
装箱: new Number(num) 或者 Object(num)
拆箱: 把对象转换为原始值
  1. 首先调用对象的“Symbol.toPrimitive”函数
  2. 如果对象不具备这个属性,则调用“对象.valueOf()”函数,看获取的是否为原始值,是原始值则实现目标
  3. 如果不是原始值,则继续调用“对象.toString()”函数,把其转换为字符串!
  4. 如果最后的目的是变为数字,则再把字符串转换为数字 例如:
var num2 = new Number(10);
num2[Symbol.toPrimitive] -> undefined
num2.valueOf() -> 10
10+10 => 20

平时项目中会涉及数据类型的检测

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString.call
  • Array.isArray()
  • isNaN

typeof检测数据类型

  • 所有的数据类型值,在计算机底层都是按照 “64位” 的二进制值进行存储的!
  • typeof是按照二进制值进行检测类型的
    • 二进制的前三位是零,认为是对象,然后再去看有么有实现call方法,如果实现了,返回 'function',没有实现,则返回 'object'
    • null是64个零 typeof null -> 'object' 「局限性」
    • ...
  • 检测未被声明的变量,值是'undefined'
// 场景一:检测当前值是否是一个对象
const fn = options => {
    let type = typeof options;
    if (options !== null && (type === "object" || type === "function")) {
        // 是个对象
    }
};
fn({
    x: 10,
    y: 20
});
fn(10);

// 场景二:支持更多的模块导入方案
(function () {
    let utils = {};

    if (typeof window !== "undefined") window.utils = utils;
    if (typeof module === "object" && typeof module.exports === "object") module.exports = utils;
})();

parseInt/parseFloat都是用来把其它值转换为数字的,从字符串(传递的不是字符串,也要先转换为字符串)左侧第一个字符开始查找,把找到的有效数字字符转换为数字,遇到一个非有效的,则停止查找!一个都找不到,结果是NaN!

“+”在JS中比较特殊:除了数学运算,还有字符串拼接

  1. 加号两边有一边是字符串
  2. 加号两边有一边是对象,则可能是字符串拼接
  3. 如果两边既没有字符串也没有对象,则是数学运算
var a = ?;
if(a == 1 && a == 2 && a==3){
 console.log("OK")
}

解决方案一:利用“==”会进行数据类型转换、再利用对象转数字要经过四步,此时我们重写其中某一步,拿到自己想要的即可。

a = {
 i : 0
}
a[Symbol.toPrimitive] = function(){
 return ++this.i;
}

var a = [1,2,3];
a.toString = a.shift;

解决方案二:

var i =0;
Object.defineProperty(window,'a',{
 get(){
  return ++i;
 }
});
if(a==1 && a==2 && a==3)
 console.log("OK")
}