
3.1 JavaScript语法
JavaScript是一门直译式、弱类型的脚本语言,也是Web开发最重要的语言之一。JavaScript由ECMAScript、DOM(文档对象模型)、BOM(浏览器对象模型)三部分组成。ECMAScript规定了JavaScript的语法核心,这也是本节重点介绍的内容。
3.1.1 变量
1.交互式运行环境——REPL
Node.js提供了一个交互式运行环境——REPL。在这个交互式环境中可以运行简单的应用程序。在控制台直接输入node即可进入这个环境,此时控制台会显示一个“>”符号,表明我们已经进入这个环境,如图3.1所示。

图3.1 进入REPL运行环境
提示
如果要退出该运行环境,连续按两次Ctrl+C快捷键,或者输入.exit。Node.js的命令需要在前面加点。例如,可用.help查看所有命令。
本节中的所有代码都会在这个环境中使用和运行。
2.浏览器环境——Chrome
当然,读者也可以在浏览器的控制台运行。以Chrome浏览器为例,通过使用F12键或者Ctrl + Shift + I快捷键打开开发者工具,在开发者工具栏中选择Console面板,如图3.2所示。在Console中也是显示一个“>”符号,和REPL的使用方法一致。

图3.2 浏览器的Console面板
3.关键字var
JavaScript的变量通过关键字var来声明。前面说过JavaScript是一门弱类型的编程语言,JavaScript的所有数据类型都可以用var关键字来声明,通过var变量名=值的形式就可以对变量同时进行声明和赋值。和许多语言一样,JavaScript通过分号“;”来分隔不同的语句,以下这段代码就声明了两个变量:

4.变量的命名
JavaScript规定变量名必须以字母、美元符($)、下划线(_)三者之一开头,同时JavaScript对大小写敏感,大小写不同也就意味着是不同的两个变量。同时,JavaScript不区分单引号与双引号,因此上一个例子与用单引号表示的效果一致:

5.变量提升机制
JavaScript中存在变量提升机制,也就是所有的变量声明在运行时都会提升到代码的最前方。例如,上个例子在运行时实际上会先声明两个变量再赋值:

通过一个更直观的例子或许会让读者更易理解变量提升。在REPL中试图使用一个未声明的变量时会出现is not defined错误,如图3.3所示。

图3.3 变量未声明错误
如果试图使用一个已经声明却未赋值的变量,那么这个变量所代表的是undefined,如图3.4所示。

图3.4 已经声明却未赋值
提示
图3.4中有两行undefined:一个是白色,一个是半透明白色。执行node语句,在没有任何返回值的时候总是会输出一个undefined,读者不必介意,这不是错误。白色语句是正常输出的内容。
使用一个在后来定义赋值的代码时会返回undefined,如图3.5所示。

图3.5 先使用后声明赋值
可以发现这段代码返回undefined正是因为变量提升,实际运行的代码如下:

3.1.2 注释
JavaScript中的注释和很多其他编程语言类似,以双斜杠(//)代表单行注释,以“/*注释内容*/”形式代表多行注释。

3.1.3 数据类型
JavaScript中的数据类型可以分为简单数据类型和复杂数据类型。简单数据类型有undefined、boolean、number、string、null,复杂数据类型只有object。object由一组无序的键值对组成。
1.利用typeof区分数据类型
利用操作符typeof可以部分区分以上数据类型。typeof返回的值有undefined、boolean、number、string、object和function。下面举一个例子。
【示例3-1】

【代码解析】
可以看到null和object都返回了object,这是因为null实际上是一个空对象指针,当一个变量只声明未赋值时返回undefined。
number和string数据类型分别指数字类型和字符串类型;boolean类型和其他语言一样,仅有true和false两个值;null仅有一个值null。
2.利用Boolean()转化数据类型
JavaScript中可以利用Boolean()方法将其他数据类型转化为布尔值。需要注意的是,空字符串、0、null、undefined、NaN都将转化为false,其他值则会转化为true。下面举一个例子。
【示例3-2】

3.1.4 函数
在JavaScript中,声明一个函数只需要使用function关键字即可,如声明一个求和的函数,代码如下:

当然,函数同样可以作为一个值传递给一个变量,例如:

调用一个函数同样很简单,只需要在函数声明之后使用“函数名(参数)”的形式调用即可,如调用上面的函数:

函数中默认带有一个arguments对象,这是一个类数组对象。arguments记录了传递给函数的参数信息,因为javascript中的函数调用时,参数个数并不需要和定义函数时的个数一致。在上面的add()方法中多添加几个参数,函数仍然会正常执行,例如:

利用好这一点和arguments类数组特性可以对上述的add方法拓展一下,让这个函数无论接收多少个参数,总能返回这些数值的和:

还可以利用JavaScript中的arguments类数组对象模拟函数重载。当然,实际上JavaScript并不支持函数重载,比如通过检测arguments对象的length属性做出不同的反应来模拟重载。下面给出一个完整的例子。
【示例3-3】

以上代码的运行效果如图3.6所示。

图3.6 运行效果
【代码解析】
arguments对象是一个类数组对象。通过数组的slice()方法可以把arguments对象转化为一个真正的数组,这样就可以使用数组的所有方法,而不用担心出现其他问题了。

3.1.5 闭包
JavaScript中的变量可以分为全局变量和局部变量。JavaScript中的函数自然可以读取到全局变量,而函数外部并不能读取到函数内部定义的变量,例如:

当然,这需要在定义变量的时候使用var关键字定义。不用var关键字定义的话,实际上这个变量会成为全局对象的一个属性。在Node.js中,全局对象是global,如果上面代码中的str2变量不使用var定义,str2就会成为一个全局变量,函数外部也是可以读取到这个变量的,例如:

提示
建议所有的变量都使用var关键字进行定义,以避免不必要的错误出现。
JavaScript中的闭包可以让函数读取到其他函数内部的变量,如下代码就可以让函数之外读取到函数内部定义的变量,这就是最简单的闭包。
【示例3-4】

以上就是JavaScript的简要介绍。更多关于JavaScript的知识,读者可以阅读相关的书籍进行学习和掌握。进行Node.js的学习之前,读者应该对JavaScript有一定的了解。