锦方的个人网页 · 如果有一天你突然想起了我


学习JavaScript笔记「3」

目录

循环进行重复操作

html代码:

<!DOCTYPE html>
<html>
<head>
  <title>Make Your Own Bingo Card</title>
  <link rel="stylesheet" href="script01.css">
  <script src="script01.js"></script>
</head>
<body>
<h1>Create A Bingo Card</h1>
<table>
  <tr>
    <th>B</th>
    <th>I</th>
    <th>N</th>
    <th>G</th>
    <th>O</th>
</tr>
<tr>
    <td id="square0">&nbsp;</td>
    <td id="square5">&nbsp;</td>
    <td id="square10">&nbsp;</td>
    <td id="square14">&nbsp;</td>
    <td id="square19">&nbsp;</td>
</tr>
<tr>
<td id="square1">&nbsp;</td>
    <td id="square6">&nbsp;</td>
    <td id="square11">&nbsp;</td>
    <td id="square15">&nbsp;</td>
    <td id="square20">&nbsp;</td>
</tr>
<tr>
    <td id="square2">&nbsp;</td>
    <td id="square7">&nbsp;</td>
    <td id="free">Free</td>
    <td id="square16">&nbsp;</td>
    <td id="square21">&nbsp;</td>
</tr>
<tr>
    <td id="square3">&nbsp;</td>
    <td id="square8">&nbsp;</td>
    <td id="square12">&nbsp;</td>
    <td id="square17">&nbsp;</td>
    <td id="square22">&nbsp;</td>
</tr>
<tr>
    <td id="square4">&nbsp;</td>
    <td id="square9">&nbsp;</td>
    <td id="square13">&nbsp;</td>
    <td id="square18">&nbsp;</td>
    <td id="square23">&nbsp;</td>
    </tr>
</table>
<p><a href="script01.html" id="reload">Click here</a> to create a new card</p>
</body>
</html>

标  签 意  义 table 在网页上显示表格数据 tr 在表格中开始一行 th 表格中列的标题单元格 td 包含表格中的每个单元格

Css代码:

body {
  background-color: white;
  color: black;
  font-size: 20px;
  font-family: "Lucida Grande", Verdana,Arial, Helvetica, sans-serif;
}

h1, th {
  font-family: Georgia, "Times New Roman",Times, serif;
}

h1 {
  font-size: 28px;
}

table {
  border-collapse: collapse;
}
th, td {
  padding: 10px;
  border: 2px #666 solid;
  text-align: center;
  width: 20%;
}

#free, .pickedBG {
  background-color: #f66;
}

.winningBG {
  background-image:url(images/redFlash.gif);
}

JavaScript循环:

window.onload = initAll;

function initAll() {
  for (var i=0; i<24; i++) {
    var newNum = Math.floor(Math.random() * 75) + 1;

    document.getElementById("square" + i).innerHTML = newNum;
  }
}
for (var i=0; i<24; i++) {
这一行开始循环。通常使用变量i作为循环内部的计数器变量。首先,将i设置为0。分号表示这个语句结束了,这使我们能够在同一行上放置另一个语句。下一部分的意思是,“如果i小于24,那么执行花括号中的代码”。第二个分号后面的部分将i的值加1。因为这是第一次用到递增,++操作符将i的值加1。这个循环将重复24次,所以循环中的代码将执行24次。在第一次迭代中,i是0;在最后一次迭代中,i是23。
var newNum = Math.floor(Math.random() * 75) + 1;

在循环内部,我们创建一个新的变量newNum,并将它赋值为等号右边计算的结果。内置的JavaScript命令Math.random()生成0~1的一个随机数,比如0.123456789。将Math.random()与最大值相乘(请记住,Bingo卡片中的值是从1到75)会生成0到最大值之间的结果。对结果进行floor运算会获得结果的整数部分,即0到(最大值减1)的整数。再加1就会获得1到最大值的数字。

document.getElementById("square" + i).innerHTML = newNum;

在这里,将刚才获得的随机数写入表格中。我们处理的元素的id属性是square再拼接上i的当前值。例如,在循环的第一次迭代中,i的值是0,所以这一行处理id为square0的元素。这一行将square0对象的innerHTML属性设置为newNum的当前值。

对象探测

window.onload = initAll;

function initAll() {
  if (document.getElementById) {
    for (var i=0; i<24; i++) {
      setSquare(i);
    }
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
}
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var newNum = Math.floor (Math.random() * 75) + 1;
  document.getElementById(currSquare).innerHTML = newNum;
}
if (document.getElementById) {

这是条件语句的开头。如果对象存在,if语句就为true,脚本继续执行。但是,如果浏览器不理解这个对象,测试就返回false,并执行条件语句的else部分。

else {
 alert("Sorry, your browser doesn’t support this script");
}

测试返回false,这一行就会弹出警告框,脚本结束运行。

处理数组

window.onload = initAll;

function initAll() {
  if (document.getElementById) {
    for (var i=0; i<24; i++) {
     setSquare(i);
    }
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace [thisSquare] * 15;
  var newNum = colBasis + Math.floor (Math.random() * 15) + 1;
    document.getElementById(currSquare) innerHTML = newNum;
}
var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);

我们希望限制哪些随机数可以放在哪一列中。最简单的方法是给每一列分配一个编号(B:0,I:1,N:2,G:3,O:4),然后用以下表达式计算可以放进每一列中的数字:(列号×15)+(1~15的随机数)。 要用colPlace数组记录每个格子所属的列。它包含0~4的数字并重复五次(要减去空的格子。请注意,数字2仅用了4次)。

var colBasis = colPlace[thisSquare] * 15;
var newNum = colBasis + Math.floor(Math.random() * 15) + 1;

我们首先计算列号:存储在colPlace[thisSquare]中的数字乘以15。newNum变量仍然生成随机数,但不是1~75的数字,而是计算一个1~15的随机数,然后加上列号。因此,如果随机数是7,那么它在B列中是7,在I列中是22,在N列中是37,在G列中是52,在O列中是67。

在运行时更新数组

这个Bingo卡片脚本还无法确保给定的列中不出现重复的数字。这个示例要纠正这个问题,同时说明数组不必进行初始化并读取,而是可以在运行时声明和设置它们。这会提供很大的灵活性,因为可以在脚本运行时通过计算或函数修改数组中的值。

将数组的内容改为存储当前值:

window.onload = initAll;
var usedNums = new Array(76);

function initAll() {
  if (document.getElementById) {
    for (var i=0; i<24; i++) {
      setSquare(i);
    }
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}
function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace [thisSquare] * 15;
  var newNum = colBasis + getNewNum() + 1;

  if (!usedNums[newNum]) {
    usedNums[newNum] = true;
    document.getElementById(currSquare).innerHTML = newNum;
  }
}

function getNewNum() {
  return Math.floor(Math.random() * 15);
}
var usedNums = new Array(76);

这是一种声明数组的新方法。将usedNums变量声明为一个包含76个对象的新数组。正如前面提到的,这些对象可以是任何东西。在这个示例中,它们是布尔值,即true/false值。

if (!usedNums[newNum]) {
    usedNums[newNum] = true;

如果usedNums数组中的newNum位置上是false(表达式前面的!表示“非”),那么就将它设置为true,并将newNum写到卡片上。如果newNum位置上是true,就什么也不做。这样就不会有重复的数字。

使用do/while循环

有时候,需要让代码循环许多次,但是无法确定需要循环多少次。在这种情况下,就要使用do/while循环:只要某个条件为true,就执行某种操作。

防止给定的列中出现重复的数字:

window.onload = initAll;
var usedNums = new Array(76);

function initAll() {
  if (document.getElementById) {
    for (var i=0; i<24; i++) {
     setSquare(i);
    }
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace [thisSquare] * 15;
  var newNum;

  do {
    newNum = colBasis + getNewNum() + 1;
  }
while (usedNums[newNum]);

  usedNums[newNum] = true;
  document.getElementById(currSquare). innerHTML = newNum;
}

function getNewNum() {
  return Math.floor(Math.random() * 15);
}

1.var newNum; 我们在创建newNum变量时对它进行初始化。因为我们将多次设置它,所以在进入循环之前创建它,这样只需创建一次。

2.do { 这一行开始do代码块。关于这种循环必须记住的一点是,do块中的代码至少会执行一次。

3.newNum = colBasis + getNewNum() + 1; 与前面的示例一样,循环中的这行代码将newNum变量设置为我们需要的数字。

4.} 右花括号标出do块的结尾。

5.while (usedNums[newNum]); while检查会使do代码块反复执行,直到检查结果为false为止。在这个示例中,我们检查usedNums[]数组中newNum位置上的值,从而检查newNum是否已经使用过了。如果这个数字已经用过了,控制就被传递回do块的开头,整个过程再次重复。最终,我们会找到一个没有使用过的数字。在此之后,就会离开循环,将usedNums设置为true,并将newNum写到卡片上。

让用户自己运行脚本

window.onload = initAll;
var usedNums = new Array(76);

function initAll() {
  if (document.getElementById) {
    document.getElementById("reload").onclick = anotherCard;
    newCard();
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function newCard() {
  for (var i=0; i<24; i++) {
    setSquare(i);
  }
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace thisSquare] * 15;
  var newNum;

  do {
    newNum = colBasis + getNewNum() + 1;
  }
  while (usedNums[newNum]);

  usedNums[newNum] = true;
  document.getElementById(currSquare).innerHTML = newNum;
}

function getNewNum() {
  return Math.floor(Math.random() * 15);
}

function anotherCard() {
  for (var i=1; i<usedNums.length; i++) {
    usedNums[i] = false;
  }
  newCard();
  return false;
}
document.getElementById("reload").onclick = anotherCard;
newCard();

让它在被单击时调用anotherCard()。initAll()函数中原来的所有计算现在被转移到新的newCard()函数中,这里只需调用newCard()函数,newCard()函数中没有新代码。

function anotherCard() {
 for (var i=1; i<usedNums.length; i++) {
  usedNums[i] = false;
 }

 newCard();
 return false;
}

这是anotherCard()函数,当用户单击链接时会调用这个函数。它执行3个操作: 1、将usedNums[]数组中的所有元素设置为false(这样就可以重新使用所有数字); 2、调用newCard()函数(生成另一个卡片); 3、返回false值,使浏览器不尝试加载链接的href中指定的页面。

组合使用JavaScript和CSS

通过JavaScript添加一个类,使代码可以利用CSS的功能

window.onload = initAll;
var usedNums = new Array(76);

function initAll() {
  if (document.getElementById) {
    document.getElementById("reload").onclick = anotherCard;
    newCard();
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function newCard() {
  for (var i=0; i<24; i++) {
    setSquare(i);
  }
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace [thisSquare] * 15;
  var newNum;

  do {
    newNum = colBasis + getNewNum() + 1;
  }
  while (usedNums[newNum]);

  usedNums[newNum] = true;
  document.getElementById(currSquare).innerHTML = newNum;
  document.getElementById(currSquare).className = "";
  document.getElementById(currSquare).onmousedown = toggleColor;
}

function getNewNum() {
  return Math.floor(Math.random() * 15);
}

function anotherCard() {
  for (var i=1; i<usedNums.length; i++) {
    usedNums[i] = false;
  }
  newCard();
  return false;
}

function toggleColor(evt) {
  if (evt) {
    var thisSquare = evt.target;
  }
  else {
    var thisSquare = window.event.srcElement;
  }
  if (thisSquare.className == "") {
    thisSquare.className = "pickedBG";
  }
  else {
    thisSquare.className = "";
  }
}
document.getElementById(currSquare).className = "";
document.getElementById(currSquare).onmousedown = toggleColor;

因为Bingo卡片是可以重复使用的,所以要确保Bingo卡片最初是空的:对于在setSquare()中设置的每个格子,把class属性设置为""(空字符串),并让onmousedown事件处理程序调用新的toggleColor()函数。

function toggleColor(evt) {

在新的toggleColor()函数中就要使用这些样式了。用户现在可以单击卡片上的任何格子,这个格子的背景颜色就会改变,表示这个号码已经被叫过了。

if (evt) {
var thisSquare = evt.target;
}
else {
var thisSquare = window.event.srcElement;
}

首先,需要查明单击的是哪个格子。 如果一个称为evt的值被传递给这个函数,就说明用户的浏览器不是IE,可以看到evt的目标。如果浏览器是IE,就需要查看window对象的event属性的srcElement属性。无论采用哪种方式,都会得到thisSquare对象,然后可以检查和修改这个对象。

if (thisSquare.className == "") {
 thisSquare.className = "pickedBG";
}
else {
 thisSquare.className = "";
}

在这里,检查被单击的格子的class属性是否有一个值。如果没有,就给它设置pickedBG值,因为格子的背景表示这个数字已经被选择了。

检查状态

使用复杂的数学计算判断获胜组合:

window.onload = initAll;
var usedNums = new Array(76);

function initAll() {
  if (document.getElementById) {
    document.getElementById("reload").onclick = anotherCard;
    newCard();
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function newCard() {
  for (var i=0; i<24; i++) {
    setSquare(i);
  }
}

function setSquare(thisSquare) {
  var currSquare = "square" + thisSquare;
  var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
  var colBasis = colPlace [thisSquare] * 15;
  var newNum;

  do {
    newNum = colBasis + getNewNum() + 1;
  }
  while (usedNums[newNum]);

  usedNums[newNum] = true;
  document.getElementById(currSquare).innerHTML = newNum;
  document.getElementById(currSquare).className = "";
  document.getElementById(currSquare).onmousedown = toggleColor;
}

function getNewNum() {
  return Math.floor(Math.random() * 15);
}

function anotherCard() {
  for (var i=1; i<usedNums.length; i++) {
    usedNums[i] = false;1
  }

  newCard();
  return false;
}

function toggleColor(evt) {
  if (evt) {
    var thisSquare = evt.target;
  }
  else {
    var thisSquare = window.event.srcElement;
  }
  if (thisSquare.className == "") {
    thisSquare.className = "pickedBG";
  }
  else {
    thisSquare.className = "";
  }
  checkWin();
}

function checkWin() {
  var winningOption = -1;
  var setSquares = 0;
  var winners = new Array(31,992,15360,507904,541729,557328,1083458,2162820,4329736,8519745,8659472,16252928);

  for (var i=0; i<24; i++) {
    var currSquare = "square" + i;
    if (document.getElementById (currSquare).className != "") {
     document.getElementById (currSquare).className = "pickedBG";
     setSquares = setSquares | Math.pow(2,i);
   }
  }
  for (var i=0; i<winners.length; i++) {
    if ((winners[i] & setSquares) == winners[i]) {
    winningOption = i;
    }
  }
  if (winningOption > -1) {
    for (var i=0; i<24; i++) {
     if (winners[winningOption] & Math.pow(2,i)) {
       currSquare = "square" + i;
       document.getElementById (currSquare).className = "winningBG";
     }
    }
  }
}
checkWin();

每当用户给格子加标记时,获胜状态都可能会有变化,所以在toggleColor()的末尾要调用checkWin()。

var winningOption = -1;
var setSquares = 0;
var winners = new Array(31, 992, 15360, 507904, 541729, 557328, 1083458, 2162820, 4329736,➝8519745, 8659472, 16252928);

在checkWin()的开头创建下面这些新变量。 winningOption,存储用户可能遇到的获胜选项。 setSquares,存储已经单击的格子。 winners,是一个数字数组,其中的每个数字是有效获胜组合的编码值。

for (var i=0; i<24; i++) {
var currSquare = "square" + i;
if (document.getElementById (currSquare).className != "") {

对于卡片上的每个格子,需要检查它的号码是否已经被叫过。我们将使用格子的class属性作为标志——如果它是空的,就是没有被单击过;如果有class属性值,就执行下面的代码。

document.getElementById(currSquare).className = "pickedBG";
setSquares = setSquares | Math.pow(2,i);

第一行很简单,实际上它应该是多余的——class属性已经设置为了pickedBG。但是,也可能有例外,比如当用户单击了他们原本不打算单击的格子时,碰巧获胜了(这会把class属性重新设置为winningBG而不是pickedBG),然后用户再次单击这个格子恢复它的状态。如果用户实际上是获胜者,后面会重新设置class属性。

第二行使用按位算术,根据卡片的每个可能状态把setSquares设置为一个数字。单竖杠(|)对两个值执行位“或”计算:setSquares本身和数字2i。2i是Math.pow(2,i)的结果,20是1,21是2,22是4,依次类推。对这两个数字执行按位“或”操作会产生一个表示用户所处状态的变量(共有超过1600万个可能的状态)。

for (var i=0; i<winners.length; i++) {
 if ((winners[i] & setSquares) == winners[i]) {
  winningOption = i;
 }
}

现在只知道卡片当前所处的状态,我们希望查明它是否是获胜状态。在一般的Bingo游戏中,有12个获胜状态,这部分代码把卡片的当前状态与每个获胜状态做比较。我们在每个获胜状态和当前状态之间执行按位“与”计算。这会产生一个新状态,在这个状态中只有那些同时出现在两个状态中的格子,才具有true值。然后,对这个新状态和同一个获胜状态作比较,这样就能够判断卡片是否完全符合这个获胜模式,即结果不包含获胜状态之外的所有选择(因为在获胜状态中找不到它们),而且只要在获胜模式中找到的所有格子也出现在当前模式中,用户就是获胜者。在这里,把winningOption设置为i,这就是用户匹配的模式。

if (winningOption > -1) {
 for (var i=0; i<24; i++) {
  if (winners[winningOption] & Math.pow (2,i)) {
   currSquare = "square" + i;
   document.getElementById (currSquare).className = "winningBG";
  }
 }
}

最后,如果winningOption是大于-1的数字,就说明用户是获胜者。在这种情况下,希望循环遍历每个格子,检查在获胜模式中是否可以找到它。如果是,就把class属性设置为winningBG。

处理字符串数组

添加自己的文本字符串:

var buzzwords = new Array ("Aggregate",
  "Ajax",
  "API",
  "Bandwidth",
  "Beta",
  "Bleeding edge",
  "Convergence",
  "Design pattern",
  "Disruptive",
  "DRM",
  "Enterprise",
  "Facilitate",
  "Folksonomy",
  "Framework",
  "Impact",
  "Innovate",
  "Long tail",
  "Mashup",
  "Microformats",
  "Mobile",
  "Monetize",
  "Open social",
  "Paradigm",
  "Podcast",
  "Proactive",
  "Rails",
  "Scalable",
  "Social bookmarks",
  "Social graph",
  "Social software",
  "Spam",
  "Synergy",
  "Tagging",
  "Tipping point",
  "Truthiness",
  "User-generated",
  "Vlog",
  "Webinar",
  "Wiki",
  "Workflow"
);

var usedWords = new Array(buzzwords.length);
window.onload = initAll;

function initAll() {
  if (document.getElementById) {
    document.getElementById("reload").onclick = anotherCard;
    newCard();
  }
  else {
    alert("Sorry, your browser doesn’t support this script");
  }
}

function newCard() {
  for (var i=0; i<24; i++) {
    setSquare(i);
  }
}

function setSquare(thisSquare) {
  do {
    var randomWord = Math.floor((Math.random() * buzzwords.length));
  }
  while (usedWords[randomWord]);

  usedWords[randomWord] = true;
  var currSquare = "square" + thisSquare;
  document.getElementById(currSquare).innerHTML = buzzwords[randomWord];
  document.getElementById(currSquare).className = "";
  document.getElementById(currSquare).onmousedown = toggleColor;
}

function anotherCard() {
  for (var i=0; i<buzzwords.length; i++) {
    usedWords[i] = false;
  }

  newCard();
  return false;
}

function toggleColor(evt) {
  if (evt) {
    var thisSquare = evt.target;
  }
  else {
    var thisSquare = window.event.srcElement;
  }
  if (thisSquare.className == "") {
    thisSquare.className = "pickedBG";
  }
  else {
    thisSquare.className = "";
  }
  checkWin();
}

function checkWin() {
  var winningOption = -1;
  var setSquares = 0;
  var winners = new Array(31,992,15360,507904,541729,557328,1083458,2162820,4329736,8519745,8659472, 16252928);

  for (var i=0; i<24; i++) {
    var currSquare = "square" + i;
    if (document.getElementById (currSquare).className != "") {
     document.getElementById (currSquare).className = "pickedBG";
     setSquares = setSquares | Math.pow(2,i);
    }
  }

  for (var i=0; i<winners.length; i++) {
    if ((winners[i] & setSquares) == winners[i]) {
   winningOption = i;
    }
  }

  if (winningOption > -1) {
    for (var i=0; i<24; i++) {
     if (winners[winningOption] & Math.pow(2,i)) {
       currSquare = "square" + i;
       document.getElementById (currSquare).className = "winningBG";
     }
    }
  }
}
do {
 var randomWord = Math.floor ((Math.random() * buzzwords.length));
}
while (usedWords[randomWord]);

usedWords[randomWord] = true;
var currSquare = "square" + thisSquare;
document.getElementById (currSquare).innerHTML = buzzwords[randomWord];

任何字符串可以放在任何格子中(没有标准Bingo游戏中的编号限制)。只需确保获取一个还未使用过的字符串,把它标为已使用,然后写到格子中。

for (var i=0; i<buzzwords.length; i++) {
  usedWords[i] = false;
 }

与标准Bingo卡片一样,在生成一张新卡片时,必须把usedWords中的所有标志设置为false,这样就可以再次使用它们。

系列:web

该系列自动来自分类: web

  1. css 扩散列表
  2. JavaScript获取浏览器使用的语言
  3. 两个练习
  4. css RWD
  5. css 图片
  6. css 提示
  7. css 下拉
  8. css 表单
  9. css 导航栏
  10. css 单词
  11. HTML SVG
  12. HTML Canvas
  13. HTML 媒体
  14. HTML input
  15. HTML 结构
  16. 学习JavaScript笔记「4」
  17. 学习JavaScript笔记「3」 (当前)
  18. 学习JavaScript笔记「2」
  19. 学习JavaScript笔记「1」
  20. 微信小程序开发日志「4」
  21. 微信小程序开发日志「3」
  22. 微信小程序开发日志「2」
  23. 微信小程序开发日志「1」

下一篇推荐

系列继续阅读

学习JavaScript笔记「2」