请复习或补习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 对象中要求包含所有的好友数据。
-
请取出所有被人认为是土豪的用户。只要这个用户在另一个用户的"土豪"圈中,那么就 说这个用户被人认为是土豪。取出的结果放到一个数组里,并输出这个数组。
-
给定某一个用户,请计算有多少人认为这个用户是土豪,而多少人认为这个人是菊苣。 输出分别的人数。
-
现在假设 G+ 希望分别举办一次土豪炫富活动和一次菊苣交流会。但判定一个人是土豪还是 菊苣需要花太多的时间(遍历所有人的圈子)。因此G+迫切地需要某种缓存,这种缓存可以 只用一个操作就判断某个人是不是土豪或菊苣。你注意到用对象可以很轻松地判断一个键 是否存在,而用数组则需要进行循环,所以你决定在缓存中使用对象的键来表示用户 ID 。
当用户把另一个用户添加到菊苣或土豪圈时,不仅需要更新数据库,而且还要更新是否菊苣/土豪的 那个缓存。假设那个缓存也用一个JS的变量表示,其结构自行设计。
当用户将一个用户移除时,说明这个用户不再被认为是菊苣/土豪。不仅要更新数据库,还要 更新缓存。更新规则是:当最后一个人将某个用户移除土豪圈时(此时用户不再被任何人认为 是土豪),则需要将其从缓存的土豪中移除。
现在请对添加圈子(某人将某人添加到圈子中)和删除圈子(某人将某人移出某个圈子)分别 编写一段程序。这个程序同时按规则更新数据库和更新缓存。假设这个缓存是新引入的,那么 必须对所有已经存在的圈子关系生成一次缓存(规则相同,只是无须更新数据库,因为已经有 了),这部分代码也可以尝试编写。
如果觉得处理了菊苣再处理土豪要写两遍太浪费时间,可以只写其中之一。但记得把代码写 得通用一点,使得这个代码今后稍微做一点修改也能处理新的一类生物——学霸。
提示:怎么判断是否是最后一个人将某人移除土豪圈?想要高效地判断这一点,那么缓存中 就不能只存储是/不是,而应该存储这个人被多少个人认为是土豪。每次有人将其加到土豪 圈,数量+1。移除则-1。移除时如果数量变成0就可以说明这个人不再被任何人认为是土豪。
字符串在某些方面比较像一个数组。假设 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 做简单的演示。
做完作业的话,建议马上将作业的网址发到环聊里供讨论。也可以请别人帮忙调试或者解决 问题。记得多看看别人的代码,也许会有更多收获。答案不唯一,只要能达到目的,而且代码 风格不是很差的,都是可以接受的。
只做作业是不够的。请利用空余时间继续自学。