Skip to content

数据类型

有哪些

  • 基础数据类型:存储在栈内存,被引用或拷贝时,会创建一个完全相等的变量
    • undefined
    • Null
    • Boolean
    • String
    • Number
    • Symbol(ES6 引入):符号类型,表示独一无二的值
    • BigInt(ES10 引入):大整数类型,可以安全地存储和操作大整数。
  • 引用数据类型:存储在堆内存,存储的是地址,多个引用指向同一个地址
    • Object(以下类型继承自 Object)
      • Array
      • RegExp
      • Date
      • Math
      • Function

数据类型的检测

typeof

可判断基础数据类型(null 除外),不能正确判断引用数据类型(function 除外)

js
typeof 42; // "number"
typeof "blubber"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof { a: 1 }; // "object"
typeof null; // "object"
typeof [1, 2, 3]; // "object"
typeof function () {}; // "function"
typeof Symbol(); // "symbol"
typeof BigInt(9007199254740991); // "bigint"

instanceof

返回对象是否是构造函数生成的对象 可判断复杂引用数据类型,不能正确判断基础数据类型

js
let Car = function () {};
let benz = new Car();
Car instanceof Function; // true
Car instanceof Object; // true
benz instanceof Car; // true

let car = new String("Mercedes Benz");
car instanceof String; // true

let str = "Covid-19";
str instanceof String; // false

instanceof 的工作原理更详细的解释:

它首先会检查右侧的对象(函数)是否有 prototype 属性。如果没有,它会抛出一个类型错误。

如果有,它接着会查看左侧对象的原型链,看是否能找到右侧对象的 prototype。这个过程会一直持续到原型链的末端,也就是 null。

如果在原型链上找到了右侧对象的 prototype,那么 instanceof 就会返回 true。如果直到 null 都没有找到,那么就会返回 false。

这就是 instanceof 运算符的工作原理。需要注意的是,所有的对象最终都会继承自 Object,所以几乎所有的对象都可以通过 instanceof Object 检测出来。

Object.prototype.toString

js
Object.prototype.toString({}); // "[object Object]"
Object.prototype.toString.call({}); // "[object Object]"
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(function () {}); // "[object Function]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call(/123/g); // "[object RegExp]"
Object.prototype.toString.call(new Date()); // "[object Date]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(document); // "[object HTMLDocument]"
Object.prototype.toString.call(window); // "[object Window]"
js
function getType(obj) {
  let type = typeof obj;
  // 先进行 typeof 判断,如果是基础数据类型,直接返回
  if (type !== "object") {
    return type;
  }
  // 如果是引用数据类型,使用正则返回结果
  return Object.prototype.toString
    .call(obj)
    .replace(/^\[object (\S+)]\]$/, "$1");
}

// test
getType([]); // "Array"
getType("123"); // "string"

数据类型的转换

强制类型转换

  • Number()
    • 布尔值:true 和 false 分别被转换为 1 和 0
    • 数字:返回自身
    • null:返回 0
    • undefined:返回 NaN
    • 字符串
      • 只包含数字:转换为十进制
      • 有效的浮点格式:转换为浮点数值
      • 空字符串:转换为 0
      • 不是以上格式:返回 NaN
  • parseInt()
  • parseFloat()
  • toString()
  • String()
  • Boolean()
    • 除了 undefined、null、false、''、0、NaN 转换是 false
    • 其他都是 true

toString()String() 都可以用来将其他数据类型转换为字符串,但它们的行为方式有一些不同。

  1. toString() 是包装对象的一个方法,所有的对象都继承了这个方法。当你调用这个方法时,它会返回一个表示该对象的字符串。对于内置类型(如 NumberBooleanArray 等),它们的 toString() 方法已经被重新定义,以返回更有意义的字符串。例如,对于数组,toString() 会返回一个由数组中的所有元素组成的字符串,元素之间用逗号分隔。但是,如果你尝试在 nullundefined 上调用 toString(),会抛出一个错误,因为它们没有这个方法。

    javascript
    (123).toString(); // "123"
    true.toString(); // "true"
    [1, 2, 3].toString(); // "1,2,3"
    ({ a: 1, b: 2 }).toString(); // "[object Object]"
    null.toString(); // 抛出错误
    undefined.toString(); // 抛出错误
  2. String() 是一个函数,可以将任何类型的值转换为字符串。如果值有 toString() 方法,String() 会调用这个方法并返回结果。否则,它会直接返回一个表示该值的字符串。对于 nullundefinedString() 会返回 "null""undefined"

    javascript
    String(123); // "123"
    String(true); // "true"
    String([1, 2, 3]); // "1,2,3"
    String({ a: 1, b: 2 }); // "[object Object]"
    String(null); // "null"
    String(undefined); // "undefined"

总的来说,toString() 是一个方法,通常在对象上调用,而 String() 是一个函数,可以接受任何类型的参数。在处理 nullundefined 时,String() 会更安全,因为它不会抛出错误。

隐式类型转换

  • 逻辑运算符:&&、||、!

  • 运算符:+、-、*、/

  • 关系操作符:>、<、<=、>=

  • 条件运算符:if/while

  • 相等运算符:==

    1. 数字和字符串比较:字符串会被转换为数字,然后进行比较。例如:5 == '5',字符串 '5' 被转换为数字 5,所以结果为 true
    2. 布尔值和其他类型比较:布尔值会被转换为数字(true 转换为 1false 转换为 0),然后进行比较。例如:1 == true,布尔值 true 被转换为数字 1,所以结果为 true
    3. 对象和非对象比较:当一个对象与一个非对象(数字或字符串)比较时,对象会尝试转换为原始类型(通过 valueOftoString 方法),然后进行比较。例如:[1] == 1,数组 [1] 会先转换为字符串 '1',然后字符串 '1' 转换为数字 1,所以结果为 true
    4. nullundefined 比较:当 nullundefined 进行比较时,结果为 true。例如:null == undefined 的结果为 true
    5. NaN 比较NaN 与任何值比较,包括其自身,结果都是 false

这些转换规则可能会导致一些出乎意料的结果,因此在可能的情况下,推荐使用 ===(严格等于)进行比较,因为 === 不会进行类型转换。

数据类型的比较

在 JavaScript 中,数据类型的比较可以分为两种:严格比较(使用 ===!== 运算符)和抽象比较(使用 ==!= 运算符)。

  1. 严格比较(===!==

    严格比较运算符会比较两个值的类型和值。如果两个值的类型或值不同,那么这两个值就被认为是不相等的。

    javascript
    123 === 123; // true
    "123" === 123; // false
    true === 1; // false
    null === undefined; // false
    NaN === NaN; // false

    注意,NaN 是唯一一个不等于自身的值。

  2. 抽象比较(==!=

    抽象比较运算符会在比较两个值之前尝试进行类型转换。如果两个值的类型不同,JavaScript 会尝试将一个或两个值转换为一个共同的类型,然后比较它们的值。

    javascript
    123 == "123"; // true
    true == 1; // true
    null == undefined; // true
    "0" == false; // true
    NaN == NaN; // false

    注意,尽管 nullundefined 在抽象比较中被认为是相等的,但它们不会被转换为其他任何值。此外,NaN 在任何比较中都不等于任何值,包括它自己。

在编程中,通常推荐使用严格比较运算符,因为抽象比较的规则可能会导致一些非直观的结果。严格比较运算符提供了更明确和可预测的比较结果。

数据类型的包装对象

在 JavaScript 中,原始数据类型(Primitive types)包括 Undefined、Null、Boolean、Number、String、Symbol 和 BigInt。这些原始数据类型的值是直接包含在变量中的简单数据段。然而,JavaScript 为我们提供了一种方法,可以在这些原始数据类型上调用方法。这就是通过所谓的包装对象(Wrapper objects)实现的。

包装对象是一种特殊的对象,它们关联了一个原始类型的值。JavaScript 有三种内置的包装对象:String、Number 和 Boolean。当你在一个原始数据类型上调用一个方法时,JavaScript 会暂时把它转换(包装)成一个对象,这样就可以调用方法了。这个过程是自动的,你不需要显式创建一个包装对象。

以下是一些例子:

  1. String:当你对一个字符串调用方法时,JavaScript 会创建一个临时的 String 对象,调用方法,然后丢弃这个临时对象。你可以调用的方法包括 charAt()replace()split() 等。

    javascript
    let str = "hello world";
    console.log(str.charAt(0)); // 'h'

    在这个例子中,str 是一个字符串,不是一个对象,所以直接在 str 上调用 charAt() 方法实际上是 JavaScript 内部自动将 str 包装成了一个临时的 String 对象,然后在这个临时对象上调用了 charAt() 方法。

  2. Number:同样,当你对一个数字调用方法时,JavaScript 会创建一个临时的 Number 对象。

    javascript
    let num = 12345.6789;
    console.log(num.toFixed(2)); // '12345.68'

    在这个例子中,num.toFixed(2) 实际上是 JavaScript 内部自动将 num 包装成了一个临时的 Number 对象,然后在这个临时对象上调用了 toFixed() 方法。

  3. Boolean:Boolean 包装对象同样存在,但在实际编程中使用的不多。

需要注意的是,虽然 JavaScript 会自动创建这些包装对象,但直接使用 new 关键字手动创建包装对象是不推荐的,因为这可能会导致一些意想不到的结果。

javascript
let strObj = new String("hello world");
console.log(typeof strObj); // 'object', not 'string'

在这个例子中,strObj 是一个对象,而不是一个字符串。这可能会导致一些问题,因为在很多情况下,我们希望的是一个字符串,而不是一个 String 对象。

hancenter808@outlook.com