涉及语句、变量
# 语句
# for-of语句
- for-of用于遍历可迭代对象的元素
- 可迭代对象必须实现Symbol.iterator方法,这个方法必须返回一个有next方法的对象,for-of循环会按照next()产生值的顺序迭代元素
- next()返回的结果格式必须为
{done: Boolean, value: any}
,当done = true时,表示迭代结束,否则value是for-of要取得的下一个值 - Symbol.iterator方法会被for-of自动调用,如果没有找到对象的这个方法会报错
- 数组和字符串是使用最广泛的内置可迭代对象,也可以通过给普通对象添加Symbol.iterator方法使其能用for-of循环
# for-in语句
- for-in用于枚举对象中的非符号键属性,所谓的非符号键属性即对象中key不为Symbol的属性
- 如果要迭代的变量是null或undefined,则不执行循环体
- for-in和Object.keys(myObject)都用于枚举对象属性,但for-in遍历会包括对象的原型方法和属性,而Object.keys()不包括
注:for-in和for-of都可以用来遍历数组,但for-in遍历的是数组的索引(且返回的索引是string型的),而for-of遍历的数组元素值(是number型的)
# 标签语句
- 语法:label:statement,label是标识符,statement是js语句,典型的应用场景是嵌套循环
- 可以使用一个标签唯一标记一个循环,然后使用break或continue语句来指示程序是否中断循环或继续执行
- 因为JavaScript没有goto语句,标记只能和break或continue一起使用,break可以用于任何标记语句,而continue只可用于循环标记语句 如下栗子,在满足条件时通过loop1跳到最外层循环继续执行:
var i, j;
loop1:
for (i = 0; i < 3; i++) {
loop2:
for (j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
continue loop1;
}
console.log('i = ' + i + ', j = ' + j);
}
}
2
3
4
5
6
7
8
9
10
11
# 原始值与引用值
当把一个值赋给变量时,JavaScript引擎必须确定这个值是原始值还是引用值。保存原始值的变量是按值访问的,保存引用值的变量是按引用访问的。引用值是保存在内存中的对象,与其他语言不同,JavaScript不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用而非实际的对象本身。
只有引用值可以动态添加属性,虽然给原始值添加属性不会报错,但静默无效
原始值的复制是两个独立的变量,而引用值的复制两个变量的指针指向的是同一个对象
ECMAScript中所有函数的参数都是按值传递的。这意味着传参即将函数外的变量复制到一个局部变量(即一个命名参数)
- 当参数是一个原始值时,在函数内修改传递过来的参数,不会影响函数外的那个原始值变量
- 当参数是一个引用值时,如下栗子:
function setName(obj) { obj.name = "Nicholas"; //obj = new Object(); //obj.name = "Greg"; } let person = new Object(); setName(person); console.log(person.name); // "Nicholas"
1
2
3
4
5
6
7
8person被传给setName()方法,并复制到参数obj中,在函数内部,person和obj指向的是同一个对象。**即使对象是按值传进函数的,obj也会通过引用访问对象!!**所以当函数内修改obj时,person也会反映这个变化。但并不意味着参数就是按引用传递的,上面栗子的第三四行取消注释,最后的结果也一样,obj被设置为一个新对象,改为指向name为"Greg"的对象,如果person是按引用传递的,那么person应该自动将指针改为指向name为"Greg"的对象,但当再次访问person.name的时候,它的值依然是"Nicholas",这表明函数中参数的值改变之后,原始的引用仍然没变。
typeof操作符用于判断一个变量是什么类型的,但无法分辨对象的具体类型;instanceof操作符解决了这个问题,如果变量是给定引用类型(由其原型链决定)的实例,则该操作符返回true,如 person instanceof Array用于判断person是否为数组对象,如果是则返回true否则返回false