对语言引擎和开发人员来说,类型是值的内部特征,它定义了值的行为,以使其区别于其他值。
JavaScript中的变量是没有类型的, 只有值才有。 变量可以随时持有任何类型的值 。
在对变量执行typeof操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型。
1. 内置类型
JavaScript有七种内置类型:
null、undefined、boolean、number、string、object、symbol (ES6中新增):
typeof undefined === “undefined";
typeof true === “boolean";
typeof 10 === “number";
typeof ”10" === "string";
typeof {foo: 10} === “object";
typeof Symbol() === “symbol";
null比较特殊:
typeof null === “object";
一般这样检查null:
var foo = null;
!foo && typeof foo ==="object";
也可以利用Object.prototype.toString去检查:
Object.prototype.toString.call(null); //"[object Null]”
还有一种情况:
typeof function foo(){} === “function";
function实际上是object的一个“子类型”。具体来说,函数是“可调用对象”,它有一个内部属性[[Call]],该属性使其可以被调用。
2. 强制类型转换规则
将值从一种类型转换为另一种类型通常称为类型转换。在JavaScript中一般都称之为强制类型转换。
JavaScript中的强制类型转换总是返回标量基本类型值(字符串、数字和布尔值),不会返回对象和函数。
2.1 ToPrimitive
为了将对象转换为相应的基本类型值,JavaScript转换规则中定义了抽象操作 ToPrimitive:
如果目标类型是Number:
- 首先检查该值是否有 valueOf 方法。 如果有并且返回基本类型值,就使用该值进行强制类型转换
- 否则,就使用 toString的返回值来进行强制类型转换
- 如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误
如果目标类型是String:
- 首先检查该值是否有 toString 方法。 如果有并且返回基本类型值,就使用该值进行强制类型转换
- 否则,就使用 valueOf的返回值来进行强制类型转换
- 如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误
下面看几个示例:
根据目标类型不同,调用不同的方法:
var foo = {
valueOf: function(){
return '10';
},
toString: function(){
return '50';
}
};
Number(foo); //10
String(foo); //'50'
目标类型是Number,但是valueOf返回值不为基本类型,使用toString的返回值:
var foo = {
valueOf: function(){
return {};
},
toString: function(){
return '20';
}
};
Number(foo); //20
目标类型是String,但是toString返回值不为基本类型,使用valueOf的返回值:
var foo = {
valueOf: function(){
return 10;
},
toString: function(){
return {};
}
};
String(foo); // '10'
valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误
var foo = {
valueOf: function(){
return {};
},
toString: function(){
return {};
}
};
Number(foo); //TypeError: Cannot convert object to primitive value
String(foo); //TypeError: Cannot convert object to primitive value
2.2 ToString
基本类型值的字符串化规则:
- null 转换为 "null”
- undefined 转换为 "undefined”
- true 转换为 "true”
- 数字的字符串化则遵循通用规则,极小和极大的数字使用指数形式
var foo = 10;
String(foo); //'10'
var bar = 1 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
bar.toString(); // “1e+21"
引用类型的字符串化规则遵循ToPrimitive规则。
对普通对象来说,除非自行定义,否则 toString (Object.prototype.toString)返回内部属性 [[Class]] 的值:
var foo = {};
foo.toString();// '[object Object]'
数组的默认toString方法经过了重新定义,将所有单元字符串化以后再用 "," 连接起来:
var foo = [1,2,3];
foo.toString(); // '1,2,3'
toString可以被显式调用,或者在需要字符串化时自动调用。
2.3 ToNumber
有时我们需要将非数字值当作数字来使用,比如数学运算。这时候我们就需要用到ToNumber。
基本类型值的数字化规则:
- true转换为 1
- false转换为 0
- undefined转换为 NaN
- null转换为 0
ToNumber对字符串的处理基本遵循数字常量的相关规则,处理失败时返回NaN:
var foo = '10';
Number(foo); //10
foo = 'a11';
Number(foo); //NaN
对象(和数组)的数字化遵循ToPrimitive的规则。会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
2.3 ToBoolean
JavaScript中有两个关键词true和false,分别代表布尔类型中的真和假 。
- 假值(falsy value) :
- undefined
- null
- false
- 0 (+0 和 -0)
- NaN
- ""
假值的布尔强制类型转换结果为false:
Boolean(undefined); //false
Boolean(null); //false
Boolean(false); //false
Boolean(0); //false
Boolean(-0); //false
Boolean(NaN); //false
Boolean(""); //false
2. 假值对象:
浏览器在某些特定情况下,在常规JavaScript语法基础上自己创建了一些外来值,这些就是假值对象。
假值对象看起来和普通对象并无二致(都有属性),但将它们强制类型转换为布尔值时结果为false,比如:
Boolean(document.all); //false
3. 真值(truthy value):
假值列表以外的值都是真值。
- 除“”之外的字符串都是真值
- []、{} 和 function(){} 都是真值
Boolean(" "); //true
Boolean([]); //true
Boolean({}); //true
Boolean(function (){}); //true