# 概述

本文主要来自 GitHub 中作者开放的文档

在此书之前第一章中已经提到过,JavaScript 中的值有类型之分,而变量是不存在类型的,目前 JavaScript 拥有如下几种类型,区分 null 和 undefined 的话总共 7 种类型。

  • string
  • number
  • boolean
  • null and undefined
  • object
  • symbol (new to ES6)

如果你不知到某个值的类型,JavaScript 里提供了一个名字为 typeof 的函数,用这个函数可以检测你的值的类型。

var a;
typeof a;				// "undefined"
 
a = "hello world";
typeof a;				// "string"
 
a = 42;
typeof a;				// "number"
 
a = true;
typeof a;				// "boolean"
 
a = null;
typeof a;				// "object" -- weird, bug
 
a = undefined;
typeof a;				// "undefined"
 
a = { b: "c" };
typeof a;				// "object"

注意上面的 6 种类型返回的都是 string 类型的字符串(如果算上 es6 的 "symbol" 类型,就是 7 种),如 typeof "abc" 返回的是 "string",而不是 string。

同时可以看到上面只定义了一个变量,仅是在不同时刻赋予的值是不同的,我们这里使用的 typeof a 其实际意义上并不是指 type of a,而是 type of the value current in a,是指值的类型而非变量,JavaScript 中只有值拥有类型,而变量只是这些具体值的一个容器。

这其中有一个值的类型比较有趣,那就是 typeof null,因为如果你测试一下的话,就会发现她返回的竟然是一个 "object",而你希望她应该正确的返回一个 "null",注意,这是一个由来已久的 JavaScript bug,由于现在很多 web 项目中使用了这个 bug,所以不可能再去修复,否则会引发更多的问题.

假如你定义 a = undefined,再定义 var a,当你使用 typeof 输出 a 时,会发现其实都是 "undefined",这说明这两种操作可以等同看待,类似这种返回 "undefined" 的操作还有一些,如将一个没有返回值的函数(即 void 类型)赋值给 a,其返回的也会是一个 "undefined"。

function fun(){
  
}
var a = fun();
typeof a; // "undefined"

下面我们就来仔细看一下

# "object"

首先她是一个复合值,简单说就是她可以包含各种类型的值,也是我们最常用的一个类型。

var obj = {
	a: "hello world",
	b: 42,
	c: true
};
 
obj.a;		// "hello world"
obj.b;		// 42
obj.c;		// true
 
obj["a"];	// "hello world"
obj["b"];	// 42
obj["c"];	// true

可以抽象成下面这幅图

注意上面两种获取值的方式,一般优先选择第一种使用点号获取的方式(主要是由于其简短易读的特点)。但是某些情况下,例如以 property/key 形式定义的值,一般会使用后者获取,如

var obj = {
	a: "hello world",
	b: 42
};
 
var b = "a";
 
obj[b];			// "hello world"
obj["b"];		// 42

类似地,还有一些常用的类型,如数组 array 和函数 function,这些类型不是内置类型(build-in type),但可以想象成 object 的子类型。其中数组不是以 property/key 形式定义的,而是以数字作为下标按一定顺序排列的,以下标 0 作为起点,如

var arr = [
	"hello world",
	42,
	true
];
 
arr[0];			// "hello world"
arr[1];			// 42
arr[2];			// true
arr.length;		// 3
 
typeof arr;		// "object"

建议在使用数字定位的值(numerically positioned values)时定义成数组的形式,而在使用具体名字获取值(property/key 形式,named properties)时定义成 object 类型。

function 也是 object 的一个子类型,如下

function foo() {
	return 42;
}
 
foo.bar = "hello world";
 
typeof foo;			// "function"
typeof foo();		// "number"
typeof foo.bar;		// "string"

注意,通常只是在真正需要时才会调用函数 function 里的值(如上面定义的 foo.bar 这种取值方式)。

# 内置类型的方法

在 JavaScript 中,如果你定义的数据类型是内置类型,那么你可以使用其自带的方法去做一些操作。如字符串的大小写转换,长度大小的获取等。

var a = "hello world";
var b = 3.14159;
 
a.length;				// 11
a.toUpperCase();		// "HELLO WORLD"
b.toFixed(4);			// "3.1416"

一个字符串值可以被一个 String 对象包装,一个数字可以被一个 Number 对象包装,并且一个布尔值可以被一个 Boolean 对象包装。大多数情况下,你不必担心或直接使用这些值的对象包装形式,基本上我们都是在使用原始数据类型,而不必理会其自身的拆箱和装箱操作。

# 值的比较

(1)强制转换:分为显式和隐式两种,显式转换可以简单地从代码中判断,而隐式的类型转换相对比较隐蔽,可能存在一些不够明显的副作用(或不好的行为)。我们通常会认为强制做类型转换是很邪恶的一种行为,这是因为强制类型转换可能会存在一些出人意料的结果,但事实上,当我们使用强制转换时,很多时候场景是相对合理的,容易被人理解的,甚至可以提高代码的可读性。

显式转换:

var a = "42";
 
var b = Number( a );
 
a;				// "42"
b;

隐式转换:

var a = "42";
 
var b = a * 1;	// "42" implicitly coerced to 42 here
 
a;				// "42"
b;				// 42 -- the number!

(2)布尔值判断(Truthy & Falsy):当非布尔值被强制转为布尔值时,它是真还是假?下面列一下默认的一些情况。在实际使用中,如果你的 ajax 返回的数据类型比较复杂,那就要小心了。

默认为 falsy 的情况:

  • "" (empty string)
  • 0, -0, NaN (invalid number)
  • null, undefined
  • false

默认为 truthy 的情况:

  • "hello"
  • 42
  • true
  • [ ], [ 1, "2", 3 ] (arrays)
  • { }, { a: 42 } (objects)
  • function foo() { .. } (functions)

举个例子说明一下

var t = "";
if (t){
 console.info("1");
}else{
 console.info("2");  // 输出 2
}

可以看到默认空字符串做布尔转换时,其实就是 false。

(3)相等判断:这个是一个比较常见的问题,一般使用判断是不做类型区别的,而 = 会首先判断你的数据类型是否一致,如

var a = "42";
var b = 42;
 
a == b;			// true
a === b;		// false

所以:

  • 如果比较中的任何一个值(aka side)可以是真或假值,则避免并使用 =。
  • 如果比较中的任一值可能是这些特定值(0,“” 或 [] - 空数组),请避免并使用 =。
  • 在所有其他情况下,可以安全地使用 ==。这不仅是安全的,而且在很多情况下它可以简化代码,提高可读性。

想要具体了解的话可以阅读 es5 官方文档的 11.9.3 章节。

另外,在做数组判断时,可能会遇到下面这种情况。至于原因是什么,可以参考 es5 的官方文档。

var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";
 
a == c;		// true
b == c;		// true
a == b;		// false

(4)不等式判断:通常我们认为做不等判别的知识 number 类型,然而在 JavaScript 中,string 类型值同样可以,string 类型的判断使用的是字母排列规则,如 b<f,a<b

console.info("bar" < "foo");   // 输出 true
console.info("24" < "21");   // 输出 false

当然,你也可以将 number 和 string 做比较,如

var a = 41;
var b = "42";
var c = "43";
 
a < b;		// true
b < c;		// true

然而,有时我们会遇到比较奇葩的判断,致使两边的数据类型 “严格不想等”(strict inequality),如

var a = 42;
var b = "foo";
 
a < b;		// false
a > b;		// false
a == b;		// false

此时,上面的 b 会判定为 "invalid number value" ,即 NaN,在 es5 文档上讲:NaN 既不大于也不小于任何其他值。所以都是 false。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Jalen Chu 微信支付

微信支付

Jalen Chu 支付宝

支付宝

Jalen Chu 公众号

公众号