当前位置: 代码迷 >> JavaScript >> 雄辩的JavaScript第二章(经典通译计划1)
  详细解决方案

雄辩的JavaScript第二章(经典通译计划1)

热度:455   发布时间:2012-08-24 10:00:20.0
雄辩的JavaScript第二章(经典翻译计划1)

?

第二章:JavaScript基础:值,变量和控制流

?

在电脑世界中,只有数据:除数据之外的东西是不存在的。虽然,本质上,所有数据都是由0-1比特位组成的序列,但是每一块数据都有自身的作用。在JavaScript中这些数据被整齐地区隔为值,每一个值的类型决定了它可以扮演的角色,JavaScript中有6种基本类型的值:数、字符串、布尔值、对象、函数和undefined

?

创建一个值,你只需要创建它的名字。非常方便是吧!你不用去找创建值的材料,没有一点成本,仅仅召唤一句:我要一个值!嗖的一声,你就拥有了一个值。当然,这些值不是从真空中产生的,每一个值必须存放在某处,如果你在一个时间点进行大数量级地调用,很快电脑的内存将会被耗尽。不过还好,这种问题只会在同步调用大量的数据时发生,一旦你不再使用一个值了,它将会被驱散掉,留下几个比特的尸体,这些尸体会在下一轮值的创建中被回收利用。

?

?

数字类型的值,像下面这样表示,估计你已经知道了。

?

114

?

JavaScript控制台中输入它,同样的数字会在输出窗口中显示出来。过程这样的:你所输入的字面量被转化为了一个数字类型的值,然后JavaScript控制台将这个数值写回屏幕。做点练习?意义似乎不大,很快我们将会学到不用这么直接的方式去创建数值,那个时候再去JavaScript控制台中试试吧。

?

114的比特串是这个样子的:

?

0100000001100010000000000000000000000000000000000000000000000000

?

一共64个比特位。JavaScript的数值总是占用这个长度,所以可表达的数的范围在JavaScript中是有限的。3个十进制的数位,仅仅可以表示0999,一共10^3个数。64个二进制数码,2^64个数,其实已经很多了,比10^9还要大(1的后面跟190)。

?

当然并不是小于10^19的数都可以表示,因为还有负数呢!必须牺牲一个比特位来保存符号。问题来了,不是所有范围的数都可以表示,除此之外我们还要占用另外11个比特,去储存十进制数码间的小数点。

?

这么看来只剩下52位了。所以表示的范围小于2^52,这个数量级比10^15要大,这个范围内的数值在JavaScript中是安全的。在许多情形中,涉及到的整数都在这个范围内,所以我们完全不用在意这些比特的细节。还不错吧,但是我们没有对付比特位特别有效的办法,许多时候你还是需要它们来帮助你完成你的工作的,它们对表示大数特别有效果。

?

分数用一个小数点分隔:

?

9.81

?

对于特别大或者小的数,可以使用科学计数法表示,加上e并且在e后面跟上指数。

?

2.998e8

?

这个数表示2.998 × 10^8 = 299800000

?

如果整数计算结果可以用52bit表示,那么准确性是可以确保的。不幸的是,分数通常不那么准确。像π这样的无理数,无法用分数精确表示。许多数还会失去准确性,除非64bit都来存放它们。好尴尬的啊,但是这个问题通常只会在特别的场景中才会给你带来麻烦。注意它,是给你的一个提醒――总是把分数看做是近似值,不要把它们看做精确值。

?

?

通常我们用这些数来完成计算。像“加”或者“乘”这样的计算符,以两个数值作为操作数,并且产生一个作为结果的数值。JavaScript中应该这样使用:

?

100 + 4 * 11

?

+”和“*”被称为操作符。第一个符号代表加法,第二个代表乘法。将操作符放在两个数值之间,将会在这两个数值上产生作用,产生一个新的数值。

?

上面这个值代表计算4100的和,然后在乘以100吗,还是代表先乘后加?你一定猜到了,首先做乘法。在计算之中,可以通过括号改变计算的顺序。

?

(100 + 4) * 11

?

减法使用“-”操作符,除法使用“/”操作符。如果操作符同时出现,并且没有括号,计算将按照优先级进行。第一个例子说明乘法的优先级比加法高。完整的优先级应该这样描述:先乘除,后加减。

?

试着计算一下这个值,然后在JavaScript控制台中键入这个表达式,看看结果

?

115 * 4 - 4 + 88 / 2

?

不要担心优先级的问题。心里如果没有底,加个括号吧。

?

有个操作符,或许你还不是很熟悉。“%”是取模操作符。X % Y X 除以 Y后得到的余数。例如 314 % 100 1410 % 3 1144 % 120。取模运算的优先级在乘法和减法之间。

?

?

下面一种值的类型是字符串。如果仅仅从从名称上推断用途,没有数值那么显而易见,但是它非常的基础和重要。字符串用以表示一个文本,字符串值得名称来源于一系列字符组成一个串的事实。用双引号包裹字面内容,就可以得到一个字符串:

?

"Patch my boat with chewing gum"

?

似乎一切都可以包裹在双引号之中,JavaScript会以一个字符串来对待它们。但是一些字符很恶心。你不妨想想把双引号放到双引号中的样子。

?

换行符,也就是当你敲击回车后的效果,也不能放到引号之间,字符串必须是一行。

?

为了将这些恶心的字符放到字符串之中,我们要使用一个小技巧:一旦引号中出现了“\”那么他后面的内容就会有特殊的含义了。“\”后面的引号不代表字符串的结束,它是字符串的一部分。“\n”,会被解释为一个换行符;“\t”会被解释为一个制表符。

?

"This is the first line\nAnd this is the second"

?

当然如果希望只看到“\”也有办法,双写“\”就可以了。

?

"A newline character is written like \"\\n\"."

?

?

字符串上没有除法、乘法和减法操作。不过可以使用“+”操作符,“+”并不是执行加的操作,而是连接操作,它将两个字符串连接在一起:

?

"con" + "cat" + "e" + "nate"

?

还有许多操纵字符串的方法,接下来会慢慢介绍。

?

操作符并不是都是符号,有些操作符是字母。例如,typeof这个操作符,它会返回一个字符串结果说明你需要查询的值的类型。

?

typeof 4.5

?

这之前看到的操作符都是操作两个值,但是typeof只有一个操作数。我们把需要两个操作数的操作符称为二元操作符,只需要一个操作数的操作符称为一元操作符。减号既可以作为一元操作符,也可以作为二元操作符:

?

-(10 - 2)

?

?

还有一种值称为布尔类型。值只有两种:truefalse。下面展示了一种产生布尔值的方法:

?

3 > 2

?

当然,通过下面的方式可以产生false:

?

3 < 2

?

>”和“<”你应该早已了解,它们是二元操作符,结果产生的布尔值表示两个操作数是否满足这种关系。

?

字符串也可以加以比较:

?

"Aardvark" < "Zoroaster"

?

上面的字符串是按照字典顺序加以比较的。通常大写字母比小写字母小,所以"Z" < "a"将产生布尔值true。非字母字符(!,@等等)仍然有一定顺序,它们的比较通常是基于Unicode标准的。这个标准把字符映射为整数,当然也包含了希腊、阿拉伯、日本、泰米尔这些语言的字母。这种映射可以方便地将字符储存在电脑之中――通过一系列数字,就可以表示这些字母。当比较字符串时,JavaScript仅仅只需要从左到右比较这些数字。

?

"Itchy" != "Scratchy"

?

?

?

布尔值间实用的操作符也不少。JavaScript支持三个逻辑操作符:与、或、非。它们可以用以布尔运算。

?

&&”操作符表示逻辑与。它是一个二元操作符,当且仅当两个操作数为真时,结果才为真。

?

true && false?

?

||”操作符表示逻辑或,两个操作数中一个为真,结果就为真。

?

逻辑非用“!”表示,它是一个一元操作数,总是对给定的值取反。!truefalse!falsetrue

?

?

Ex.2.1?

((4 >= 6) || ("grass" != "green")) &&

!(((12 * 2) == 144) && true)

?

结果为真吗?为了代码的可读性,最好还是添加必要的括号,这样写是不是简单多了?

?

(4 >= 6 || "grass" != "green") &&

!(12 * 2 == 144 && true)

?

的确,最终值为真。你可以化简最后合并计算:

?

(false || true) && !(false && true)

?

true && !false

?

true

?

你注意到"grass" != "green"为真了吗?草的确是绿色的,但是不等于绿色。

?

?

需要括号的场景并不是显而易见的,检查所有的操作符是一种方法。“||”的优先级最低,然后是“&&”,(> ==)这些比较操作符要再高一些,然后是其他的操作符,记住这些原则,一切从简,括号越少越好。

?

?

到目前为止的所有例子,似乎把JavaScript当成了一个口袋计算器。输入一些数值,使用操作符,然后产生新的值。创建值在JavaScript中是必不可少的一部分,但是仅仅是一个部分。产生值的过程也被称为表达式计算。每一个直接写出的值也是表达式(例如22 或者 psychoanalysis”),当然括号里的部分也是表达式,一个二元操作符可以作用在两个表达式上,一元操作符可以作用在一个表达式上。

?

创建表达式有多种方法,后面会慢慢道来。

?

比表达式更大的单元是语句,程序是由语句组成的。语句以最好以“;”结尾。最简单的语句是一个表达式跟着一个分号。

?

1;

!false;

?

当然这个语句没有实际意义。表达式可以产生一个值,而语句足以通过量变的积累来改变世界。它可以在屏幕产生输出,多数时候会影响之后的语句。这些变化被称作“副作用”。上面的语句仅仅是产生1true,然后立刻将其置入比特桶之中,什么以不留下,当然也不产生副作用。

?

?

程序如何记录内部的状态?它是怎么记住发生过的事情?我们已经知道如何通过旧值产生新值,但是这样不会改变旧值,新值要么被立即使用,要么随后消失。为了捕获值,javascript有了变量的概念。

?

var caught = 5 * 5;

?

一个变量总是有一个变量名,它指向一个值,用以保持这个值。上面的语句创建了变量名为caught的变量,然后通过它捕获了由5 * 5产生的值。

?

上面的程序执行后,你可以再控制台输入caught,你可以重新得到25这个值。变量名用以引用和获得它所保存的值。caught + 1 一样可以正确执行。变量名可以作为一个表达式,也可以作为更大表达式的一部分。

?

var关键词用以创建一个变量。在var之后是变量名。几乎可以用任何词命名变量名,但是其中不可以包含空格。数字可以作为变量名的一部分,catch22是一个有效的变量名,但是不能以数字作为变量名的起始。“$”和“_”可以像字母一样表示变量名,$_$也是一个有效的变量名。

?

如果你希望新的变量立刻捕获一个值,可以通过赋值“=”操作符实现。

?

当一个变量指向一个值时,并不意味着永久的指向。任何时候,都可以通过赋值操作让变量指向一个新值。

?

caught = 4 *4;

?

你可以把变量名想象成触手而不是盒子。它们不包含任何值,但是可以抓住值,两个变量可以指向同一个值。当然只有活动状态下的变量才可以访问它指向的值。

?

当你需要存储某些东西时,你制造一个触角并持有它,或者用原有的触角指向新的值:为了记录Luigi欠你钱的金额,你可以这样做:

?

var luigiDebt = 140;

?

然后,每一次Luigi还你钱时,总是可以通过让变量指向一个新的的数值,来减少他欠你钱的总量:

?

luigiDebt = luigiDebt - 35;

?

某一个时刻,变量、值的集合被称为环境。只要程序开始执行,环境就不会为空。环境中总是包含了许多标准变量。当你的浏览器载入一个页面时,它会创建一个环境,并在环境中附属这些标准变量,直到载入新的页面,都可以创建和修改这些变量。

?

……

?

环境中许多标准变量都是函数类型的。函数就是把一系列代码包装到一个值中。这一系列代码可能非常有用,通过包含它们的函数名就可以调用这些代码。在浏览器中,alert变量持有一个现实包含了信息的对话框窗口的函数,可以这样使用:

?

alert("Also, your hair is on fire.");

?

执行函数中代码的过程被称作调用,调用的标志是使用括号。每一个产生函数值的表达式都可以在其后加上括号表示对它的调用。括号中的字符串值被传递到函数中,这个值就是要在对话框窗口中显示的文本。传递给函数的值被称作参数。alert只需要一个参数,其他函数可能需要更多。

?

……

?

显示对话框有一些“副作用”。一些函数之所以有用是因为它们产生了“副作用”。当然函数也会产生一个值,这样的情况之下不需要产生“副作用”。例如,Math.max这个函数,它接收两个参数,并且返回其中较大的一个:

?

alert(Math.max(2,4));

?

当一个函数产生一个值时,这个过程被称作返回“return”。因为产生值的函数总是JavaScript表达式,因此函数调用可以成为更大的表达式的一部分:

?

alert(Math.min(2,4) + 100);

?

第三章将讨论如何自定义函数。

?

……

?

如同上述的例子展示的那样,alert对于显示一些表达式的结果很有用。但是不停让用户点击这些对话框会让他们崩溃,从现在开始,我们探讨一些另外的机制,使用一个类似的函数――“print”。“print”不会弹出窗口,仅仅只是把值在JavaScript控制台中输出。“print”不是标准的JavaScript函数,浏览器不会把它提供给你,但是在这本书中,这样做是可行的,在下面这些页面中你可以这样使用:

?

print("N");

?

show也是一个相似的函数。print将以文本的形式显示参数,而show将会尽力显示参数在程序中的样子,传递更多关于值的类型的信息。当把文本传递给show时会一并带上引号:

?

show("N");

?

标准环境中提供了弹出窗口的其他一些方法。可以通过confirm函数询问用户可否。函数会返回一个布尔值,如果用户点击了是将返回true,反之,返回false

?

show(confirm("Shall we, then?"));

?

prompt用于询问开放式问题,第一个参数是询问的问题,第二个参数是用户键入文本前的默认字符。用户可以在窗口中键入一行字符串,函数最终会以一个字符串的形式返回它们。

?

show(prompt("Tell us everything you know.","..."));

?

……

?

赋予环境中每一个变量新的值是可行的。可能会很有用,但是很危险。当你把8传递给print后,它便再也不能工作了。幸运的是,通过JavaScript控制台上大大的重置按钮,你可以将环境恢复至初始状态。

?

……

?

每个程序如果只有仅仅一行代码,将会特别无趣。当你将多行语句放入一个程序中时,它们会以此从上到下的执行。

?

var theNumber = Numer(prompt("Pick a number",""));

print("Your number is the square root of " + theNumber * theNumber);

?

Number函数将一个值转化为一个数值,这所以这样使用是因为,prompt返回的是一个字符串 StringBoolean这两个函数也很相似,它们会把值转化成对应的类型。

?

……

?

下面考虑一个实际的问题,输出012的所有偶数。下面给出一种方法:

?

print(0);

print(2);

print(4);

print(6);

print(8);

print(10);

print(12);

?

可以达到目的,但是编程的精义是简化工作。如果目标变为输出1000一下的所有偶数,这个方法就不那么凑效了。我们需要的是一种自动地执行一系列代码段的方法。

?

var currentNumber = 0;

while (currentNumber <= 12) {

print(currentNumber);

currentNumber = currentNumber + 2;

}

?

在第一章中,你已经看到过while方法了。以while开始的语句完成循环的操作。循环放在一系列语句之中,它会使得程序代码被执行多次。在上面的代码中,while包含了括号中的表达式(当然表达式是必须的),用于控制循环的结束。当表达式产生的布尔值为true时,代码会被重复执行。一旦布尔值变为false,程序会跳出循环。

?

变量currentNumber的设置展示了一种通过一个变量跟踪程序进程的方法。每一次循环重复,这个变量会加2,每一次循环,在头部,都会和12做一个比较以此决定是否继续循环。

?

while语句的第三部分是另外一个表达式。是循环体,也就是需要多次执行的动作,如果我们不需要输出数,程序可以这样写:

?

var currentNumber = 0;

while (currentNumber <= 12)

currentNumber = currentNumber + 2;

?

在这里currentNumber = currentNumber + 2;这个表达式构成了循环体。如果输出这些数是必须的,那么循环体得包含多个语句。{ }用于构建代码块。从大括号外面看,代码块就如同一个语句。在上面的例子中,代码除了打印数值还完成更新currentNumber的工作。

?

?

练习2.2:通过上面介绍的方法,计算并输出2^10。不允许通过2*2*2...这样的方法。

?

如果觉得有困难,看以参照序号为偶数的例子。程序必须完成规定量的操作,while循环中的计数器用以确保操作的完成,程序用某个结果乘以2而不是输出计数器的值,某个结果也是一个变量,结果通过这个变量来产生。

?

如果你还未弄清楚细节,不要着急。即使你完全理解了这章中所有的技术,也不代表你可以顺利地解决这一章中出现的问题。阅读和编写代码可以培养解决问题的感觉,多研究解决方法,并且在下一个例子中联系一下。

?

var result = 1;

var counter = 0;

while (counter < 10) {

result = result * 2;

counter = counter + 1;

}

show(result);

?

计数器从1开始,并且通过小于等于10来作为判断。这样理解很容易,当然当你习惯了从0开始,将会是一个不错的选择。

?

显然,你的解决方法可能和我的不尽相同,能够解决问题就行,如果它们显得很难,那么理解我的解决方法是必须的。

?

?

练习2.3:通过一些微小的改动,上面例子中的程序就可以用来画三角形了。“三角形”是一些文本,只是你看上去觉得像三角形。

?

输出10行,第一行有一个“#”,第二行两个“#”,并以此类推。

?

如何让一个字符串中有X个“#”呢?一种解决方法是建立一个内循环――循环中的循环。一种更简洁的方式是利用上一次循环中产生的字符串,然后在其尾部加上一个字符。

?

var line = "";

var counter = 0;

while (counter < 10) {

line = line + "#";

print(line);

counter = counter + 1;

}

?

?

?

可能你已经注意到一些语句前的缩进了,缩进不是必须的:没有缩进计算机仍然可以很好地接受它们。实际上,换行也不是必须的。你可以随性把程序写成长长的一行。缩进的作用是使得代码的结构明晰、易读。程序块中会包含其他程序块,这样你会分不清是程序块开始还是结束,增加了缩进后,程序中的逻辑块会形成与之相一致的视觉单元。我喜欢用两个空格表示缩进,当然因人而异。

  相关解决方案