声明语句也叫变量语句,这种语句会建立新变量。能够在声明变量时给出初始值,若是没有明确给出,变量的值就是undefined。git
var count = 0; var dogs = ["Sparky","Spot","Spike"]; var response; var melta = {latitude:35.8,longitude:14.6}; var finished = false; var winner = null;
这段脚本明确给出了几个变量的初始值,事实上,除response
以外都有了初始值。这时候,变量response
的值就是undefined
。
能够在一个语句中声明多个变量,能够给部分变量赋初始值。程序员
var start = 0,finish = 72,input,output = [];
这个语句会将input初始化为undefined值。编程
表达式语句对表达式求值但,忽略获得的值。这听起来有点傻,由于能够编写出相似于下面的无用脚本;api
2+2; // 计算2+2,仅此而已 "hello"; // 也有效,但彻底没用 Math.sqrt(100); // 完成计算,也仅此而已 "a".toLowerCase(); // 获得一个新字符串,但忽略它
可是能够借助表达式的反作用来建立有用的语句,所谓"反作用",就是一些操做,能够生成可见结果、改变变量或对象属性中保存的值,或者修改对象的结构等。以前的delete
运算符与alert
和赋值同样,都会产生反作用数组
var x = 2; // 声明x,初始化为2 alert(x); // 显示2 alert(10*x); // 显示20 var y; // 声明y,但不明确赋值 alert(y); // 显示undefined
记住,变量声明和赋值就是简单地把一个值放到一个变量里,仅此而已。除此以外,没有任何其余后果,好比不会设定变量与变量之间的关系。在前面的脚本中,声明var z = y
不会让z和y成为同一个变量,也不会要求它们在以后始保存相同的值。这个语句意思仅仅是"新建一个变量z,让它的初始值等于y的当前值"。以后再给y从新赋一个新值时,z的值不会变。dom
JavaScript提供了一些语句和几个运算符,可让咱们编写的脚本在特定条件下执行一操做,在不一样条件下则执行另外一组操做。函数
if
语句if语句会根据你提供的条件,最多执行许多候选操做中的一种。这个语句的最通常形式是有一个if部分,0个或多个else if部分,还可根据须要带有else部分。每一个候选项都是大括号中的语句序列。这些条件会自上而下一次评估。只要一个条件为真,就会执行它对应的候选操做,而后结束整个if语句。工具
var score = Math.round(Math.random()*100); if (score>=90) { grade = "A"; } else if (score>=80) { grade = "B"; } else if (score>=70) { grade = "C"; } else if (score>=60) { grade = "D"; } else { grade = "F"; }; alert(score+" is a "+grade)
下图用一种UMKL(Unified Modeling Language,统一建模语言)活动图解读了上述语句。UML是一种很是流行的软件系统可视化语言。这张图传达的事实就是:会逐个检测每一个条件,一旦发现一个条件成立,就再也不进行测试。测试
if
语句,当变量s
没有包含长度为16
的字符串时,提示一条消息(注意,这个语句没有else if
或else
部分)var s = prompt("Enter a something"); if (s.length!==16) { alert("string length isn't 16") };
if
语句,检查变量x
的值,(1)若是x>0
,则将它加到数组变量values
的末尾;(2)若是x<0
,则将它加到values
的前面;(3)若是x===0
,则递增变量zeroCount
;(4)柔则,什么也不作。var values = []; var zeroCount = 0; var x = Number(prompt("Enter a number")); if (x>0) { values.push(x); } else if (x<0) { values.unshift(x); } else if (x===0) { zeroCount++; };
?:
条件表达式 有时你可能更喜欢使用条件表达式,而不是if语句。条件表达式就是"x?y:z"
,当x为真时,表达式的结果为y,当x为假时,表达式的结果为z。this
if (latitude>=0) { hemisphere = "north"; } else { hemisphere = "south"; } // 写为: hemisphere = (latitude>=0) ? "north" : "south";
条件表达式有时会用在构建字符串的表达式中,以下(这里的present假定是一个保存布尔值的变量:)
var notice = "She is "+(present? "" : "n't")+" here.";
switch
语句另外一种条件语句 —— switch
语句,将一个值一系列case
进行比较,知道找出一个与它的值相等(===
)的case
,而后从该处开始执行语句。能够根据须要包含一个default case
,它会匹配全部值。
switch (direction.toLowerCase()){ case "north" : row -= 1; break; case "south" : row += 1; break; case "east" : column += 1; break; case "west" : column -= 1; break; default: alert("Illegal direction"); }
break
语句会终止整个switch
语句。每种case
都以一个break
结束,这是一种很好的作法;不然
,执行会"直落"
到下一个case
(不会再与剩下的case表达式进行比较)。例如,上面的脚本咱们省略了break
,并且方向是"east"
,会发生什么状况呢?column
中的值会被递增,而后递减,而后弹出一个提示框,告诉你"east"
不是一个合法方向。
有时,"直落"正是咱们想要的。假定在一群参加竞赛的人中,每一个人都得到一个证书,但达到一级奖励的人还会获得一个背包,达到二级奖励的人还会获得一次滑雪度假,而达到三级奖励的人还会奖励一俩汽车。这种状况就可使用没有break语句的编码。
/* * 这个脚本会为一个给定奖励级别生别一组奖励 * 每一个奖励级别的参赛者会获得该级奖励和全部 * 低级奖励。它使用了一种很丑陋的switch语句 * 形式,其中的各个case之间没有相互距离。 */ var level = +prompt("Enter your prize level,1-3"); var prizes = []; switch (level){ case 3 : prizes.push("car"); case 2 : prizes.push("ski vacation"); case 1 : prizes.push("backpack"); default: prizes.push("certificate"); } alert(prizes);
一个具备直落效果的switch语句的活动图
像这样的计算不多会在现实中发生因此通常来讲,仍是避免使用那些不以break(或其余某一中断语句)结束的case,以防与switch更常见的形式混淆。事实上,以前介绍的JSLint代码质量检查工具就是将"直落"看做错误!咱们总能为直落switch找出替代方法。
来看一种情景,至少对于许多程序员新手来讲,这种情景彷佛是须要使用if
语句,?:
运算符或者switch
语句。假定有一个变量state
,保存德国一个州名,咱们但愿将这个州的首府名赋值给变量capital
,若是不能识别州名,则为其赋值undefined
。
// 丑陋的代码 —— 不要使用这一代码 if (state === "Baden-Wurttemberg") { capital = "Strttgart"; } else if (state = "Bayern") { capital = "Munchen"; } else if (state = "Berlin") { capital = "Berlin"; } else if (state = "Potsdam") { capital = "Potsdam"; } else if (state = "Bremen") { capital = "Bremen"; } else if (state = "Hamburg") { capital = "Hessen"; } else { capital = undefined; }
此代码对每一个州都重复两段内容:state ===
和 capital =
。switch语句能够消除前者,但必须为每一个州都增长一个break —— 没有实质性的改进。
// 丑陋的代码 —— 不要使用这一代码 switch (state){ case "Baden-Wurttemberg" : capital = "Stuttgart"; break; case "Bayern" : capital = "Munchen"; break; case "Berlin" : capital = "Berlin"; break; case "Brandenburg" : capital = "Potsdam"; break; case "Bremen" : capital = "Bremen"; break; case "Hamburg" : capital = "Hambrug"; break; case "Hessen" : capital = "Wiesbaden" break; default:capital = undefined; }
咱们将在第三次尝试中使用的条件表达式能够消除赋值的重复做用,但没法消除相等检测中的重复。
capital = (state === "Baden-Wurttemberg") ? "Stuttgart" : (state === "Bayern") ? "Munchen" : (state === "Berlin") ? "Berlin" : (state === "Brandenburg") ? "Potsdam" : (state === "Bremen") ? "Bremen" : (state === "Hamburg") ? "Hamburg" : (state === "Hessen") ? "Wiesbaden" : undefined;
咱们不能将全部重复片断排除在外,这必定意味着存在一种更好的方法来查找首府,事实上也的确存在。若是剔除了全部关于测试与赋值的内容,还剩下什么呢?就是州和首府!咱们并不须要什么精确的计算来将州和首府关联在一块儿,能够在数据而非代码中定义这种关系。咱们所须要的就是一个简单对象。
var CAPITALS = { "Baden-Wurttemberg" : "Stuttgart", "Bayern" : "Munchen", "Brandenburg" : "Potsdam", "Bremen" : "Bremen", "Hamburg" : "Hamburg", "Hessen" : "Wiesbaden" };
如今,只需写出:
capital = CAPITALS[state];
就能得到变量state
中所包含州的首府。能够认为这一代码是在一个由州及首府组成的表格中查询首府。在这样使用一个对象时,就说它是一个查询表、一个词典、一个映射、一个关联数组、或一个数列。查询表一般是将键映射到值(key = value
)。这里的州是键,首府是值。在适用时,查询代码要优于条件代码,缘由有以下几个。
没有冗余的代码片断,是脚本更短、更易于理解。
州和首府的显示位置紧挨在一块儿,更容易"看出"它们之间的关联。
代码(查询)和数据(查询表)在本质上是不一样的东西,不该当混放在一块儿。
JavaScript引擎执行查询的速度要远快与条件代码。
还有一个例子,咱们使用词典来关联手机键盘上的数字和字母。
为了将带有字母的电话号码转换为号码,咱们可使用:
var LETTER_TO_NUMBER = { A:2, B:2, C:2, D:3, E:3, F:3, G:4, H:4, I:4, J:5, K:5, L:5, M:6, N:6, O:6, P:7, Q:7, R:7, S:7, T:8, U:8, V:8, W:9, X:9, Y:9, Z:9 };
好比LETTER TO NUMBER["C"] === 2
。能不能在另外一个方向上使用这个映射呢?单个数字能够映射为多个字母,因此咱们将使用字符串:
var NUMBER_TO_LETTER = { 2:"ABC", 3:"DEF", 4:"GHI", 5:"JKL", 6:"MNO", 7:"PQRS", 8:"TUV", 9:"WXYZ" };
这里,咱们说:“给定一个数字n,NUMBER TO LETTER[n]”的值是一个字符串,其中包含了与键盘上的n相关联的全部字母(并且也只有这些字母)。”在后续介绍处理整个手机号码脚本时间,将会用到这些词典中的第一个。
用你本身的语言,说明能够用查询代替条件代码结构的情景(为以前的分数与成绩示例使用查询策略)
var score = { 100:"A", 99:"A", 98:"A", 80:"B", 85:"B", 89:"B", }; alert(score[100])
情景:查询电话归属地、邮编。元素周期表......
假定你注意到某一代码中存在表达式CAPITALS[Saarland]
。几乎能够确定它有什么错误?
可能存在语法错误,方括号运算符中若是不是变量,必须用引号括起
以前的布尔值一章中,若是x和y都是布尔值,则AND-ALSO和OR-ELSE运算符具备如下特性:
当且仅当x
或y
为真(或均为假)时,x || y
为真
当且仅当x
和y
均为真时,x && y
为真
if (t<0 && t>100) { /**执行某些操做**/ } // 与下面代码的含义彻底相同 if (t<0) { if (t>100) { /**执行某些操做**/ } }
若是第一部分的求值已经得到了足够多的信息,那就讲第二部分的求值短路,也就是跳过。
咱们如今明白AND-ALSO和OR-ELSE名字的原因了。
x and also y
就是说:若(if)x为真,则(then)(且仅在此时)去查看y是否也(also)为真。 x or else y
就是说:若(if)x为真,那很好;不然(else)必须去查看y是否为真。 第二部分根据条件决定是否求值。
alert(27 && 52); // 52 alert(0 && 52); // 0 alert(27 || 52); // 27 alert(0 || 52); // 52
换句话说,JavaScript不会将数字转换为布尔值。
x && y
的值,JavaScript首先对x
求值。若是x
为假(false
或能够转换为false
),则整个表达式得出x
的值(再也不计算y
)。不然整个表达式得出y
的值。x || y
的值,JavaScript首先对x
求值。若是x
为真(true
或能够转换为true
),则整个表达式得出x
的值(再也不计算y
)。不然,整个表达式得出y
的值。利用这一行为,能够编写一些小巧的代码。假定有一个变量favoriteColor
,咱们知道,若是你有最喜欢的颜色,这个变量就包含了这种颜色的名称,若是没有最爱的颜色,那它的值就是undefined。若是有喜欢的颜色,就用这种颜色为汽车喷漆,若是没有,则喷为黑色;
car.color = favoriteColor || "black";
这一行代码是有效的,由于favoriteColor
中包含了一个非空字符串,它为真,因此会为其指定car
的颜色。若是favoriteColor
为undefined
(为假),则根据定义,||
表达式的值就是它的第二个(右侧)操做数,也就是黑色。
对表达式 3 && "xyz" || null
求值。
首先对3 && "xyz"
求值,3
转换为true
,继续对右边表达式求值,为true
,形成 ||
短路,不对null
进行计算,返回"xyz"
对表达式3 && "" || null
求值。
首先对3 && ""
求值计算,空字符串转换为false
,而因||
须要,继续对右边表达式求值,返回null
判断正误:对于变量x
和y
,x && y
老是等同于x ? y : x
正确
首先对x求值,判断是否短路,x
为真,求值y
,x
为假,那只有x
已求值
判断正误:对于变量x
和y
,x || y
老是等同于x ? x : y
、
正确
首先对x求值,判断是否短路,x
为真,短路并返回,x
为假,继续求值y
上一节研究了不一样状况下作不一样事情的方法。如今来看一遍又一遍地重复同一事情的方法。
while
和do-while
语句JavaScript的while语句会在条件为真时重复执行代码。下面的例子要求用户输入一个恰有五个字符的字符串,并一直询问,知道用户遵照指令为止。当用户输入不知足要求时,脚本会计算尝试次数(并重复提示)。只有在输入了可接受的字符串时,while语句才会结束。
var numberOfTries = 1; while (prompt("Enter a 5-charater string").length !== 5){ numberOfTries += 1; } if (numberOfTries>1) { alert("Took you "+numberOfTries+" tries to get this right"); }
while语句的通常形式为:
while (test) { stmts }
首先执行第一个test,若是它为真,则执行循环体,重复整个语句。这就是说,条件测试出如今循环体以前,循环体可能一次也不会执行。而在do-while语句中国,循环体至少会执行一次。通常形式为:
do {stmts} while (test)
能够用do-while语句重写以上脚本:
var numberOfTries = 0; do { var input = prompt("Enter a 5-character string"); numberOfTries++; } while (input.length!==5); if (numberOfTries>1) { alert("Took you "+numberOfTries+" tries to get this right"); }
for
语句第二种循环 —— for
语句,也就是在条件为真时一直循环,但它一般用于迭代遍历一个固定的项目集,好比一个数值范围、一个字符串中的字符、一个数组的索引、一个对象链,等等。这个语句通常形式是:
for (init ; test ; each) {stmts}
JavaScript引擎首先运行init代码,而后,只要test为真,则运行循环体,而后运行each。init部分一般会声明一或多个变量(但并不是老是如此)。
// 显示4,6,8,10,...,20为偶数 for (var Number=4;Number<=20;Number+=2) { alert(Number+" is even ") }
这里number被初始化为4,并且由于它小于等于20,因此将提示"4 is even",而后将number直接设置为6,接下来将显示"6 is even",number变为8。最后显示20,由于最后number将跳到22,条件为false。
在处理数组时会使用for语句。下面例子中,处理一个单词列表,也就是字符串words[0]、words[1]、words[2],等等。如何"逐步遍历"这个列表呢?能够建立一个变量i,它会在每次的迭代中递增1.
// 显示一个字符串,又每一个数组项目的首个字母组成 var words = ["as","far","as","i","know"]; var result = ""; for (var i=0;i<words.length;i++) { result += words[i].charAt(0).toUpperCase(); } alert(result); // 为何使用i,由于数组元素索引(index),因而使用其首字母,一个传统了。
下面是一个另外一个与数组有关的例子,它演示了一种常见模式,用于检查每一个数组元素,看它是否知足某一条件。 // 显示一个数组中的0的个数
var a = [7,3,0,0,9,-5,2,1,0,1,7]; var numberOfZeros = 0; for (var i=0,n=a.length;i<n;i++) { if (a[i]===0) { numberOfZeros++; } } alert(numberOfZeros);
注意这个示例还演示了如何在for循环的初始化部分声明两个变量
。将n初始化为数组的长度,循环终止检测变得简单一点。
除了迭代数值范围和数组元素以外,for语句还常常用于迭代一个字符串中的各个字符。
若是字符是数字,则直接"将它传送"给结果字符串
若是字符在A~Z之间,则查找对应的手机键盘数字,并传送该数字。
若是字符是其余内容,则忽略它。
var LETTER_TO_NUMBER = {A:2,B:2,C:2,D:3,E:3,F:3,G:4,H:4,I:4,J:5,K:5,L:5,M:6,N:6,O:6,P:7,Q:7,R:7,S:7,T:8,U:8,V:8,W:9,X:9,Y:9,Z:9}; var phoneText = prompt("Enter a phone number (letters permitted)").toUpperCase(); var result = ""; for (var i=0;i<phoneText.length;i++) { var c = phoneText.charAt(i); if (/\d/.test(c)) { result += c; } else if (c in LETTER_TO_NUMBER) { result += LETTER_TO_NUMBER[c]; } } alert("The phone number is: "+result);
在迭代另外一类序列时也常常看到for循环:对象的连接结构
var scores = { score:29, next:{ score:99, next:{ score:47, next:null } } }; var total = 0; for (var p=scores;p!=null;p=p.next) { total += p.score; }; alert(total);
p
引用了对象scores
,并将p.score
属性运算后赋值给变量total
,而且每次执行完代码块后,p
引用的对象的属性变为p.next.score
,下一次就是p.netx.next.score
(scores.next.score
→scores.next.next.score
)下一个例子,演示嵌套循环。
var SIZE = 9 ; document.write("<table border='1' cellspacing='0'>") for (var i=1;i<=SIZE;i++) { document.write("<tr>") for (var j=1;j<=SIZE;j++) { document.write("<td>"+i*j+"</td>"); } document.write("<tr>") } document.write("</table>")
for (var i=10;i>=0;i--) { console.log(i); }
var i = 10; while (i!==-1){ console.log(i); i--; }
for (var i=1,n=1;i<21;i++) { n *= i; console.log(n); };
for-in
语句JavaScript包含一个迭代对象属性名的语句。这门语言将这一操做称为属性名的枚举。
var dog = { name:"Lisichka", breed:"G-SHEP", birthday:"2011-12-01" }; for (var p in dog) { alert(p) } // name breed birthday
这个脚本将生成三条提示:一个给出name,一个给出breed,一个给出birthday。这些属性的出现顺序是任意的。试试另外一个对象:
var colors = ["red","amber","green"]; for (var c in colors) { alert(c) } // 0 1 2
枚举是对属性名进行的,不是针对值。变量colors引用的对象的属性名是0、一、2和length。可是,在运行这一代码时,你只会看到显示了0,1,2。为何没有length?
其实,一个对象的每一个属性,除了拥有值之外,还有几个特性(attribute)。
// 特性 在为真时的含义 writable 属性的值能够修改 enumerable 这个属性将出如今属性的for-in枚举中 configurable 能够从其对象中删除这个属性,它的特性值是能够改变的
凑巧,数组的length属性的enumerable特性被设置为false。由前面的例子知道,它的writable特性为true。
修改与狗有关的小脚本,提示如下内容:必须用for-in语句生成这些提示,并用object[property]符号提示属性值。
var dog = {name:"Lisichka",breed:"G-SHEP",birthday:"2011-12-01"}; for (var i in dog) { document.write("The dog's "+i+" is "+dog[i]+"<br />") } // dog[property]注意property是字符串类型,而不是变量。
一般,语句都是按顺序一次执行一条。条件语句和迭代语句会稍微偏离这种有时被称做直线式代码的形式,但这种偏离是语句结构自己决定的,很容易识别。但还四种语句的结构化不是这么强,他们对控制流的效果是中断性的。有这些:
break
,当即放弃执行当前正在执行的switch
或迭代语句;continue
,当即放弃一个迭代语句中当前迭代的剩余部分;return
,当即放弃当前执行的函数;thorw
,将在后面介绍;break
和continue
break语句将当即终止整个循环。在搜索数组(或对象链),这一语句特别有用,它会在你找到正在查找的内容以后当即终止搜索。
// 查找第一个偶数的索引位置 for (var i=0;i<array.length;i++) { if (array[i]%2===0) { alert("Even number found at position "+i); break; } }
continue语句当即开始循环的下一次迭代,而不在完成当前迭代。当循环中的一些(而非所有)迭代生成有用信息时,这一语句很是有用。continue语句就是说“嗨,此次迭代里没有什么要作的事情了,我立刻要开始下一次迭代了”。
// 计算一个数组中全部正数值之和 var array = [-1,3,12,3,-23,-23,-2,0,1,-12]; if (array[i]<=0) { continue; // 跳过非正数 } sum += array[i]; } alert("Sumof positives is "+sum)
恰好我在MDN里找到了一些文档MDN-JS-break语句
那位社友的问题在于,在while循环中,当i=4
时,就continue
跳过了自增操做,按照MDN的说法,它将回到条件继续执行,这便成了一个死循环。而在for循环就直接each更新表达式了。
接下来写一个脚本:用户输入一个数字,判断是否为质数。
var SmallLest = 2; var BigGest = 9E15; var n = prompt("输入一个数字"); var condition = isNaN(n) || n % 1 !== 0 || n < SmallLest || n > BigGest; if (condition) { alert("只能判断2~9e15之间的整数"); } else { var foundDivisor = "是"; // default,是质数 for (var k = 2,last = Math.sqrt(n);k <= last;k++) { if (n%k === 0) { // 2 ~ Math.sqrt(n)之间任何一个数能够整除n,则不是质数 foundDivisor = "不是"; break; } } } alert(n+" 是否为质数? "+" : "+foundDivisor);
最后一个关于break和continue的示例要研究一个问题:如何中断外层循环?一种方法是对循环进行标记,而后在break语句中说起这个标记。假定有一个对象纪录了一组人选择的彩票信息。
var picks = { Alice:[4,52,9,1,30,2], Boris:[14,9,3,6,22,40], Chi:[51,53,48,21,17,8], Dinh:[1,2,3,4,5,6], };
另外,假定咱们但愿知道是否有人选择了数字53。能够依次查看每一个人选择的数字,但只要找到53,就但愿中止整个搜索,而不仅是终止对当前人员选择数字的扫描。
var picks = { Alice:[4,52,9,1,30,2], Boris:[14,9,3,6,22,40], Chi:[51,53,48,21,17,8], Dinh:[1,2,3,4,5,6], }; var found = false; Search:for (var person in picks) { var choices = picks[person]; for (var i=0;i<choices.length;i++) { if (choices[i]===53) { found = true; break Search; } } }
重写计算数组例子,改成使用break语句。
// continue重写:计算一个数组全部正数值之和 var num = [1,3,4,-2,-12,-3,0,-3,-1]; var sum = 0; for (var i=0;i<num.length;i++) { if (num[i]<0) { break; // break后,回到条件更新表达式,这里是自增 }; sum += num[i]; } alert(sum)
bug
。若是幸运(竟然叫幸运 - -)的话,仍是能看到输出结果,并会想到“这个结果不可能正确”,而后再去复查脚本,纠正错误。崩溃
alert("Welcome to my script"); var message = printer+1; alert("The script is now ending")
在脚本运行时,出现第一次提示,但因为第二条语句须要一个未声明变量printer的值,因此引擎会抛出异常。由于这一异常未被捕获,因此整个脚本都将被放弃,最后一条提示永远不会被执行。
除了使用未声明变量这种状况外,还有哪些错误会被看做错误,并致使JavaScript抛出异常呢?
RangeError
)null
值中读取属性(TypeError
),由于只有对象拥有属性,JavaScript不能将null
转换为对象SyntaxError
)var a = [10,20,30]; a.length = -5; // "Uncaught RangeError: Invalid array length" var a = null; alert(a[3]); // "Uncaught TypeError: Cannot read property '3' of null" alert(3/-) // "Uncaught SyntaxError: Unexpected token )"
咱们可使用JavaScript的throw
语句在本身的代码中显式的抛出异常。能够抛出本身想要的任何值;在下面的例子中,将抛出一个字符串:
alert("Welcome to my script") throw "Ha ha ha"; // "Uncaught Ha ha ha" alert("You will never see this message")
咱们提到,未捕获的异常会致使脚本崩溃。要捕获异常,可使用try-catch语句。
try { // 这是一我的为设计的示例,只说明了一个点 alert("Welcome to my script"); throw "Ha ha ha"; alert("You will never see this script"); } catch(e) { alert("Caught : "+e); }
catch子句将一个变量(在本例中是e,这是一个至关常见的选择)初始化(或理解为将抛出的值赋值给e?)为被抛出的值。在实践中,许多JavaScript程序员都须要抛出带有各类属性的对象,用以提供一些信息,用以提供一些信息,来为其描述抛出此异常的问题。例如:
throw {reason:"class full",limit:20,date:"2012-12-22"} // "Uncaught #<Object>"
异常为特定的编程问题提供了很是天然的解决方案。只要你意识到,利用你当前拥有的数据,一个计算不能正常进行,那就应该抛出异常。
和大多数程序设计特性同样,异常也可能被滥用。下面这个脚本要求用户从三扇分别标有1,2,3的门中选择一扇,并赢得藏在这扇门以后的奖励。
// 若是没有异常这将是更好的一个脚本 try{ var PRIZES = ["a new car","a broken stapler","a refrigerator"]; var door = prompt("Enter a door number(1,2,or3)"); var prize = PRIZES[door-1]; alert("You have won "+prize.toUpperCase()+"!!"); }catch(e){ alert("Sorry, no such door.") }
若是用户输入除1,2,3以外的任何值,prize
的值都将是undefined,对undefined
调用toUpperCase
将会抛出一个异常。这个异常被捕获,并报告一条错误。这一点很难经过研究代码来发现,所以,咱们说这一脚本的逻辑有些费解。他依赖于咱们调用toUpperCase这一事实,它与输入无效门牌号的"问题"没有什么关系!咱们最后用一个简单的if语句当即核实输入。
正数除0结果为Infinity,负数除0为-Infinity,0除以0为NaN。
var PRIZES = ["a new car","a broken stapler","a refrigerator"]; var door = prompt("Enter a door number(1,2,or3)"); if (door==1 || door==2 || door==3) { alert("You have won "+PRIZES[door-1]+"!!"); } else { alert("Please Input number 1,2or3") }
咱们已经给出了如下通常形式的if
、while
、do-while
、for
和for-in
语句
if (test) { stmts } if (test) { stmts } else { stmts } if (test) { stmts } else if (test) { stmts } if (test) { stmts } else if (test) { stmts } else { stmts } while (test) { stmts } do { stmts } while (test); for (init;test;each) { stmts } for (var variable in object) { stmts }
但事实上,上面使用语句序列(放在大括号)的位置,JavaScript都容许使用单个语句,下面这种写法彻底合法;
if (count === 0) break; // 或者 if (count === 0) break; // 但不必定是最好的 if (count === 0) { break; }
从技术角度来讲,任何一个放在大括号中的语句序列,其自己就是单条语句,成为块语句。所以,在任何须要使用单条语句的地方均可以使用块语句,但在实践中,若是只是为了使用块语句而使用块语句,看起来会很傻。下面的脚本虽然有点傻,确实合法的;
{{{{alert("Hello");}}}}
咱们还强烈建议,应当始终使用块语句来构建这两种语句
,哪怕简短形式能够减小键入工做。主要理由以下:// 下面的脚本显示数字0至9的平方 for (var i=0;i<=10;i++) { alert(i+" squared is "+(i*i)) };
程序员决定向循环体中添加一条语句,定义一个新变量,用来保存计算所得的平方,但却忘了添加大括号
for (var i=0;i<10;i++) var square = i * i; alert(i+" squared is "+square);
由于for循环体老是跟在控制表达式(放在小括号)以后的单条语句,因此这个脚本声明了变量square,并重复为它赋值,最后一次为81.在for语句完成以后将出现提示。这时,i的值为10,因此整个脚本给出单条提示:10 squared is 81,若是养成了符合语句中使用大括号的习惯,就永远不会犯这样的错误。
仅在if语句和迭代语句中使用块语句,并且在这两种语句中也总要使用块语句
官方的JavaScript定义声明,如下语句应当以分号(;)结束:变量声明语句、表达式语句(包括赋值)、do-while语句、continue语句、break、return语句和throw语句。
可是这门语言的设计者容许程序员根据本身的一元省略语句末尾的分号,依靠JavaScript引擎来指出哪一个地方应当有分号。遗憾的是,这一规则下降了咱们将长语句分跨在多行代码的灵活性。关于处理缺失分号的技巧细节,可在官文中找到。
当你尝试使用一个还没有声明的变量时,JavaScript引擎会抛出一个异常。可是,若是尝试为一个未声明的变量赋值,JavaScript会自动为你声明这个变量。
// 假定变量next_song历来没有声明过 next_song = "Purple Haze";
这个脚本不会抛出异常!许多人可能会说它应该抛出异常的,许多专家认为这个隐式声明是语言设计缺陷。在赋值中意外地错误拼写一个变量名,会致使一个新变量的声明,它不一样与你原本想要赋值的变量。这个脚本将一直运行,只到发生了某些“跑偏道路”的事情,是错误很难查找。若是引擎在赋值时抛出异常,哪会更好一些,由于这个错误的侦测就很容易了。
千万不要依赖这一“功能“,JSLint很明智的将它的应用报告为错误。
递增和递减运算符
var x = 5; x++; // x:6 var y = x++; // y:6 x:7 等号右结合 var z = ++x; // x:8 z:8 var w = ++y + z++; // y:7,w:15,z:9
=
右侧开始计算,最后赋值给变量x
。x:5
x
(使用x),最后再进行自增。x:6
=
、后置++
,后置自增无结合性,则先赋值(使用x)y:6
,后自增x:7
=
、++前置
,二者结合性都是右结合,则先自增x:8
,后赋值z:8
=
、前置++
、+
、后置++
,加括号应该是:(var w = ((++y) + z))++
,先对前置自增运算y:7
,然先使用z
与y
相加w:15
,赋值给变量w
,最后z
才自增。因此y:7,w:15,z:9