# JavaScript基础数据类型

# 1. 值类型与引用类型

# 1.1 数据类型分类

  • 基本数据类型:String Boolean Number Symbol(ES6新增) Undefined Null
  • 复杂数据类型:Object
  • 基本数据类型中有两个为特殊数据类型: null undefined
  • 常见内置对象:Boolean Number String Array Math Date RegExp Function...

Symbol(ECMAScript 6 新定义数据类型)暂时不涉及

# 1.2 数据访问

  • 基本数据类型在栈空间存储,访问方式是按值访问。基本类型(值类型)在调用函数的时候,传递的是值。
  • 引用类型的对象在堆中存储,地址在栈中存储。引用类型,在函数调用的时候,传递的是地址(引用)。

具体如下图所示:

js数据类型-1

function addTen (num) {
  num += 10;
  return num;
}
const count = 20;
const result = addTen(count);
console.log(count); // 20,没有变化
console.log(result); // 30

function setName (obj) {
  obj.name = 'liam';
  // eslint-disable-next-line no-new-object
  obj = new Object();
  obj.name = 'tom';
}
// eslint-disable-next-line no-new-object
const person = new Object();
person.name = 'liam1';
setName(person);
console.log(person.name); // "liam"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2. 数据类型判断

# 2.1 typeof

typeof操作符是检测基本类型的最佳工具

返回结果 含义
undefined 未定义
boolean 布尔值
string 字符串
number 数值
object 对象或null
function 函数

对未初始化的变量执行typeof操作符会返回undefined值,而对未声明的变量执行typeof操作符同样也会返回undefined

let test; // 这个变量声明之后默认取得了 undefined 值
// var age // 下面这个变量并没有声明
console.log(typeof test); // "undefined"
console.log(typeof age); // "undefined"
1
2
3
4

typeof原理:不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位存储其类型信息

  • 000: 对象
  • 010: 浮点数
  • 100:字符串
  • 110:布尔
  • 1:整数

null:null的二进制表示全为0,自然前三位也是0,所以执行typeof时会返回"object"

undefined:用 −2^30 整数来表示(一个超出整型范围的数)

ES6 的 typeof 是如何对待函数和对象类型的:

  • 如果一个对象(Object)没有实现 [[Call]] 内部方法,那么它就返回 object
  • 如果一个对象(Object)实现了 [[Call]] 内部方法,那么它就返回 function

一个对象如果支持了内部的 [[Call]] 方法,那么它就可以被调用,就变成了函数,所以叫做函数对象

注意首字母为小写字母 例如: typeof 'abc'=== 'string'

# 2.2 Instanceof

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上

所以instanceof可以用于判断typeof返回object的引用类型存储值的类型

JavaScript 中一切皆对象,如下代码第3行返回false,其实问题的关键在于typeof str返回string并不是object

const str = 'This is a simple string';
const newStr = new String('String created with constructor');
str instanceof String; // 返回 false, 检查原型链会找到 undefined
newStr instanceof String; // 返回 true
1
2
3
4

这样 Boolean Number是一样的逻辑。还剩下两种基本类型:Null Undefined undefined 当我们对变量只声明没有初始化时,输出为 undefined,typeof undefined 返回的是 undefined 也不是 object 类型,所以 undefined 并不是任何对象的实例。

null 表示的是空对象,虽然 typeof null 是 object,但是 null 和 undefined 一样并没有任何属性和方法,在 instanceof 定义中也有判断,如果类型不是 object(这个类型判断并不是跟 typeof 返回值一样),就返回 false。

js数据类型

使用 instanceof 就是确定原型和实例之间的关系

const Fn = function () {};
const f1 = new Fn();
console.log(f1 instanceof Fn); // true
console.log(f1 instanceof Function); // false
console.log(f1 instanceof Object); // true
1
2
3
4
5

instanceof 还可以在继承关系中用来判断一个实例是否属于它的父类型

// 判断 f2 是否是 Fn2 类的实例 , 并且是否是其父类型的实例
function Father () {}
function Son () {}
Son.prototype = new Father(); // JavaScript 原型继承
const f = new Son();
console.log(f instanceof Son); // true
console.log(f instanceof Father); // true
1
2
3
4
5
6
7

# 2.3 instanceof 运算符代码

function instanceOfNew(L, R) { // L 表示左表达式,R 表示右表达式
  const O = R.prototype; // 取 R 的显示原型
  L = L.__proto__; // 取 L 的隐式原型
  while (true) {
    if (L === null) return false;
    if (O === L) { // 这里重点:当 O 严格等于 L 时,返回 true
      return true;
    }
    L = L.__proto__;
  }
}
1
2
3
4
5
6
7
8
9
10
11

# 2.4 constructor

constructor 属性返回对创建此对象的数组函数的引用。

object.constructor 其中object 是一个对象或函数的名称。 constructor 属性是每个具有原型的对象的原型成员。 这包括除 Global 和 Math 对象之外的所有内部 JavaScript 对象。

'abc'.constructor === String; // true
(123).constructor === Number; // true
true.constructor === Boolean; // true
[1, 2].constructor === Array; // true
({ name: 'liam' }).constructor === Object; // true
(() => {}).constructor === Function; // true
new Date().constructor === Date; // true
(/[a-z]/).constructor === RegExp; // true
1
2
3
4
5
6
7
8

js数据类型

下面是使用new创建的基础数据类型

const str = new String('abc');
str.constructor === String; // true
1
2

在继承关系中用来判断会出现错误

function Father () {}
function Son () {}
Son.prototype = new Father(); // JavaScript 原型继承
const f = new Son();
console.log(f.constructor === Son); // false
console.log(f.constructor === Father); // true
1
2
3
4
5
6

解决construtor的问题通常是让对象的constructor手动指向自己:

function Father () {}
function Son () {}
Son.prototype = new Father(); // JavaScript 原型继承
const f = new Son();
f.constructor = Son; // 将自己的类赋值给对象的constructor属性
console.log(f.constructor === Son); // true
console.log(f.constructor === Father); // 基类不会报true了
1
2
3
4
5
6
7

# 2.5 Object.prototype.toString.call(obj)

Object.prototype.toString.call() 最准确最常用的方式。首先获取Object原型上的toString方法,让方法执行,让toString方法中的this指向第一个参数的值。

Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(123); // "[object Number]"
Object.prototype.toString.call('abc'); // "[object String]"
Object.prototype.toString.call([]); // "[object Array]"
// eslint-disable-next-line no-new-func
Object.prototype.toString.call(new Function()); // "[object Function]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call(new RegExp()); // "[object RegExp]"
Object.prototype.toString.call(new Error()); // "[object Error]"
Object.prototype.toString.call(document); // "[object HTMLDocument]"
Object.prototype.toString.call(window); // "[object Window]" window是全局对象global的引用
// 使用new创建的基础数据类型对象
const str = new String();
Object.prototype.toString.call(str); // "[object String]"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 3. 数据类型转换

# 3.1 基础介绍

js在一些操作符的作用下会进行隐式转换,涉及隐式转换最多的两个运算符 +==,下面来介绍一下。

  • + 可能是字符串拼接操作,也可能是数字相加
  • ==不同于===存在数据类型转换
  • - * % / > <等其他操作符只会针对number类型,所以其都是把其他类型转换成数字类型
  • && || !与或非操作符是进行布尔运算的,所以会把他们转换成布尔值

可以看一下下面的例子,下文中会依次介绍

'123' - 1; // 122
'123a' - 1; // NaN
`123${ 1}` // 1231
`${NaN }123a`; // NaN123a
Number(null); // 0
null == 0; // false
null >= 0; // true
2 == true; // false
'' == 0; // true
1
2
3
4
5
6
7
8
9

隐式转换中主要涉及到三种转换:

含义 函数名称
将值转为原始值 ToPrimitive()
将值转为数字 ToNumber()
将值转为字符串 ToString()
将值转为布尔值 ToBoolean()

# 3.2 类型转换涉及函数

# 3.2.1 通过ToNumber将值转换为数字

参数类型 转换结果 举例
Undefined NaN undefined +0 // NaN
Null +0 null >=0 // true
Boolean true转换1,false转换为+0 true + 1 // 2
String 将字符串中内容转化为数字,转化失败返回NaN '123'-1 // 122
Object 先用ToPrimitive(obj, Number)转换为原始值,再用ToNumber转换为数字 [2]-1 // 1

''空字符串转换为数字为 0

# 3.2.2 通过ToString将值转换为字符串

参数类型 转换结果 举例
Undefined 'undefined' undefined + '123' // undefined123
Null 'null' null + '123' // null123
Boolean 转换为'true' 或 'false' 'false' + '123' // false123
Number 数字转换字符串 -17.5 + '123' // -17.5123
Object 先用ToPrimitive(obj, String)转换为原始值,再用ToString转换为数字 [key='name',1]+'123a' // name,1123a

# 3.2.3 通过ToBoolean将值转换为布尔值

参数类型 转换结果 举例
Undefined false !!undefined // false
Null false !!null // false
Number 0、NaN为false,其他为true !!0 // false
String 空字符串(长度为0)为false,其他为true !!'' // false
Object true !![] !!{} // true

除了这六个值(undefined、null 、false、0、NaN、'')转换为false,其他都为true

# 3.2.4 通过ToPrimitive转换值

调用 ToPrimitive 函数将对象转化为原始类型。先看一下下面的内容,是不是头大,没关系,我们一点点讲解

[2, 3] - 1 // NaN
[] + [] // ""
{} - 1 // -1
({}) - 1 // NaN
{} + 1 // 1
1 + {} // 1[object Object]
[] + {} // [object Object]
1
2
3
4
5
6
7

ToPrimitive(input, hint)

参数名称 参数含义
input 将要转换的值
hint 转换类型,有Number/String/default三个分类
# 3.2.4.1 如果hint被标记为Number
  1. input为原始值,直接返回input
  2. 否则,调用input对象的valueOf()方法,如果结果是原始类型,则返回这个原始值
  3. 否则,调用input对象的toString()方法,如果结果是原始类型,则返回这个原始值
  4. 否则,抛出TypeError异常
# 3.2.4.2 如果hint被标记为String
  1. input为原始值,直接返回input
  2. 否则,调用input对象的toString()方法,如果结果是原始类型,则返回这个原始值
  3. 否则,调用input对象的valueOf()方法,如果结果是原始类型,则返回这个原始值
  4. 否则,抛出TypeError异常
# 3.2.4.3 如果没有设置hint这个参数时,会按照如下来自动设置
  1. input对象为Date类型,则hint被设置为String
  2. 否则,hint被设置为Number
# 3.2.4.4 valueOf方法解析
  1. Number、Boolean、String这三种构造函数生成的基础值的对象形式,通过valueOf转换后会变成相应的原始值。
  2. Date这种特殊的对象,其原型Date.prototype上内置的valueOf函数将日期转换为日期的毫秒的形式的数值。
  3. 除此之外返回的都为this,即对象本身:(有问题欢迎告知)
const num = new Number('123');
num.valueOf(); // 123

const time = new Date();
time.valueOf(); // 1545879601992

// eslint-disable-next-line no-array-constructor
const arr = new Array();
arr.valueOf() === arr; // true
1
2
3
4
5
6
7
8
9
# 3.2.4.5 toString方法解析
  1. Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法。
  2. 除以上对象及其实例化对象之外,其他对象返回的都是该对象的类型,(有问题欢迎告知),都是继承的Object.prototype.toString方法。
// eslint-disable-next-line no-prototype-builtins
Date.prototype.hasOwnProperty('toString'); // true

// eslint-disable-next-line no-prototype-builtins
RegExp.prototype.hasOwnProperty('toString'); // true

// eslint-disable-next-line no-prototype-builtins
Function.prototype.hasOwnProperty('toString'); // true

const arr = new Array([1, 2, 3]);
arr.toString(); // '1,2,3'

const time = new Date();
time.toString(); // "Thu Dec 27 2018 11:06:31 GMT+0800 (中国标准时间)"

const func = function () {
  return '123';
};
func.toString(); // "function () { return '123'}"

// eslint-disable-next-line no-new-object
const obj = new Object({});
obj.toString(); // "[object Object]"

Math.toString(); // "[object Math]"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

看一个经典的面试题:a == 1 && a == 2 && a == 3 什么情况下为 true ?

const a = {
  i: 1,
  toString () { // 或 valueOf
    a.i += 1;
    return a.i;
  },
};

// eslint-disable-next-line eqeqeq
console.log(a == 1 && a == 2 && a == 3); // true
1
2
3
4
5
6
7
8
9
10

a.i 最开始为1,执行 a == 1时,会调用 toString() 方法,得到 true 后,a.i 自增为 2,然后继续执行 a.i == 2,如此依次执行。 如果已经掌握了本文,那么不难知道,这里的 toString 也可以是 valueOf 或 ES6 中的 [Symbol.toPrimitive] 。

# 3.3 类型转换与操作符

操作符 名称 转换类型
++/-- 递增/递减 Number
-/+ 一元加/减 Number
-/*// 减法/乘法/除法 Number
! 逻辑非 Boolean

# 3.3.1 expr1 + expr2加法操作符

  • 如果expr1和expr2都是数字,执行常规的加法计算
  • 如果expr1和expr2不全是数字,则把对象、数值或布尔值等,调用它们的 toString()方法取得相应的字符串值。
  • 对于 undefined 和 null,则分别调用 String()函数并取得字符串"undefined"和"null",再将两个字符串拼接起来。

# 3.3.2 expr1 && expr2

  • 如果expr1 能转换成false则返回expr1,否则返回expr2。
  • 因此,与布尔值一起使用时,如果两个操作数都为true时&&返回true,否则返回false。

# 3.3.3 expr1 || expr2

  • 如果expr1能转换成true则返回expr1,否则返回expr2。
  • 因此,与布尔值一起使用时,如果任意一个操作数为true时,返回true。

# 3.3.4 小于(<)、大于(>)、小于等于(<=)和大于等于(>=)

  • 操作符都返回一个布尔值
  • 如果两个操作数都是数值,则执行数值比较。
  • 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值(可以通过字符串的 charCodeAt() 函数获取字符编码值)。
  • 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
  • 如果一个操作数是对象,则调用这个对象的 valueOf() 方法,用得到的结果按照前面的规则执行比较。如果对象没有valueOf()方法,则调用 toString()方法,并用得到的结果根据前面的规则执行比较。
  • 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
const result1 = 5 - true; // 4,因为true被转换成了1
const result2 = NaN - 1; // NaN
const result3 = '23' < '3'; // true
const result4 = '23' < 3; // false
const result5 = 'a' < 3; // false

// eslint-disable-next-line use-isnan
const result6 = NaN < 3; // false
// eslint-disable-next-line use-isnan
const result7 = NaN >= 3; // false

// eslint-disable-next-line no-constant-binary-expression
console.log(0 || 'NaN'); // 返回 NaN
console.log(NaN || ''); // 返回 '' 空字符串
// eslint-disable-next-line no-constant-binary-expression
console.log(null || 'undefined'); // 返回 undefined

const obj = {};
// eslint-disable-next-line no-constant-binary-expression
console.log(0 && obj); // 返回 0
console.log(obj && 0); // 返回 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 3.3.5 expr1 == expr2

  • 如果一个值是null, 另一个是undefined,则它们相等
  • 如果一个值是数字,另一个是字符串,先将字符串转换为数字,然后使用转换后的值进行比较
  • 如果其中一个值是true,则将其转换为1再进行比较。如果其中一个值是false,则将其转换为0再进行比较
  • 如果一个值是对象,另一个值是数字或字符串,则将对象转换为原始值,然后再进行比较。对象通过toString()方法或者valueOf()方法转换为原始值,JavaScript语言核心的内置类先尝试使用valueOf(),再尝试使用toString(),除了日期类,日期类只能使用toString()转换,那些不是JavaScript语言核心中的对象则通过各自的实现中定义的方法转换为原始值

# 5. 面试题目

const x = {};
const y = { key: 'y' };
const z = { key: 'z' };
x[y] = 'fatfish';
x[z] = 'medium';
console.log(x[y]);

// 使用一个对象作为属性键,最终会转换为[object Object]
x[y] = 'fatfish'; // x => { [object Object]: "fatfish" }
x[z] = 'medium'; // x => { [object Object]: "medium" }
console.log(x[y]); // medium
1
2
3
4
5
6
7
8
9
10
11
const arr = [1, 30, 4, 21, 100000];
console.log(arr.sort());

// 指定定义排序顺序的函数。如果省略,数组元素将转换为字符串,然后根据每个字符的 Unicode 值进行排序。
1
2
3
4
const fn = () => {
  // eslint-disable-next-line no-multi-assign
  let x = y = 1000;
  x += 1;
  return x;
};

fn();
console.log(typeof x);
console.log(typeof y);

// let x = y = 1000
// 这段代码等同于如下代码;
const x = 1000;
// 在这里,我们其实是声明了一个全局变量 y
y === 1000;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5. 参考文章

【JavaScript:Object.prototype.toString方法的原理】 (opens new window)

【JavaScript instanceof 操作符】 (opens new window)

你所忽略的js隐式转换 (opens new window)

理清JS中等于(==)和全等(===)那些纠缠不清的关系 (opens new window)

JavaScript高级程序设计(第3版)

Last Updated: 8/19/2025, 4:28:59 PM