Skip to content

Instantly share code, notes, and snippets.

@quietlynn
Created June 10, 2014 15:10
Show Gist options
  • Save quietlynn/351d7756cb99c082b078 to your computer and use it in GitHub Desktop.
Save quietlynn/351d7756cb99c082b078 to your computer and use it in GitHub Desktop.
JavaScript 入门第三次作业

零、复习控制语句

请复习或补习JS的所有控制语句。活动的时候没讲到的 switch 语句等,也请查阅相关书籍 或网络来学习。

对于没有学习过编程或者不了解控制语句的各位,建议在 codecademy 进行简单的训练。 但不用急着学习后面的内容啦,只要掌握控制语句就足够了。

一、”谢谢惠顾!“

首先,用 var num = Math.floor(Math.random() * 8); 可以得到一个 0 到 7 之间的随 机整数。这里 Math.random() 可以获得一个 0..1 之间的随机数,然后乘以 8 ,再取整数 部分,结果就是 0 到 7 之间的随机整数了。

这次的题目要求是,做一个抽奖程序。抽奖所有可能的结果都保存在一个数组中, 这个数组里全部都是字符串,每一个是一种可能的结果。

现在要求从数组中抽一个结果打印出来。当然,这里每个结果抽到的概率都相等。

改进:但实际抽奖的时候,大奖的概率总是低一些的。为了达到这个效果,可以在数组里 只写一次"一等奖",而写十次"谢谢惠顾"。多抽几次,试试看自己的运气吧~

改进2:手写十次"谢谢惠顾"实在是太累了,所以我们决定用一个循环来生成用于抽奖的 数组。先设计一个存储结构(可以任意由字符串、数字、数组、对象构成),用来存放所有 可能的结果,和这个结果可能出现的比例(用整数表示,比如谢谢惠顾对应10,一等奖对应1 等等)。然后利用循环语句,生成抽奖用的数组。最后将生成的数组用到上面写的抽奖程序 中去。

改进3:假设现在有很多人都要来抽奖,再假设所有的抽奖券都是抽过以后不返还的(也就是 说,如果抽的人数与数组长度相等,就一定有人会抽到一等奖)。试着写一个循环,从数组 中依次抽出多个结果。结果的数量应该与数组的长度相同(请不要手写一个数字上去,请用 .length 取数组长度,谢谢)。依次打印抽出的结果。这个练习需要掌握从数组中删除单个 元素的方法,如果不会请自行谷歌一下。

二、土豪、菊苣和我

现在假设你要来帮助谷歌做 G+ 。你作为一个资深用户,深刻地体会到 G+ 是由土豪、菊苣 和你自己组成的,因此在设计社交圈时,你需要充分考虑到这一点。

首先你改革了 G+ 的圈子系统,要求圈子必须包含"土豪"、"菊苣"两个分类。所有的好友, 必须至少处在这两个圈子其中之一。而自己不能添加自己为好友。(背景知识:圈子是G+ 上对于好友的分类。一个人可以创建任意数量的圈子,每个好友可以放在一个或多个圈子中)

接下去你设计了G+的数据库(假设是基于文档的数据库,可以用JavaScript的基本类型、对象 和数组来表示)。现在假设你从数据库里取得了所有人的好友数据,存储在变量 db 中。(db 的结构请活用数组和对象来实现。)db 对象中要求包含所有的好友数据。

  1. 请取出所有被人认为是土豪的用户。只要这个用户在另一个用户的"土豪"圈中,那么就 说这个用户被人认为是土豪。取出的结果放到一个数组里,并输出这个数组。

  2. 给定某一个用户,请计算有多少人认为这个用户是土豪,而多少人认为这个人是菊苣。 输出分别的人数。

  3. 现在假设 G+ 希望分别举办一次土豪炫富活动和一次菊苣交流会。但判定一个人是土豪还是 菊苣需要花太多的时间(遍历所有人的圈子)。因此G+迫切地需要某种缓存,这种缓存可以 只用一个操作就判断某个人是不是土豪或菊苣。你注意到用对象可以很轻松地判断一个键 是否存在,而用数组则需要进行循环,所以你决定在缓存中使用对象的键来表示用户 ID 。

当用户把另一个用户添加到菊苣或土豪圈时,不仅需要更新数据库,而且还要更新是否菊苣/土豪的 那个缓存。假设那个缓存也用一个JS的变量表示,其结构自行设计。

当用户将一个用户移除时,说明这个用户不再被认为是菊苣/土豪。不仅要更新数据库,还要 更新缓存。更新规则是:当最后一个人将某个用户移除土豪圈时(此时用户不再被任何人认为 是土豪),则需要将其从缓存的土豪中移除。

现在请对添加圈子(某人将某人添加到圈子中)和删除圈子(某人将某人移出某个圈子)分别 编写一段程序。这个程序同时按规则更新数据库和更新缓存。假设这个缓存是新引入的,那么 必须对所有已经存在的圈子关系生成一次缓存(规则相同,只是无须更新数据库,因为已经有 了),这部分代码也可以尝试编写。

如果觉得处理了菊苣再处理土豪要写两遍太浪费时间,可以只写其中之一。但记得把代码写 得通用一点,使得这个代码今后稍微做一点修改也能处理新的一类生物——学霸。

提示:怎么判断是否是最后一个人将某人移除土豪圈?想要高效地判断这一点,那么缓存中 就不能只存储是/不是,而应该存储这个人被多少个人认为是土豪。每次有人将其加到土豪 圈,数量+1。移除则-1。移除时如果数量变成0就可以说明这个人不再被任何人认为是土豪。

三、 补充:字符串(String)

字符串在某些方面比较像一个数组。假设 var a = "Hello";,那么可以用a[0]来取字符 "H"。取到的字符并不是特殊的字符类型,而是一个长度为1的字符串。字符串也支持 for .. in 语句,此时与数组类似,变量的值从 0 到 a.length - 1 变化。

不同之处在于,字符串是不可修改的。不能修改字符串某个位置的字符,也不能增加或者 删除字符。字符串是不可变的。想要连接、替换或者截取字符串时,必须生成新的字符串, 如 b = a.substr(1, 2),可以取字符串 a 从第二个位置(1)开始的两个字符(2)。

除了 .length 等都有的以外,字符串与数组支持的操作截然不同。字符串有独有的查找、 替换、取子字符串等操作。注意替换和取子字符串等都是生成新的字符串而非修改。

但是注意当执行 a += "abc"; 这个表达式的时候,应该按照 a = a + "abc" 来理解, 先生成一个新的字符串a + "abc"然后赋值给 a ,从而实现增加字符。

(但是因为这种情况下,原先的 a 不再使用了,重新复制一遍效率很低,所以环境可能会优 化成直接修改 a 的值(已知 Chrome 或者说 V8 会优化这个)。不过从概念上来说,并不违 反字符串是不可变的这一表面现象,只是实现上更加高效了而已。大家在理解的时候还是 尽量按照字符串不可变来理解就可以了。)

因为字符串是不可变的,所以当然也就没有所谓的字符串修改,也不存在 a = b; 后会不会 同步修改这种令人纠结的问题(因为字符串本身不会变化,最多只是再 a = c;而已,真是 可喜可贺~

小练习:

从一个字符串,比如 "Hello" 中取得所有字符,并将其放到一个数组中。然后,将这个数组 反转(也就是说,变成 ["o", "l", "l", "e", "h"]),然后以逗号分隔输出。

反转数组的过程要求使用循环来进行。不推荐在原先的数组上进行操作,而建议使用另一个 新的空数组,然后依次将元素添加到新数组的开头,以实现反转。

或者,如果循环语句用的 不是 for .. in 循环而是普通的 for 循环,那么完全可以让 i 从 a.length - 1 到 0 来递减。这样一来,反向每次取一个元素,添加到新数组的末尾。(如果不知道如何写一个 递减的循环,那么可以上网搜索相关写法。)

以上两种方法都是可以的。请选自己喜欢的就可以了。不过请注意实际编写代码的时候,可以 用 a.reverse(); 一句语句来反转整个数组,并不需要用循环来做。但是如果对于循环不 熟悉的话,以上可以作为一次不错的练习,所以这次还是不要偷懒比较好。

以逗号分隔输出,可以手动用 result += a[i] + "," 来实现(其中 result 是一个 在循环中不断增加的字符串),也可以用 a.join(",") 来实现。

作业要求:

作业并不是必须的,不做也可以。但是,如果做了作业,建议用 https://gist.github.com 把你的解答分享出来,和大家交流。当然,也可以用 jsfiddle 做简单的演示。

做完作业的话,建议马上将作业的网址发到环聊里供讨论。也可以请别人帮忙调试或者解决 问题。记得多看看别人的代码,也许会有更多收获。答案不唯一,只要能达到目的,而且代码 风格不是很差的,都是可以接受的。

只做作业是不够的。请利用空余时间继续自学。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment