Skip to content

2 数据类型

2.1 数据类型

一共有 7 种基本数据类型

  • 1 Number - 基于 IEEE 754 标准实现,采用双精度 64 位二进制格式, -(2 ^ 63 - 1) ~ 2 ^ 63 - 1
  • 2 Boolean - 只有 true 和 false
  • 3 Undefined - 没有定义的值
  • 4 Null - 空值
  • 5 String - 字符串
  • 6 Symbol - 唯一不可修改的值
  • 7 BigInt - 大整数类型

一种引用类型

  • Object - 引用类型,存储在堆中

2.2 类型检测

2.2.1 typeof

判断基础数据类型,除了 null 也可以判断 function

js
typeof (function() {}) // function
typeof (() => {}) // function
typeof (function() {}) // function
typeof (() => {}) // function

但数组、对象、null 都会返回 object

js
typeof [] // object
typeof {} // object
typeof null // object
typeof [] // object
typeof {} // object
typeof null // object

2.2.2 instanceof

判断引用类型

原理是判断其原型链上是否有该构造函数的原型

原型三角形

js
const _instanceof = (obj, Func) => {
  // 获取实例的原型对象
  let objPrototype = Object.getPrototypeOf(obj);
  // 获取构造函数的原型对象
  const funcPrototype = Func.prototype;
  while (objPrototype) {
    if (objPrototype === funcPrototype) {
      return true;
    }

    objPrototype = Object.getPrototypeOf(objPrototype);
  }
  return false;
};

console.log(new Object() instanceof Object); // true
console.log(_instanceof(new Object(), Object)); // true
const _instanceof = (obj, Func) => {
  // 获取实例的原型对象
  let objPrototype = Object.getPrototypeOf(obj);
  // 获取构造函数的原型对象
  const funcPrototype = Func.prototype;
  while (objPrototype) {
    if (objPrototype === funcPrototype) {
      return true;
    }

    objPrototype = Object.getPrototypeOf(objPrototype);
  }
  return false;
};

console.log(new Object() instanceof Object); // true
console.log(_instanceof(new Object(), Object)); // true

2.2.3 constructor

实例对象可以通过 constructor 属性找到它的构造函数

js
({}).constructor === Object // true
[].constructor === Array // true
({}).constructor === Object // true
[].constructor === Array // true

这种方法不太准确,因为可以修改原型对象

2.2.4 Object.prototype.toString.call()

可以判断所有类型

js
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(1);  // '[object Number]'
Object.prototype.toString.call('1'); // '[object String]'
Object.prototype.toString.call(true); // '[object Boolean]'
Object.prototype.toString.call(undefined); // '[object Undefined]'
Object.prototype.toString.call(Symbol(1)); // '[object Symbol]'
Object.prototype.toString.call(BigInt(1)); // '[object BigInt]'
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call(1);  // '[object Number]'
Object.prototype.toString.call('1'); // '[object String]'
Object.prototype.toString.call(true); // '[object Boolean]'
Object.prototype.toString.call(undefined); // '[object Undefined]'
Object.prototype.toString.call(Symbol(1)); // '[object Symbol]'
Object.prototype.toString.call(BigInt(1)); // '[object BigInt]'

2.2.5 如何判断是否是数组

常见的有:

  • Array.isArray()
  • instanceof
  • Object.prototype.toString.call()

2.2.6 如何判断对象是否属于某个类

  • instanceof
  • constructor
  • Object.prototype.toString.call()

2.3 类型转化

2.3.1 布尔类型

在条件判断中,除了 undefinednullfalseNaN''0-0+0 会被转化为 false,其他都会被转化为 true

这里有个特殊的点

js
+0 === -0; // true, 因为都会被转化为 false
+0 === -0; // true, 因为都会被转化为 false

2.3.2 隐式类型转化

JavaScript 的每个值都隐含的自带了 ToPrimitive 方法,用来将值进行隐式转化成基本类型值

js
let value = 0;
let a = {
    valueOf() {
        return 1;
    },
    toString() {
        return '2';
    },
    [Symbol.toPrimitive]() {
        value = value + 1;
        return value;
    }
}

a == 1; // true
a == 2; // true
a == 3; // true
let value = 0;
let a = {
    valueOf() {
        return 1;
    },
    toString() {
        return '2';
    },
    [Symbol.toPrimitive]() {
        value = value + 1;
        return value;
    }
}

a == 1; // true
a == 2; // true
a == 3; // true

ToPrimitive 方法会优先调用 Symbol.toPrimitive 方法,如果没有,再调用 valueOf 方法,如果还没有,再调用 toString 方法 在没有 ToPrimitive 情况下, 转数字先调用 valueOf 方法,转字符串先调用 toString 方法

2.3.3 基本类型在不同操作符下的转化规则

  • 1 +操作符: +操作符的俩边有一个是 string 类型时,俩边隐式转化成 string 类型,其他情况都转化成 number 类型
  • 2 其他情况转化为数字在操作
原始值转化目标结果
number布尔值除了 0、-0、NaN 都为 true
string布尔值除了空串都为 true
undefined、null布尔值false
引用类型布尔值true
number字符串6 -> '6'
数组字符串[1, 2] -> '1, 2' 每个元素都进行转字符串操作
对象字符串'[object, Object]'
string数字'1' -> 1 'a' -> Nam
数组数字空数组为0,存在一个元素且为数字转数字,其他情况为 NaN
null数字0
除数组以外的引用类型数字NaN
Symbol数字报错

转数字的特殊场景

  • undefined转数字: NaN
  • null转数字: 0
  • false转数字: 0
  • []转数字: 0

2.4 常见的问题

1 栈和堆有什么区别?

1 从数据结构的角度上看 栈是一个先进后出的数据结构 堆是一个特别的完全二叉树

2 从存储的角度上看 栈存储基本类型 堆存储引用类型

3 从垃圾回收的角度上看

  • 栈 采用 ESP 指针,例如当一个函数调用时,该函数的上下文被压入调用栈中,此时 ESP 指针指向该上下文,当函数执行完后,ESP指针下移,函数上下文弹出调用栈
  • 堆分成新生代和旧生代
  • 新生代采用 GC 算法,将新生代分成俩个区域,活动对象区域和空闲区域,对于一些占用内存较小的对象,会被分配到活动对象区域,当活动对象区域充满时,会进行一次 GC 算法,将存活的对象移入空闲区域并进行一次碎片内存整理后,将空闲区域和活动对象区域进行互换,等待下一次的垃圾回收的执行(俩次回收都还存活的对象,进入到老生区)
  • 旧生代采用标记清除 + 标记整理算法,会循环查找堆内存空间的对象是否被引用,如果没有,则标记清除,清除后会标记整理算法将碎片空间进行整理

2 什么是 JavaScript 中的包装类型

在 JavaScript 中,基本类型是没有属性和方法的,但是为了方便操作基本类型的值,当调用基本类型的属性和方法时,JavaScript 会隐式地将基本类型的值转化为对象。

js
const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"

3 undefined 和 null 的区别

undefined 表示未定义,一般变量声明了但还没有定义的时候返回 undefined null 表示空值,常用在对象初始化的场景

区别如下:

  • typeof null 返回的是 ‘object’, 因为在早期 javaScript 设计时,类型通过 1~3位标识进行存储,对象和null一样都是 000
  • typeof undefined 返回的是 ‘undefined’
  • undefined 不是保留字,可以被赋值,通常我们会用 void 0 表示 undefined,null 是保留字,不能被赋值

4 isNaN 和 Number.isNaN 的区别

  • isNaN 不会判断是否为数字,会先将参数转化为数字,再判断是否为 NaN
  • Number.isNaN 会判断是否是数字,是数字后才会判断是否是 NaN
js
isNaN('a'); // true
Number.isNaN('a'); // false
isNaN('a'); // true
Number.isNaN('a'); // false