JavaScript–变量与基本数据类型

2次阅读

共计 4469 个字符,预计需要花费 12 分钟才能阅读完成。

前言 JavaScript 中的变量为松散类型,所谓松散类型就是指当一个变量被申明出来就可以保存任意类型的值,就是不像 SQL 一样申明某个键值为 int 就只能保存整型数值,申明 varchar 只能保存字符串。一个变量所保存值的类型也可以改变,这在 JavaScript 中是完全有效的,只是不推荐。相比较于将变量理解为“盒子“,《JavaScript 编程精解》中提到应该将变量理解为“触手”,它不保存值,而是抓取值。这一点在当变量保存引用类型值时更加明显。
JavaScript 中变量可能包含两种不同的数据类型的值:基本类型和引用类型。基本类型是指简单的数据段,而引用类型指那些可能包含多个值的对象。本文主要介绍基本数据类型及其特点。
基本类型包括:Null、Undefined、Number、String、Boolean。引用类型主要包括:Object、Array、Date、RegExp、Function。
申明 JavaScript 中申明变量通过 var 操作符,申明的变量会成为其所在作用域内的局部变量,意思就是在全局申明的变量就是通常所说的全局变量,在函数内申明的变量就是以该函数为作用域的局部变量,局部变量会在函数执行完毕后被销毁,未通过 var 操作符申明的变量会默认为全局变量。需要一次申明多个变量时可以通过单 var 操作符的方式,代码会更加简洁。
var name = ‘susan’,
age = ’23’,
sex = ‘female’;

typeof 操作符在介绍基本类型值之前,先说下 typeof 操作符,typeof 操作符会返回数据类型的字符串表示。用它来检测基本数据类型比较有效率,而检测引用类型时通常用 instanceof 操作符。
typeof undefined; //undefined
typeof 2015; //number
typeof false; //boolean
typeof null; //object
typeof ‘abc’; //string
typeof {a:1}; //object

这里有一点不同的是,typeof 在对 null 进行检测时会返回字符串“object”,因为在 JavaScript 中 null 被当作空对象指针,这一点在 Douglas 的《JavaScript 语言精粹》也被吐槽过,不过了解下就可以了。
Undefined 类型 Undefined 类型只有一个特殊值即 undefiend。所有未初始化的变量均会保存该值。
var aa;
alert(aa); //undefined

这里要注意一点,undefined 与未定义的变量不同,如果在代码中调用某个未定义 (申明) 的变量,解析器会提示如下信息。
意为这个变量没有被申明过,查找的方式是通过沿作用域链向上搜索,如果在全局环境中都没有找到该变量的申明则抛出错误,这部分内容本菜以后和大家讨论。
Null 类型 Null 类型同样也只包含一个值即 null,从逻辑上看它被当作空对象指针,正是由于这个特性,如果你定义某个变量时不确定当前赋何值,但未来需要赋某个 object 类型值时,正确的方式就是将该变量初始化为 null。
这里提一句,在对 null 与 undefined 进行 == 比较时,会返回 true,据《JavaScript 高级程序设计》说,undefined 派生自 null,所以 ECMA-262 规定它俩相等性操作为 true。
Boolean 类型 Boolean 俗称布尔,仅包括两个值:true 和 false。这里有一个 Boolean()转型函数,它可以对任意类型的值使用,作用就是将其它类型值转换为布尔型。转换规则主要如下。
String 型:非空字符串 -true,空字符串(“”)-false
Number 型:任何非 0 数 -true,0 与 NaN-false
Object 型:任何对象 -true,null-false
Undefined 型:false
但并非使用该转型函数才会使数据类型转换,当遇到 if 语句时会对数据进行自动的类型转换。自动类型转换有其优点也有弊端,这里不再扩展。重要的是通过 Boolean 转型函数理解转换规则,以便在编码中使用。
这里举个非常简单的例子:在某个 app 中需要通过检测本地是否缓存了用户 ID 来判断需不需要登录操作。
if (!localStorage[‘memberId’]) {
// 登陆操作
}

这里当本地没有用户 ID 时,localStorage 值为 undefined,转换后为 false 值,非运算后为 true,执行登录操作。而不需要写成 localStorage[‘memberId’] === undefined 等等。
Number 类型 JavaScript 中的 Number 类型支持十进制、八进制以及十六进制的数值。关于浮点型的数值这里有几点要注意,在 JavaScript 中,0.1 与.1 相同,但是这种省略的写法是不推荐的。由于保存浮点型所需的内存是整型的两倍,所以 JavaScript 会在适当的时候将不必要的浮点型转换为整型,比如浮点型的 10.0 会自动保存为整型的 10。特别需要注意的一点是,浮点型运算精度远不如整型,例子如下:
console.log(0.1 + 0.2);

可以看到,运算并没有得到预期的结果,所以在实际运算中要注意这一点,同时这个例子也反映出了 JavaScript 中浮点型的最高精度即为显示的 17 位小数。过大或过小的数可以使用科学计数法 e 来表示,这一点就不再赘述。
InfinityJavaScript 能够保存的数值并不是无限大小的,当大于或小于某个界限时,该值会被自动转换为特殊值——Infinity,Infinity 也包括正负两种。检测一个数值是否为 Infinity 可以通过 isFinite()函数。
NaN 在 Number 类型中还有个很特殊的值,那就是 NaN,即非数值(Not a Number)。这个特殊值的存在是为了避免在某些需要返回数值时因为运算问题未返回数值报错,影响程序运行。比如一个数除以 0,在其他编程语言中会抛出错误,而在 JavaScript 中会返回 NaN。
NaN 有两个特点:1. 任何涉及 NaN 的操作均会返回 NaN,2.NaN 不与任何值相等,包括他自己 =.=,即做 NaN == NaN 的相等性验证时会返回 false。
检测一个值是否为 NaN 可以用 isNaN()函数,它会尝试将接收的参数转换为数值,意思就是字符串“10”可以被转换成数值 10,而字符串“color”不行。转换成功返回 false,反之为 true。
数值转换 Number 类型的数值转换方式可能通过三个函数:Number()、parseInt()、parseFloat()。由于 Number()转换函数转换规则奇葩(复杂且不合理),所以这里主要介绍 parseInt()与 parseFloat()。
首先申明一点,parseInt()与 parseFloat()函数是专门用于把字符串转换成数字的。这一点可能会导致困惑,明明是用来转换数值的,为什么要接收字符串。举个简单的例子,parseInt()在接收 3.14 这个浮点型数值时,会自动转换成该值的字符串表示——“3.14”,它会把 3.14 转换为 3 从逻辑上来看并不是它真的能对数值取整,而是在解析“3.14”这个字符串时遇到小数点“.”这个不能转换为数值的字符时会自动省略后面的东西。
有了以上的认识,我们来了解这两个函数具体的转换规则:
parseInt()函数在转换字符串时,会忽略前面的空格,直到找到第一个非空字符。如果第一个非空字符不是数字字符或者负号则返回 NaN。如果第一个字符是数值字符会继续解析第二个,直到解析完整个字符串或者遇到了一个非数值字符(如上面 3.14 的例子)。
parseInt(“”); //NaN
parseInt(3.14); //3
parseInt(“4.12”); //4
parseInt(“xyx123”); //NaN
parseInt(“123xyx”); //123

parseInt()同样可以解析二进制、八进制与十六进制的数值,由于 ECMAScript 版本不同对非十进制数解析时会出现分歧,所以最好传入第二个参数作为基数。
parseInt(100111,2); //39
parseInt(123,8); //83
parseInt(“0xBC”,16); //188

与 parseInt()函数类似,parseFloat()也是从第一个字符开始解析,直到字符串末尾或者遇到一个无效的浮点数字字符为止。比如,第一个小数点是有效的,第二个是无效的,因此后面的字符会被忽略。与 parseInt()不同的是它始终会忽略开头的 0,且不具备传入基数的能力,即只能解析十进制数值。
parseFloat(“123xyx”); //123
parseFloat(“xyx123”); //NaN
parseFloat(“012.3”); //12.3
parseFloat(“34.5”); //34.5
parseFloat(“34.5.6″); //34.5

String 类型在 JavaScript 中字符串使用单、双引号没有区别,只是要注意起始与结束保持一致即可。JavaScript 中也有转义字符,与其他语言基本一致,这里就不再赘述了。任何字符串都可以通过 length 属性来获取其长度。
var str = ‘Hello World’;
alert(str.length); //11

这里简要说一个特点,ECMAScript 中字符串一旦创建了就不能被改变,例如拼接某两个字符串,首先是创建一个新的字符串,将原有的字符串组合后装入其中,最后销毁原来的两个字符串。所以并不是像看上去那样进行简单的拼接。
字符串转换要将一个值转换为字符串类型有两个方式:1.toString()方法,2.String()转型函数。这两个方法的区别就是 null,undefined 值没有 toString()方法,而任何类型值都可以使用 String()函数。
var num = 123;
num.toString(); //”123″
var boo = false;
boo.toString(); //”false”

多数情况下,调用 toString()方法不必传递参数。当要确定输出数值的不同进制时,可以传入一个基数。
var num = 10;
num.toString(); //”10″
num.toString(2); //”1010″
num.toString(8); //”12″
num.toString(10); //”10″
num.toString(16); //”a”

在不知道要转换的值是不是 null 或 undefined 时,可以使用 String()方法。其规则为:如果该值有 toString()方法则调用该方法,如果是 null 或 undefined 则返回其字符串表示 ….. 好吧,总之用 String()转型函数就不会错。
String(10); //”10″
String(true); //”true”
String(null); //”null”
String(undefined); //”undefined”

正文完
 0