本节将讨论如何使用JavaScript。我们知道,每个程序员编写程序的风格和惯例都不尽相同,因此在本书一开始,我想先说说我自己的编程风格和惯例,这样读者在后续章节中碰到更复杂一点的程序时,就不会感到疑惑了。本书并非一部JavaScript 新手教程,而是语言基本结构使用方法指南。 1.2.1 声明和初始化变量 JavaScript 中的变量默认是全局变量,严格地说,甚至不需要在使用前进行声明。如果对一个事先未予声明的JavaScript 变量进行初始化,该变量就成了一个全局变量。但本书遵循C++ 和Java 等编译型语言的习惯,在使用变量前先对其进行声明。这样做的好处是,声明的变量都是局部变量。本章稍后部分将详细讨论变量的作用域。 在JavaScript 中声明变量,需使用关键字var,后跟变量名,后面还可以跟一个赋值表达式。下面是一些例子: 1.2.2 JavaScript中的算术运算和数学库函数 JavaScript 使用标准的算术运算符: +(加) - (减) *(乘) /(除) %(取余) JavaScript 同时拥有一个数学库,用来完成一些高级运算,比如平方根、绝对值和三角函数。算术运算符遵循标准的运算顺序,可以用括号来改变运算顺序。 例1-1 演示了使用JavaScript 执行一些算术运算的例子,同时也用到了一些数学库中的函数。 例1-1 JavaScript 中的算术运算和数学函数 1.2.3 判断结构 根据布尔表达式的值,判断结构让程序可以选择执行哪些程序语句。本书用到的两种判断结构为if 语句和switch 语句。 if 语句有如下三种形式: 简单的 if 语句; if-else 语句; if-else if 语句。 例1-2 演示了如何编写简单的if 语句。 例1-2 简单的if 语句 例1-3 演示了if-else 语句。 例1-3 if-else 语句 例1-4 演示了if-else if 语句。 例1-4 if-else if 语句 本书用到的另外一个判断结构是switch 语句。在有多个简单的选择时,使用该语句的代码结构更加清晰。例1-5 演示了switch 语句的工作原理。 例1-5 switch 语句 这是解决该问题最高效的方式吗?不是,但是这个例子充分展示了switch 语句的工作原理。 JavaScript 中的switch 语句和其他编程语言的一个主要区别是:在JavaScript 中,用来判断的表达式可以是任意类型,而不仅限于整型;而C++ 和Java 等一些语言就要求该表达式必须为整型。事实上,如果你留意观察,上面那个例子中代表月份的数字其实是字符串类型。不用将它们转化成整型,就可以直接在switch 语句中使用。 1.2.4 循环结构 本书涉及的多数算法,从本质上都具有循环的特性。本书将用到两种循环结构:while 循环和for 循环。 如果希望在条件为真时执行一组语句,就选择while 循环。例1-6 展示了while 循环的工作原理。 例1-6 while 循环 如果希望按执行次数执行一组语句,就选择for 循环。例1-7 使用for 循环求整数1 到10 的累加和。 例1-7 使用for 循环求和 访问数组中的元素时,也经常用到for 循环,如例1-8 所示。 例1-8 使用for 循环访问数组 1.2.5 函数 JavaScript 提供了两种定义函数的方式,一种有返回值,一种没有返回值(这种函数有时也叫做子程或void 函数)。 例1-9 展示了如何定义一个有返回值的函数和如何在JavaScript 中调用该函数。 例1-9 有返回值的函数 例1-10 展示了如何定义一个没有返回值的函数,使用该函数并不是为了得到它的返回值, 而是为了执行函数中定义的操作。 例1-10 JavaScript 中的子程或者void 函数 JavaScript 中,函数的参数传递方式都是按值传递,没有按引用传递的参数。但是JavaScript 中有保存引用的对象,比如数组,如例1-10 所示,它们是按引用传递的。 1.2.6 变量作用域 变量的作用域是指一个变量在程序中的哪些地方可以访问。JavaScript 中的变量作用域被定义为函数作用域。这是指变量的值在定义该变量的函数内是可见的,并且定义在该函数内的嵌套函数中也可访问该变量。 在主程序中,如果在函数外定义一个变量,那么该变量拥有全局作用域,这是指可以在包括函数体内的程序的任何部分访问该变量。下面用一段简短的程序展示全局作用域的工作原理: function showScope() { return scope; } var scope = "global"; print(scope); // 显示"global" print(showScope()); // 显示"global" 函数showScope() 可以访问变量scope,因为scope 是一个全局变量。可以在程序的任意位置定义全局变量,比如在函数定义前或者函数定义后。 在showScope() 函数内再定义一个scope 变量,看看这时发生了什么: function showScope() { var scope = "local"; return scope; } var scope = "global"; print(scope); // 显示"global" print(showScope()); // 显示"local" showScope() 函数内定义的变量scope 拥有局部作用域,而在主程序中定义的变量scope 是一个全局变量。尽管两个变量名字相同,但它们的作用域不同,在定义它们的地方访问时得到的值也不一样。 这些行为都是正常且符合预期的。但是,如果在定义变量时省略了关键字var,那么一切都变了。JavaScript 允许在定义变量时不使用关键字var,但这样做的后果是定义的变量自动拥有了全局作用域,即使你是在一个函数内定义该变量,它也是全局变量。 例1-11 展示了定义变量时省略了关键字var 的后果。 例1-11 滥用全局变量的恶果 在例1-11 中,由于在showScope() 函数内定义变量scope 时省略了关键字var,所以在将字符串"local" 赋给该变量时,实际上是改变了主程序中scope 变量的值。因此,在定义变量时,应该总是以关键字var 开始,以避免发生类似的错误。 前面我们提到,JavaScript 拥有的是函数作用域,其含义是JavaScript 中没有块级作用域, 这一点有别于其他很多现代编程语言。使用块级作用域,可以在一段代码块中定义变量, 该变量只在块内可见,离开这段代码块就不可见了,在C++ 或者Java 的for 循环语句中, 经常可以看到这样的例子: for (int i = 1; i <= 10; ++i) { cout << "Hello, world!" << endl; } 这样做的原因是,我们不希望自己成为你养成坏编程习惯的帮手。 1.2.7 递归 JavaScript 中允许函数递归调用。前面定义过的factorial() 函数也可以用递归方式定义: 当一个函数被递归调用,在递归没有完成时,函数的计算结果暂时被挂起。为了说明这个过程,这里用一幅图展示了以5 作为参数,调用factorial() 函数时函数的执行过程: 本书讨论的一些算法采用了递归的方式。对于大多数情况,JavaScript 都有能力处理递归层次较深的递归调用(上面的例子递归层次较浅);但是保不齐有的算法需要的递归深度超出了JavaScript 的处理能力,这时我们就需要寻求该算法的一种迭代式解决方案了。任何可以被递归定义的函数,都可以被改写为迭代式的程序,要将这点牢记于心。
数据结构与算法JavaScript描述——1.2 JavaScript编程实践
书名: 数据结构与算法JavaScript描述
作者: [美] Michael McMillan
出版社: 人民邮电出版社
原作名: Data Structures and Algorithms with JavaScript
译者: 王群锋 | 杜 欢
出版年: 2014-8
页数: 216
定价: 49.00元
装帧: 平装
ISBN: 9787115363398