原文

You Don't Know JS: Types & Grammar

类型

  • null

  • undefined

  • boolean

  • number

  • string

  • object

  • symbol -- added in ES6

值得注意的情形

typeof Symbol()      === "symbol";    // true
typeof function a(){} === "function"; // true
typeof null === "object"; // true

An "undefined" variable is one that has been declared in the accessible scope, but at the moment has no other value in it.
An "undeclared" variable is one that has not been formally declared in the accessible scope.

var a;

a; // undefined
b; // ReferenceError: b is not defined

尽管b没有定义,但用typeof对其操作后返回的也还是undefined

var a;

typeof a; // "undefined"

typeof b; // "undefined"

利用这点,我们可以做一些检查而避免报错

// oops, this would throw an error!
if (DEBUG) {
    console.log( "Debugging is starting" );
}

// this is a safe existence check
if (typeof DEBUG !== "undefined") {
    console.log( "Debugging is starting" );
}

讨论数组时,字符串类型的数字索引会直接被当作数字。

var a = [ ];

a["13"] = 42;

a.length; // 14

JavaScript中字符串是不可变的,数组是可变的,所有的字符串方法都返回新的字符串。

特别大或特别小的数字在显示时会默认调用toExponential()

var a = 5E10;
a;                    // 50000000000
a.toExponential();    // "5e+10"

var b = a * a;
b;                    // 2.5e+21

var c = 1 / a;
c;                    // 2e-11

因为数字可以被Number对象包裹,所以数值可以调用Number.prototype的方法。

var a = 42.59;

a.toPrecision( 1 ); // "4e+1"
a.toPrecision( 2 ); // "43"
a.toPrecision( 3 ); // "42.6"
a.toPrecision( 4 ); // "42.59"
a.toPrecision( 5 ); // "42.590"
a.toPrecision( 6 ); // "42.5900"

你也可以不通过变量直接访问这些方法,不过要注意.。因为.是一个有效的数字字符,它会优先被当作数字的一部分。

// invalid syntax:
42.toFixed( 3 );    // SyntaxError

// these are all valid:
(42).toFixed( 3 );    // "42.000"
0.42.toFixed( 3 );    // "0.420"
42..toFixed( 3 );    // "42.000"

42.toFixed( 3 )是错误的语法,因为.被当作数字的一部分。42..toFixed( 3 )中第一个.被当作数字的一部分,第二个.被当作属性操作符。

也可以用科学计数法表示数字。

var onethousand = 1E3;                        // means 1 * 10^3
var onemilliononehundredthousand = 1.1E6;    // means 1.1 * 10^6

以下这个情况并非JavaScript独有,任何采用二进制浮点数,依据IEEE 754都会如此

0.1 + 0.2 === 0.3; // false

这是因为用二进制浮点表示 0.1 0.2 并不精确。为了解决这个问题,设置个辅助的数值进行比较,这个值是2^-52 (2.220446049250313e-16),这个数值在ES6中为Number.EPSILON

if (!Number.EPSILON) {
    Number.EPSILON = Math.pow(2,-52);
}

function numbersCloseEnoughToEqual(n1,n2) {
    return Math.abs( n1 - n2 ) < Number.EPSILON;
}

var a = 0.1 + 0.2;
var b = 0.3;

numbersCloseEnoughToEqual( a, b );                    // true
numbersCloseEnoughToEqual( 0.0000001, 0.0000002 );    // false
Number.MAX_SAFE_INTEGER // 9007199254740991 2^53-1
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_SAFE_INTEGER // -9007199254740991
Number.MIN_VALUE // 5e-324

NaN是"not a number",不过更准确的定义应该是"invalid number","failed number",因为实际上它还是个number。它出现在用算数操作符操作运算元时,并不是两个都是数字的情形。

var a = 2 / "foo";        // NaN

typeof a === "number";    // true

我们知道

0 == false  // true
'' == false  // true

我们以为像NaN表示失败的也会是false,实际上

var a = 2 / "foo";

a == NaN;    // false
a === NaN;    // false
a == a; // false 它连自己都不等于
+0 === -0; // true

NaN == false; // false
undefined == false; // false
null == false; // false

与之相比,undefinednull都是种类型,该类型的值都只有一种。undefined是声明变量的默认值。

var b = null
var c = null
b === c // true
var d = undefined
var e = undefined
d === e // true

Number.isNaN()代替isNaN()

var a = 2 / "foo";
var b = "foo";

a; // NaN
b; // "foo"

window.isNaN( a ); // true
window.isNaN( b ); // true 
if (!Number.isNaN) {
    Number.isNaN = function(n) {
        return (
            typeof n === "number" &&
            window.isNaN( n )
        );
    };
}

var a = 2 / "foo";
var b = "foo";

Number.isNaN( a ); // true
Number.isNaN( b ); // false

或者利用它自己都不等于自己的特点。

if (!Number.isNaN) {
    Number.isNaN = function(n) {
        return n !== n;
    };
}

数字还有个特殊的数值Infinity

var a = 1 / 0;    // Infinity
var b = -1 / 0;    // -Infinity
typeof b; // "number"

数字和数字对象

function foo(x) {
    x = x + 1;
    x; // 3
}

var a = 2;
var b = new Number( a ); // or equivalently `Object(a)`

foo( b );
console.log( b ); // 2, not 3

nbb3210
436 声望31 粉丝

优雅地使用JavaScript解决问题