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()方法的返回值相同。

2. 引用类型

构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。

var person = new Object();

2.1 Object类型

(1)创建对象

创建Object示例的方法有两种:
第一种是使用new操作符后跟Object构造函数

var person = new Object();

第二种是使用对象字面量表示法:

var person = {
    name: 'Peggy7',
    age: 25
}

var person = {}与var person = new Object()是等价的。

(2)访问对象的属性

访问对象属性可以用点表示法和方括号表示法。

person.name
person['name']

两者看上去没有区别,但方括号表示法可以通过变量的访问属性,如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以使用方括号表示法。通常,除非使用变量来访问属性,否则建议使用点表示法。

2.2 Array类型

(1)创建数组

创建数字也有两种方法:
第一种是使用new操作符后跟Array构造函数

var colors = new Array(3);
var colors2 = new Array('red', 'blue', 'green');

如果传入的是数值则表示创建一个长度为该数值的数组,也可直接传递数组中要保存的项。

第二种是使用数组字面量表示法:

var colors = ['red', 'blue', 'green'];

数组的length属性不光是只读的。

(2)监测数组

Array.isArray()方法可以准确的监测出一个值是否是数组。


Peggy7
677 声望22 粉丝