乐趣区

JavaScript奇葩语言特性归纳持续更新中

1. 基本概念

1.1 数据类型

(1)typeof 操作符


console.log(typeof null);  //“object”

用 typeof 操作符去监测 null,得到的类型是 object。
原因是 null 被认为是一个空的对象引用。


function func(){// do something}
console.log(typeof func);  // "function"

function 虽然不是 6 大数据类型中的一种,但却可以被 typeof 操作符监测出来。
原因是函数在 ECMAScript 中是对象,但函数确实有一些特殊的属性,所以需要用 typeof 来区分。

(2)Undefined


var message;
console.log(message); // undefined
console.log(answer);  // 报错

console.log(typeof message);  // undefined
console.log(typeof answer);   // undefined

声明后未初始化的变量默认值为 undefined,想获得一个未声明的变量会报错,这很好理解。
但是用 typeof 操作符监测声明后未初始化的变量和一个未声明的变量都会得到 undefined。虽然这两种变量从技术角度看有本质区别,但实际上也不可能对它们做任何操作。
所以在声明变量的时候显式地初始化是一个好的选择,这样监测出 undefined 就知道是未声明的变量了。

(3)Null

null 表示的是一个空对象指针,所以如果一个变量在之后准备保存对象,那么初始化的值为 null 是最合理的。这样只要检查 null 值就知道是否已经保存了一个对象的引用了。


console.log(undefined == null);  // true

用相等操作符 (=) 去比较 undefined 和 null 会得到 true 的结果。
原因是 undefined 实际上是派生自 null。[这句话我觉得不用理解, 语言就是这么设计的。]

(4)Boolean

ECMAScript 中所有的值都有与 2 个 boolean 值对应的值:

数据类型 转换为 true 转换为 false
Boolean true false
String 任何非空字符 空字符
Number 任何非零数字值 0 和 NaN
Object 任何对象 null
Undefined n/a(不适用) undefined

(5)Number


var floatNum1 = 1.;    // 解析为 1
var floatNum2 = 10.0;  // 解析为 10

由于保存浮点数值需要的内存空间是保存整数值的两倍,因此 ECMAScript 会不失时机地将浮点数值转换为整数值。
如果小数点后面没有跟任何数字,那么这个数值就可以作为整数值来保存。


console.log(0.1 + 0.2);  // 0.30000000000000004

浮点数计算不精确。
基于 IEEE754 数值浮点计算产生误差,原因是计算机会先把 0.1 和 0.2 转化为二进制,再把相加的结果转化为十进制。在两次转化中产生了误差。


由于内存的限制,ECMAScript 并不能保存世界上所有的数值。最小数值为 5e-324,保存在 Number.MIN_VALUE 中;最大数值为 1.7976931348623157e+308,保存在 Number.MAX_VALUE 中。如果某次计算的结果得到了一个超出 JavaScript 数值范围的值,那么这个数值将被自动转换成特殊的 infinity 具体来说,如果这个数值是负数,则会被转换成 -infinity(负无穷),如果这个数值是正数,则会被转换成 Infinity(正无穷)。
可使用 isFinite()函数来确定一个数值是不是又穷的。


console.log(NaN == NaN);  // false

NaN,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。
NaN 本身有两个非同寻常的特点:
首先,任何涉及 NaN 的操作(例如 NaN/10)都会返冋 NaN, 这个特点在多步计算中有可能导致问题。
其次,NaN 与任何值都不相等,包括 NaN 本身。


这里我们探讨一个问题就是任何数据除以 0 只会返回 2 种结果:1 个是 NaN,一个是 Infinity。
下面看几个例子:

console.log(0/0);       // NaN
console.log(true/0);    // Infinity
console.log(false/0);   // NaN
console.log("2222"/0);  // Infinity
console.log(-1/0);      // -Inifinity
console.log(undefined/0);  // NaN
console.log(null/0);    // NaN

从这几个例子中可以归纳出几个结论:

  1. 0/ 0 和 NaN/0 会得到 NaN (例子中 false 会转化为 0,undefined 会转化成 NaN,null 会转化为 0, 对象会转化为 NaN[示例中未举出])
  2. 其他任何转化为数字不为 0 的值除以 0 都会得到 Infinity (正值就是 Infinity,负值则为 -Infinity)

可用 isNaN()函数来判断这个参数是否“不是数值”。如果这个值不能被转化成数值,则返回 true。

console.log(isNaN(NaN));    // true
console.log(isNaN(10));     // false
console.log(isNaN("10"));   // false
console.log(isNaN("blue")); // true
console.log(isNaN(true));   // false

尽管有点儿不可思议,但 isNaN()确实也适用于对象。在基于对象调用 isNaN()函数时,会首先调用对象的 valueOf()方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用 toString()方法,再测试返回值。


有 3 个方法可以把非数值转换为数值:Number()、parseInt()、parseFloat()

Number()方法转换规则:

  1. 布尔值:true 转换为 1,false 转换为 0
  2. 数字值:简单的传入传出
  3. undefined:转换为 NaN
  4. null: 转换为 0
  5. 字符串:如果只包含数字,则会去掉最前面的 0 转换为十进制;如果字符串包含有效的十六进制数,则转换为等值的十进制;空字符串转换为 0;如包含上述格式以外的字符,转换为 NaN
  6. 对象:会首先调用对象的 valueOf()方法,然后确定该方法返回的值是否可以转换为数值。如果不能,则基于这个返回值再调用 toString()方法,再测试返回值。

[搞懂这个规则再结合 NaN 的计算规则就可以完全理解任何数值 / 0 的结果]

parseInt()计算规则:
这个方法有第二个参数,是指定进制规则的。不传默认为十进制。
parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直至找到第一个非空格字符。如果第一个字符不是数字字符或者负号,parseInt()就会返冋 NaN; 也就是说,用 parseInt()转换空字符串会返回 NaN(Number()对空字符返回 0)。如果第一个字符是数字字符,parseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。

parseFloat()计算规则:
这个方法只解析十进制。
parseFloat()也是从第一个字符开始解析每个字符。而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符申将被忽略。

(6)String

有 2 个方法可以把非字符串转换为字符串:toString()、String()

除了 undefined 和 null 都可以使用 toString()方法,这个方法接受一个参数,可以指定进制规则。如果可能是 undefined 或者 null,可以用 String()方法。

(7)Object

对象其实就是一组数据和功能的集合。对象可以通过执行 new 操作符后跟要创建的对象类型的名称来创建。

var o = new Object()

Object 的每个实例都具有下列属性和方法:

  1. Constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数 (constructor) 就是 Object()。
  2. hasOwnProperty(propertyName):用于检查给定的域性在当前对象实例中 (而不是在实例的原型中) 是否存在。其中,作为参数的属性名 (propertyName) 必须以字符串形式指定(例如:o.hasOwnProperty (“name”) )。
  3. isProtocypeOf(object):用于检査传人的对象是否是另一个对象的原型。
  4. propertylsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句来枚举。与 hasOwnProperty ()方法一样,作为参数的域性名必须以字符串形式指定。
  5. toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
  6. toString():返回对象的字符串表示。
  7. valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值相同。
退出移动版