ES6定义的新循环语句:专门用于可迭代对象。
let array = [2,4,8],sum = 0;
for (let item of array) {
sum += item
}
console.log(sum); // 14
let str = "hello for/of"
let tempArr = []
for (let item of str) {
tempArr.push(item)
}
console.log(tempArr)
// [
// 'h', 'e', 'l', 'l',
// 'o', ' ', 'f', 'o',
// 'r', '/', 'o', 'f'
// ]
对象(默认)是不可迭代的。Object.keys(obj)方法返回obj中属性名数组,Object.values(obj)方法返回obj中值的数组。Object.entries(obj) 返回键与值数组的数组(最内层为由一个键及对应值组成的数组)。
let obj = {x: "hello", y:2}
console.log(Object.keys(obj))
console.log(Object.values(obj))
console.log(Object.entries(obj))
// [ 'x', 'y' ]
// [ 'hello', 2 ]
// [ [ 'x', 'hello' ], [ 'y', 2 ] ]
是js从一开始就有得。in后面可以是任意对象。
for (variable in object) statement; //variable通常是一个变量名
for(let p in obj) console.log(obj[p]); //会将obj得属性名赋值给变量p
variable 还可以是任意表达式,只要能求值为赋值表达式的左值就行。这个表达式在每次循环时都会被求值,这意味着每次的求值结果可能都不同。
let obj2 = {x: "hello", y:2}
let arr2 = [], i = 0;
for (arr2[i++] in obj2);
console.log(arr2); // [ 'x', 'y' ]
对于数组,for/in为枚举出数组索引,所以在开发中,对于数组的循环我们只会用到for/of。
let arr3 = ["hello", "js"]
console.log("for/in:")
for (let p in arr3) console.log(p);
console.log("for/of:")
for (let p of arr3) console.log(p);
// for/in:
// 0
// 1
// for/of:
// hello
// js
通过前置一个标识符和一个冒号,可以为任何语句加上标签:
identifier:statement // identifier标签名 statement语句
给语句加标签后,相当于给它取了个名字,可以在程序的任何地方通过这个名字来引用它。任何语句都可以有标签。identifier可以是任何合法的js标识符,和变量及函数不在同一个命名空间。
当break后面跟一个标签时,它会跳转到具有指定标签的包含语句的末尾或终止该语句。
let array1 = [3,2,5,6,2,5]
breakLabel: for (let it of array1) {
for (let i = 0; i < 3; i++) {
if ((it + i) % 2 === 0) {
console.log("挑出:it:" + it); //挑出:it:3
break breakLabel;
}
}
}
continue语句在while和for循环中的行为有差异:while循环直接返回到它的条件,但for循环会先求其increment表达式,然后再返回其条件。
continueLabel: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 2; j++) {
console.log("i:" + i + " j:" + j)
if (i === 2 || j === 1) {
continue continueLabel;
}
}
}
// i:0 j:0
// i:0 j:1
// i:1 j:0
// i:1 j:1
// i:2 j:0
异常是一种信号,表示发生了某种意外情形或错误。抛出异常是为了表明发生了这种错误或意外情形。捕获异常则是要处理它,即采取必要或对应的措施以从异常中恢复。throw语句的语法如下:
throw expression;
expression可能求值为任何类型的值,可以抛出一个表示错误码的数值,也可以抛出一个包含可读的错误信息的字符串。js解释器在抛出错误时会使用Error类及其子类。
如果在try块中,由于return、continue或break语句而离开了try块,则解释器在跳转到新目标之前会先执行finally块。
function division(x) {
if (x % 2 === 0) throw new Error("不能为偶数");
}
for (let i = 0; i < 3; i++) {
try {
console.log("i=" + i)
division(i)
break
} catch (e) {
console.log(e.message)
} finally {
console.log("finally执行")
}
}
// 运行结果:
// i=0
// 不能为偶数
// finally执行
// i=1
// finally执行
作用是新建实例对象,并且给实例对象内成员(属性或方法)赋值。
构造函数是一种特殊的函数,通常首字母大写,只有当以new操作符来调用的时候,才算是构造函数。
function fun1() {
console.log('fun1')
}
let a = fun1()
console.log(a)
function Fun2() {
this.x = 1
this.y = 3
return "hello" //不起作用
}
let b = new Fun2()
console.log(b)
// 运行结果:
// fun1
// undefined
// Fun2 { x: 1, y: 3 }
封装构造函数的过程会比较麻烦,但一旦封装成功,再创建对象时就会变得非常轻松。
构造函数执行流程:
1)立即创建一个新的对象;
2)将新建的对象设置给函数中的this,在构造函数中可使用this来引用新建的对象;
3)逐行执行函数中的代码;
4)将新建的对象作为返回值返回,不需要return。
js中每个函数都有一个prototype对象属性,指向另一个对象。这个对象的所有属性和方法都会被构造函数的实例继承,所有我们可以把那些不变(公用)的属性和方法,直接定义在prototype对象属性上。
prototype就是调用构造函数所创建的那个实例的原型(proto)。
每个对象都有一个__proto__属性,用于指向创建它的函数对象的原型对象prototype。
作为一个对象,当访问其中一个属性或方法时,如果这个对象没有这个方法或属性,那么js将会访问这个对象的__proto__属性所指向上一个对象,并在这个对象中查找指定方法或属性,如果找不到,则继续通过这个对象的__proto__属性,查找其指向的对象。直到这个链表结束。
function Person() {
this.name = ""
this.age = 27
}
console.log(Person.prototype) //每个函数都有prototype属性
let p = new Person()
console.log(p.prototype) //对象没有prototype属性
console.log(p.__proto__) //每个对象都有__proto__属性
// 运行结果:
// {}
// undefined
// {}
用于创建一个新对象,使用其第一个参数作为新对象的原型。
let obj = Object.create({x: 1, y: 2})
console.log(obj) // {}
console.log(obj.__proto__) // { x: 1, y: 2 }
console.log(obj.x,obj.y) // 1 2
obj.x = 99
console.log(obj.x) // 99
console.log(obj.__proto__) // { x: 1, y: 2 }
obj.__proto__.x = -999
console.log(obj.__proto__) // { x: -999, y: 2 }
js支持为对象定义访问器属性,这种属性不是一个数值,而是一个或两个访问器方法(ES5 引入):一个获取方法(getter)和一个设置方法(setter)。
如果有读取方法,则这个属性可读,否则不可读(始终会得到undefined)。
如果有设置方法,则这个属性可写,否则不可写。
let obj = {
x: 3,
y: 23,
get area() {
return this.x * this.y
},
}
console.log(obj.area) // 69