#JavaScript第三次记录整理
作业地址传送门 ##一.数组
上次交流的时候,我们讨论过JS的两个基本类型,Number和String类型,分别表示数和字符串。
但是只有 Number 和 String 类型是不够的。表示更加复杂的类型则需要数组(Array)和对象(Object)。
先讲数组。一个数组类似于一个列表,可以储存多个JS的类型值。
比如 var items = ["a", "b", "c", 9];
这里存储了4个值,三个字符串和一个数。也就是说,数组允许我们将多个值存储在一个变量中。
是不是很方便呢?
一个数组的写法是方括号 [ ] 中,以逗号分隔多个值。
比如 [1, 2, 3, 4]
。
空的括号 [] 表示0个元素的数组。
用 items[0]
的语法就可以取得 items 中的第一个元素,按之前的例子, items[0]
是 "a"。
需要更改数组的话,则可以使用 items[0] = "aaa";
这样的赋值语句。
也就是说,一个数组后面加上[0]基本上和一个变量的用法类似。
console.log 也支持输出数组如console.log([1,2,3]);
。
方括号中,必须是一个整数,或者是能计算成为整数值的表达式,如 items[1 + 1] 取第三个元素(不是第二个)。
当然也可以用变量,比如 var a = 1; var items = [2, 3]; console.log(items[a]);
结果应该是3。
再次说明,数组的类型是数组类型(Array),是不同于字符串和数的另一种基本类型。
数组的元素类型并没有限制的,比如 ["1", 2, [3, 4]] ,元素类型分别是字符串、数和数组
console.log([2,3]) 的输出由环境决定。NodeJS下可能是 [2,3]。开发者工具可能显示得更加友好,比如带有样式和高亮。
JS的数组大小是可以变化的,可以用 items.push(9); 在末尾增加一个元素,原先是 [1,2,3] 的会变成 [1,2,3,9]。
类似的还可以删除元素,如 items.pop();
会去掉最后一个元素,变成 [1,2]
由于我们现在还没有学循环语句,所以没有办法对数组中的每个元素进行批量操作,只能手动用 items[0], items[1] 来操作,所以说暂时没太多用处。
##二.对象
对象也是JS的一种基本类型,其写法是 var obj = {a: 9};
这个可以理解成一个对象obj,其属性a为9。
怎么取得值呢?可以用 obj.a
也可以用 obj["a"]
。
注意如果用方括号获取的话,里面需要的是一个字符串,当然也可以是字符串表达式或者变量。
来自凤凰菊苣的插嘴 点操作符不能取带有短线的属性名,因为会被理解为运算符。
JS的对象相当于其他语言的字典dictionary或者map,可以认为是一个键值对。
比如说用于翻译的话, var dict = {"hello": "你好", "bye": "再见"};
其中有两个元素,dict.hello 的值是 "你好", dict.bye 是 "再见"。
对象的键是允许任何字符串的,比如 {"a^@#sdfp": 9}。
如果碰巧那个字符串是合法的变量名,则可以省略引号,如 {a: 9} 与 {"a": 9} 等价。
在访问的时候,使用 obj["a"] 来获取。如果键碰巧是合法的名称,则可以使用 obj.a 这种简单的写法。
如果访问的键是不确定的,或者含有特殊字符,则只能使用 obj["a"] 这种语法来访问。
比如 var student={name: "Alice", score: 95};var prop="name";console.log(student[prop]);
这里利用一个字符串类型的变量来获取 student.name。
JS的对象类型和数组类型类似,也是复杂类型,区别就是对象类型用名字而不是序号。
student.name = "Bob"; 这样的语法可以用于更改对象的一个属性。
console.log 可以用于输出对象,至于输出什么大家自己试试看就好。
写对象的时候,冒号右侧可以是任意表达式,比如 var a = 9; var obj = {a: a}; 这里 a: 是表示键或者说属性名是 a, 而冒号右侧的 a 是取变量 a 的值。
有了数组和对象,就可以存一些比较复杂的内容了。
明显属于一个整体的两个值,比如一个学生的姓名和分数,可以考虑用对象来存储 var student={name: "Alice, score: 95};
如果用两个变量来存储,则传递和引用不太方便。
如何存储多个学生?太简单了: var students = [{name: "Alice", score: 95}, {name: "Bob", score: 80}];
这里首先是一个数组,这个数组的每一个元素是一个对象,分别有 name 和 score。
要取得第一个学生的姓名: students[0].name。
但是呢,如果我们想要取得 Alice 的姓名,就只能用循环一个个查找过去了。
如果需要根据名字,或者说根据字符串来查找,那么存储的时候最好选择用对象,比如 var scores = {"Alice": 9, "Bob": 10};
这样获取 Alice 的分数就是 scores["Alice"]。
所以刚才说过, JS 的对象可以当做字典或者map来用/
现在假设你来设计G+的社交圈。一个人有多个社交圈,每个圈子中有多个好友。请设计一个结构来存储某个人的好友列表。
下面再给出一种存储方式,仅供参考 var people = [{name: "AprocySanae", circles: ["菊苣", "土豪"]}, {name: "shizuko", circles: ["渣渣", "小透明"]}];
。
这种方式是保存每个人属于哪些圈子,而不是保存每个圈子有哪些人。
首先, var a = {}; 定义一个空对象。该对象没有任何用户定义的属性
那么空对象有什么用?一个用处是,对象是可以之后添加属性的。
给不存在的属性赋值则自动添加,比如 a.prop = 9;
会让 a 变成 {prop: 9}。
删除一个属性,则是 delete a.prop ,删除以后就和没存在过一样。
利用添加和删除,可以维护动态的圈子列表之类的。也可以把 JS 的对象当做集合用。
好了,到这里简单对象就基本介绍完毕了
##三.null和unidentified
我们再介绍两种 JS 的类型,分别是 null 和 undefined。
这两种类型的特殊之处在于只有一个值。 唯一的 null 类型值是 null, 而唯一的 undefined 类型值是 undefined。
要注意的是, null 是一个关键字,但 undefined 是一个全局变量。不排除有人恶意将 undefined 赋值成其他的值,要小心。
undefined 顾名思义,就是没有确定过的值。比如一个没有赋值过的变量。 var a; console.log(a);
这样输出是 undefined。
注意,如果没有 var a; 这句语句,那么会提示错误。一个没有值的变量和没有这个变量是不同的。
另一种说法是, JS 中所有变量的默认值是 undefined。访问不存在的属性,返回也是 undefined ,比如 var a = {}; console.log(a.prop);
。
不过返回 undefined 并不能判断一个属性不存在。可能那个属性存在,只是碰巧值是 undefined,比如 var a = {prop: undefined};
。
一个数组中不存在的元素也是 undefined,比如 var a = [1,2]; console.log(a[9999]);
。
undefined 也可以写作 void 0,不要问为什么。
至于每次 console.log(...) 出现的那个 undefined 嘛……函数如果没有返回值,那么其返回值默认为 undefined。
接下去讲一下 null。
null 表示空。已经有一个 undefined 了,为什么还需要一个 null? 谁知道呢。
只想到一种用途,需要表示一个空值,但又不能是 undefined 的情况下(比如说,可能和未定义的属性混淆起来?),可以用 null。
用 console.log(typeof 变量名) 可以看到一个变量的类型。
如 var a = 9; console.log(typeof a);
。
typeof 的运算结果总是字符串。
注意 typeof null 是 object 。这是一个意外……
顺便, typeof 一个不存在的变量名,结果是 "undefined"。
typeof 9 是 "number"。 typeof "abc" 是 "string"。
##四.boolean boolean 只有两个值, true 和 false ,表示真和假。
typeof true 是 "boolean",false当然也是。
JS 的相等判断有两种, == 和 ===。
1 === 1
结果是 true。
其中 === 判断类型相等且值相同,而 == 则试着把两边类型转换成一样的再判断是否相同。
! 是逻辑非,就是取相反。 !true 是 false, !false 是 true。
&& 是逻辑与, 两边都是 true ,结果为 true。否则为 false。
比如 1 + 1 === 2 && 1 + 2 === 3 是 true。
|| 是逻辑或,两个竖线。两边都是 false 结果为 false ,否则为 true。
注意数组和对象有自己的身份。任意两个数组的都是不相等的,比如 [] === [] 结果是 false。
只有自己和自己才相等,如 var a = []; console.log(a === a)
结果是 true。
写 {} === {}
会出现语法错误。只能写 ({}) === ({})
,结果是 false。
无论长得再像的两个数组或者对象,都是不同的。就算console.log输出看不出区别,也不相等。
如果要判断两个数组的元素是否相等嘛……用循环……
判断一个数组是否为空,用的是 items.length === 0 来判断。
只有数组、对象、函数这三个复杂的类型有身份,其他的类型都被认为是简单类型,判断的都是值是否相等。
字符串是没有身份的,所以判断一个字符串是否为空可以是 a === "" 也可以是 a.length === 0。
身份这个说法,只是用于说明数组、对象、函数的特殊性。他们只和自己相等,和长得像的其他对象不相等。
所以我们称数组、对象、函数有”身份“,只是一种说法,避免每次都扯一长串定义。
对了补充一个坑, typeof [1,2] === "object"
,所以 typeof 不能区分数组和对象……坑。
事实上 typeof 的定义是就那么几种……对于不认识的,一概都是 "object"。
要判断一个变量 a 是不是数组,可以用 Array.isArray(a) 结果是 true 或者 false。
有身份的任何变量,都可以添加属性,比如数组、函数、对象都支持 a.prop = 9;
这种语法。
var x = {}; var y = x;
的时候, y 和 x 是同一个对象。
还有一个区别就是 {0:1, 1:2, 2:3} 其实是 {"0":1, "1":2, "2":3}。
然后对象不支持数组的各种操作,比如 push。
##五.控制语句
####条件语句
if (a === b) { console.log("相等"); } else { console.log("不相等") }
。
语法是 if (条件) { ...} else { ... } ,其中 else {...}可选,如果不写就是没有任何语句,条件时boolean的表达式。
boolean 以外转换成 boolean 。要记的只有空数组转换为 false, 空字符串转换为 false, 0 转换为 false, null 和 undefined 转换为 false 。其他都是 true。
记不住就不要记,用 === 之类的来严格判断。
条件成立执行第一个 { ... } ,不成立执行 else 后的那个 { ... }。
####循环语句
while (a < 10) { a += 1;}
空数组不是 false ,只是在 if 环境中会当做 false 处理。
循环语句语法是 while (条件) { ... } ,1. 检查条件成立,2. 如果成立执行 { ... },然后再回到第1步,如此反复。
while 的条件也是和 if 一样,可能存在转换。
for 循环是 while 循环的另一种写法。
语法是 for(A; B; C;) { D; }
相当于 A;
for (A; B; C) { D; }
,但是 A, B, C 都只能是一个表达式,不能是多个语句。
常用的写法是 for (var i = 0; i < 10; i++) { console.log(i); }
输出 0 到 9。
但是有些时候 switch 语句什么的更方便,这些请自己学习啦。
关于 JS 的控制语句,如果不熟悉的话,请在 codecademy 自己练习吧~
需要讲的,只有 JS 特殊的语句而已。
首先是 for .. in
var a = {b: 3, d: 4}; for (var i in a) { console.log(i); }
这个会输出 "b" 和 "d"。
for (i in a) 的语法, 对于 a 的所有属性各执行一次,每一次 i 变成 a 的一个属性的名称,是一个字符串。
这样就可以 console.log(a[i]);。
对于长度为10的数组a, for (i in a) , i 依次变成 0, 1, 2, ... 9。
相当于 for (var i = 0; i < a.length; i++)
。
要注意的是, i 变成的是 0 到 a.length - 1,是变成数组的序号, 而不是像某些语言一样变成数组的值。
要拷贝一个数组,可以这样: var b = []; for (var i in a) { b.push(a[i]); }
。
如果直接 b = a; 那么 b 不是一个拷贝,而是和 a 共用一个数组,这个之前讲过。
#####Meeting ended at 15:02:20 UTC