内置类型
JavaScript 有七种内置类型。
- 空值(null)
- 未定义(undefined)
- 字符串(string)
- 数字(number)
- 布尔值(boolean)
- 对象(object)
- 符号(symbol,ES6 中新增)
检测
typeof undefined === "undefined"; // true
typeof "42" === "string"; // true
typeof 42 === "number"; // true
typeof true === "boolean"; // true
typeof { life: 42 } === "object"; // true
比较特殊的存在
typeof null === "object"; // true
typeof function a(){/*..*/} === "function"; // true
function(函数)也是 JavaScript 的一个内置类型。它实际上是 Object 的一个“子类型”。
常用原生函数
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol() --- ES6 中新加入的!
var a = new String("abc");
typeof a; // 是 "object",不是 "String"
a instanceof String; // true
Object.prototype.toString.call( a ); // "[object String]"
typeof 只能用于判断基本数据类型,无法判断复杂数据类型。对于所有 typeof 返回值为 "object" 的对象(如数组)都包含一个内部属性 [[Class]] (我们可以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,一般通过 Object.prototype.toString(..) 来查看。
Object.prototype.toString.call([1,2,3]);
// "[object Array]"
Object.prototype.toString.call(/regex-literal/i);
// "[object RegExp]"
Null() 和 Undefined() 这样的原生构造函数并不存在,但是内部 [[Class]] 属性值仍然是 "Null" 和 "Undefined"。其它基本类型被各自的封装对象自动包装起来,所以它们的内部 [[Class]] 属性值分别为 "String","Number","Boolean"。
Object.prototype.toString.call("abc");
// "[object String]"
Object.prototype.toString.call(null);
// "[object Null]"
Object.prototype.toString.call(1);
// "[object Number]"
Object.prototype.toString.call(true);
// "[object Boolean]"
Object.prototype.toString.call(undefined);
// "[object Undefined]"
Object.prototype.toString.call(Symbol(123))
// "[object Symbol]"
这里的 Symbol 非常特殊,我们可以使用 Symbol(..) 原生构造函数来自定义符号。但不能带 new 关键字,否则会出错。
强制类型转换
ToString
toString() 负责处理非字符串到字符串的强制类型转换。
基本类型的字符串化规则:null 转换为 "null",undefined 转换为 "undefined",true 转换为 "true"。数字的字符串化遵守通用规则,极小和极大的数字使用指数形式。
// 1.07 连续乘以七个 1000
var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
// 七个 1000 一共 21 位数字
a.toString(); // "1.07e21"
普通对象的字符串化规则:除非对象自定义了 toString() 方法,否则 toString() (Object.prototype.toString()) 返回内部属性 [[Class]] 的值。
// 普通对象
var a = {b: "123"};
a.toString(); // "[object Object]"
// 数组
var a = [1,2,3];
a.toString(); // "1,2,3"
数组的默认 toString() 方法经过了重新定义,将所有单元字符串化后再用 "," 连接起来。
ToNumber
基本类型的数字化规则:true 转换为 1,false 转换为 0。undefined 转换为 NaN,null 转换为 0。字符串的处理基本遵循数字常量的相关规则/语法。处理失败时返回 NaN(处理数字常量失败时会产生语法错误)。
对象(包括数组)会首先被转换为相应的基本类型值。首先检查是否有 valueOf() 方法,如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。如果 valueOf() 和 toString() 都不返回基本类型值,会产生 TypeError 错误。
Object.create(null) 创建的对象 [[Prototype]] 属性为 null,并且没有 valueOf() 和 toString() 方法,因此无法进行强制类型转换。
var a = Object.create(null);
Number(a);
// VM406:1 Uncaught TypeError: Cannot convert
// object to primitive value
// at Number (<anonymous>)
// at <anonymous>:1:1
ToBoolean
假值:
- undefined
- null
- false
- +0、-0 和 NaN
- ""
除了假值以外的值都是真值。
显示强制类型转换
字符串和数字之间的显示转换
String(..) 和 Number(..)
String(..) 遵循 ToString 规则,Number(..) 遵循 ToNumber 规则。
var a = 42;
var b = String(a);
var c = "3.14";
var d = Number(c);
b; // "42"
d; // 3.14
toString() 、 一元运算符 + 和 ~ 运算符(即字位操作 “非“)
var a = 42;
var b = a.toString();
var c = "3.14";
var d = +c;
b; // "42"
d; // 3.14
显示转换为布尔值
Boolean(..) 遵循 ToBoolean 规则。
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
Boolean(a); // true
Boolean(b); // true
Boolean(c); // true
Boolean(d); // false
Boolean(e); // false
Boolean(f); // false
Boolean(g); // false
一元运算符 ! 和 !!
一元运算符 ! 显式地将值强制类型转换为布尔值。但是它同时还将真值反转为假值(或者将假值反转为真值)。所以显式强制类型转换为布尔值最常用的方法是!!。
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
!!a; // true
!!b; // true
!!c; // true
!!d; // false
!!e; // false
!!f; // false
!!g; // false
隐式强制类型转换
字符串和数字之间的隐式转换
+ 运算符即能用于数字加法,也能用于字符串拼接。如果 + 的其中一个操作数是字符串则执行字符串拼接,否则执行数字加法。
var a = "42";
var b = "0";
var c = 42;
var d = 0;
a + b; // "420"
c + d; // 42
a + d; // "420"
-,*,/ 都只适用于数字,因此会强制类型转换为数字。
var a = "3.14";
var b = a - 0;
b; // 3.14
隐式转换为布尔值
- if (..) 语句中的条件判断表达式
- for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)
- while (..) 和 do..while(..) 循环中的条件判断表达式
- ? : 中的条件判断表达式
- 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)
以上遵循 ToBoolean 规则。
宽松相等和严格相等
==允许在相等比较中进行强制类型转换,而===不允许。
11.9.3 节中规定, == 在比较两个不同类型的值时会发生隐式强制类型转换,会将其中之一或两者都转换为相同的类型后再进行比较。
11.9.3.1 的最后定义了对象(包括函数和数组)的宽松相等 == 。两个对象指向同一个值时即视为相等,不发生强制类型转换。
字符串和数字之间的相等比较
字符串强制转换为数字比较
如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
其它类型和布尔值之间的比较相等
布尔值强制类型转换为数字比较
如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果。
如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
null和undefined之间的相等比较
null 和 undefined 相等(它们也与自身相等),除此之外不与其它任何值相等
对象和非对象之间的相等
对象强制类型转换为基本数据类型值
如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果。
如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPrimitive(x) == y 的结果。
抽象关系比较
“抽象关系比较”,分为两个部分:比较双方都是字符串和其他情况。
比较双方首先调用 ToPrimitive ,如果结果出现非字符串,就根据 ToNumber 规则将双方强制类型转换为数字来进行比较。
比较双方都是字符串,则按字母顺序来进行比较。
安全运用隐式强制类型转换
- 如果两边的值中有
true 或者 false,千万不要使用 ==
- 如果两边的值中有
[],"" 或者 0,尽量不要使用 ==
内置类型
JavaScript 有七种内置类型。
检测
比较特殊的存在
function(函数)也是 JavaScript 的一个内置类型。它实际上是 Object 的一个“子类型”。常用原生函数
typeof 只能用于判断基本数据类型,无法判断复杂数据类型。对于所有 typeof 返回值为 "object" 的对象(如数组)都包含一个内部属性
[[Class]](我们可以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,一般通过 Object.prototype.toString(..) 来查看。Null() 和 Undefined() 这样的原生构造函数并不存在,但是内部
[[Class]]属性值仍然是 "Null" 和 "Undefined"。其它基本类型被各自的封装对象自动包装起来,所以它们的内部[[Class]]属性值分别为 "String","Number","Boolean"。这里的 Symbol 非常特殊,我们可以使用 Symbol(..) 原生构造函数来自定义符号。但不能带 new 关键字,否则会出错。
强制类型转换
ToString
toString() 负责处理非字符串到字符串的强制类型转换。
基本类型的字符串化规则:
null转换为"null",undefined转换为"undefined",true转换为"true"。数字的字符串化遵守通用规则,极小和极大的数字使用指数形式。普通对象的字符串化规则:除非对象自定义了 toString() 方法,否则 toString() (Object.prototype.toString()) 返回内部属性
[[Class]]的值。数组的默认 toString() 方法经过了重新定义,将所有单元字符串化后再用 "," 连接起来。
ToNumber
基本类型的数字化规则:
true转换为 1,false转换为 0。undefined转换为NaN,null转换为 0。字符串的处理基本遵循数字常量的相关规则/语法。处理失败时返回NaN(处理数字常量失败时会产生语法错误)。对象(包括数组)会首先被转换为相应的基本类型值。首先检查是否有
valueOf()方法,如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。如果valueOf()和toString()都不返回基本类型值,会产生TypeError错误。Object.create(null)创建的对象[[Prototype]]属性为null,并且没有valueOf()和toString()方法,因此无法进行强制类型转换。ToBoolean
假值:
除了假值以外的值都是真值。
显示强制类型转换
字符串和数字之间的显示转换
String(..) 和 Number(..)
String(..) 遵循 ToString 规则,Number(..) 遵循 ToNumber 规则。
toString() 、 一元运算符
+和~运算符(即字位操作 “非“)显示转换为布尔值
Boolean(..) 遵循 ToBoolean 规则。
一元运算符
!和!!一元运算符
!显式地将值强制类型转换为布尔值。但是它同时还将真值反转为假值(或者将假值反转为真值)。所以显式强制类型转换为布尔值最常用的方法是!!。隐式强制类型转换
字符串和数字之间的隐式转换
+运算符即能用于数字加法,也能用于字符串拼接。如果+的其中一个操作数是字符串则执行字符串拼接,否则执行数字加法。-,*,/都只适用于数字,因此会强制类型转换为数字。隐式转换为布尔值
以上遵循 ToBoolean 规则。
宽松相等和严格相等
==允许在相等比较中进行强制类型转换,而===不允许。字符串和数字之间的相等比较
字符串强制转换为数字比较
其它类型和布尔值之间的比较相等
布尔值强制类型转换为数字比较
null和undefined之间的相等比较
对象和非对象之间的相等
对象强制类型转换为基本数据类型值
抽象关系比较
安全运用隐式强制类型转换
true或者false,千万不要使用==[],""或者0,尽量不要使用==