JavaScript 语言的历史
ECMAScript 只用来标准化 JavaScript 这种语言的基本语法结构,与部署环境相关的标准都由其他标准规定,比如 DOM 的标准就是由 W3C 组织(World Wide Web Consortium)制定的。
2011 年 6 月,ECMAScript 5.1 版发布,并且成为 ISO 国际标准(ISO/IEC 16262:2011)。到了 2012 年底,所有主要浏览器都支持 ECMAScript 5.1 版的全部功能。
2015 年 6 月,ECMAScript 6 正式发布,并且更名为“ECMAScript 2015”。这是因为 TC39 委员会计划,以后每年发布一个 ECMAScript 的版本,下一个版本在 2016 年发布,称为“ECMAScript 2016”,2017 年发布“ECMAScript 2017”,以此类推。
JavaScript 的基本语法
如果只是声明变量而没有赋值,则该变量的值是 undefined。undefined 是一个特殊的值,表示“无定义”。
var a; |
JavaScript 是一种动态类型语言,也就是说,变量的类型没有限制,变量可以随时更改类型。
var a = 1; |
如果使用 var 重新声明一个已经存在的变量,是无效的。
var x = 1; |
JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
console.log(a); |
标识符命名规则如下:
- 第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
- 第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字 0-9。
对于 var 命令来说,JavaScript 的区块不构成单独的作用域(scope)。
{ |
else 代码块总是与离自己最近的那个 if 语句配对。
var m = 1; |
switch 语句后面的表达式,与 case 语句后面的表示式比较运行结果时,采用的是严格相等运算符(===),而不是相等运算符(==),这意味着比较时不会发生类型转换。
var x = 1; |
for 语句的三个部分(initialize、test、increment),可以省略任何一个,也可以全部省略。
for (;;) { |
上面代码省略了 for 语句表达式的三个部分,结果就导致了一个无限循环。
JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。
标签通常与 break 语句和 continue 语句配合使用,跳出特定的循环。
top: for (var i = 0; i < 3; i++) { |
数据类型概述
JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有六种。(ES6 又新增了第七种 Symbol 类型的值,本教程不涉及。)
- 数值(number):整数和小数(比如 1 和 3.14)。
- 字符串(string):文本(比如 Hello World)。
- 布尔值(boolean):表示真伪的两个特殊值,即 true(真)和 false(假)。
- undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
- null:表示空值,即此处的值为空。
- 对象(object):各种值组成的集合。
通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。
对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。
至于 undefined 和 null,一般将它们看成两个特殊值。
对象是最复杂的数据类型,又可以分成三个子类型。
- 狭义的对象(object)
- 数组(array)
- 函数(function)
函数其实是处理数据的方法,JavaScript 把它当成一种数据类型,可以赋值给变量,这为编程带来了很大的灵活性,也为 JavaScript 的“函数式编程”奠定了基础。
JavaScript 有三种方法,可以确定一个值到底是什么类型。
- typeof 运算符
- instanceof 运算符
- Object.prototype.toString 方法
typeof 123; // "number" |
利用这一点,typeof 可以用来检查一个没有声明的变量,而不报错。
v; |
typeof window; // "object" |
上面代码中,空数组([])的类型也是 object,这表示在 JavaScript 内部,数组本质上只是一种特殊的对象。instanceof 运算符可以区分数组和对象。
var o = {}; |
null 的类型是 object,这是由于历史原因造成的。1995 年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑 null,只把它当作 object 的一种特殊值。后来 null 独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null 返回 object 就没法改变了。
typeof null; // "object" |
null, undefined 和布尔值
null 与 undefined 都可以表示“没有”,含义非常相似。将一个变量赋值为 undefined 或 null,语法效果几乎没区别。
if (!undefined) { |
1995 年 JavaScript 诞生时,最初像 Java 一样,只设置了 null 表示”无”。根据 C 语言的传统,null 可以自动转为 0。
Number(null); // 0 |
但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。首先,第一版的 JavaScript 里面,null 就像在 Java 里一样,被当成一个对象,Brendan Eich 觉得表示“无”的值最好不是对象。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果 null 自动转为 0,很不容易发现错误。
因此,他又设计了一个 undefined。区别是这样的:null 是一个表示“空”的对象,转为数值时为 0;undefined 是一个表示”此处无定义”的原始值,转为数值时为 NaN。
Number(undefined); // NaN |
- null 表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入 null,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入 null,表示未发生错误。
- undefined 表示“未定义”,下面是返回 undefined 的典型场景。
// 变量声明了,但没有赋值 |
如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为 false,其他值都视为 true。
- undefined
- null
- false
- 0
- NaN
- “”或’’(空字符串)
注意,空数组([])和空对象({})对应的布尔值,都是 true。
数值
JavaScript 内部,所有数字都是以 64 位浮点数形式储存,即使整数也是如此。所以,1 与 1.0 是相同的,是同一个数。
这就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64 位浮点数)。
容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把 64 位浮点数,转成 32 位整数,然后再进行运算。
1 === 1.0; // true |
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3; |
根据国际标准 IEEE 754,JavaScript 浮点数的 64 个二进制位,从最左边开始,是这样组成的。
- 第 1 位:符号位,0 表示正数,1 表示负数
- 第 2 位到第 12 位(共 11 位):指数部分
- 第 13 位到第 64 位(共 52 位):小数部分(即有效数字)
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。
Math.pow(2, 53); |
Math.pow(2, 1024); // Infinity “正向溢出” |
- 十进制:没有前导 0 的数值。
- 八进制:有前缀 0o 或 0O 的数值,或者有前导 0、且只用到 0-7 的八个阿拉伯数字的数值。
- 十六进制:有前缀 0x 或 0X 的数值。
- 二进制:有前缀 0b 或 0B 的数值。
有前导 0 的数值会被视为八进制,但是如果前导 0 后面有数字 8 和 9,则该数值被视为十进制。
0888; // 888 |
JavaScript 的 64 位浮点数之中,有一个二进制位是符号位。这意味着,任何一个数都有一个对应的负值,就连 0 也不例外。
JavaScript 内部实际上存在 2 个 0:一个是 +0,一个是 -0,区别就是 64 位浮点数表示法的符号位不同。它们是等价的。
-0 === +0; // true |
1 / +0 === 1 / -0; // false |
NaN 是 JavaScript 的特殊值,表示“非数字” Not a Number,主要出现在将字符串解析成数字出错的场合。
5 - "x"; // NaN |
NaN 不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于 Number。
typeof NaN; // 'number' |
NaN === NaN; // false |
// 场景一 |
与数值相关的全局方法
parseInt("123"); // 123 |
// 对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。 |
parseInt("1000", 2); // 8 |