javascript查缺补漏之三 —— 《循环和函数》
/ / 点击 / 阅读耗时 10 分钟break
- 当在循环中执行break时,会立即终止当前所在的循环。比如下面这几行代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for (i = 0; i < 3; i++) {
for ( j = 0; j < 3; j++) {
if (i === 0) {
console.log('最里面:', i);
break;
}
console.log('里面:', i);
}
console.log('外面:', i);
}
console.log('最外面');
//输出顺序:
最里面: 0
外面: 0
里面: 1
外面: 1
里面: 2
外面: 2
最外面
说明break只跳出了内层循环(所在循环),并没有跳出外面包裹的循环。
2. break label 语法
自己从来没有使用过这种语法,但通过下面这个列子感觉这个语法还是蛮方便的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var x = 0;
var z = 0
labelCancelLoops: while (true) {
console.log("外部循环: " + x);
x += 1;
z = 1;
while (true) {
console.log("内部循环: " + z);
z += 1;
if (z === 10 && x === 10) {
break labelCancelLoops;
} else if (z === 10) {
break;
}
}
}
//如果满足 z === 10 && x === 10 的条件,整个循环就会结束,就是使用了break labelCancelLoops 这条语法。
for in
vsfor of
vsfor
for…in 语句循环一个指定的变量来循环一个对象所有可枚举的属性。
for…of语句在可迭代的对象上创建了一个循环(包括Array, Map, Set, 参数对象( arguments) 等等)
数组适合用传统for循环来操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14let arr = [3, 5, 7];
arr.foo = "hello";
for (let i in arr) {
console.log(i); // logs "0", "1", "2", "foo"
}
for (let i of arr) {
console.log(i); // logs "3", "5", "7" // 注意这里没有 hello
}
for (let i = 0; i < arr.length; i++) {
console.log(i); //logs "0", "1", "2"// 注意这里没有 foo
}上面代码中,传统for循环和for of循环的结果相似。
函数表达式
函数表达式也可以提供函数名,并且可以用于在函数内部代指其本身,或者在调试器堆栈跟踪中识别该函数。
1
2
3var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
console.log(factorial(3));注意下面代码中
square
并非函数名,下面这个函数是匿名函数。1
2var square = function(number) { return number * number; };
var x = square(4); // x gets the value 16Arguments对象
arguments 是一个对应于传递给函数的参数的类数组对象。
arguments对象是所有非箭头函数中都可用的局部变量。可以使用arguments对象在函数中引用函数的参数。
arguments的元素可读可写。
apply()函数
func.apply(thisArg, [argsArray])
,其中[argsArray]
可以为数组也可以是类数组类数组
只要有一个 length 属性和[0…length) 范围的整数属性。比如:
1
{'length': 2, '0': 'eat', '1': 'bananas'}
查找一系列数字中的最大最小值
使用apply和原生Math.max()、Math.min()方法
1
2
3var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);使用数组扩展符
1
2var arr = [1, 2, 3];
var max = Math.max(...arr);
类数组转为数组
方法1: 对性能有影响
Array.prototype.slice.call(arguments)
,这行代码的意思是将slice方法绑定在arguments对象上。简写形式:
[].slice.call(arguments)
,依然是将slice方法绑定在arguments对象上。方法2:
const args = Array.from(arguments);
方法3:使用扩展运算符
var args = [...arguments];
arguments.length
vsfunction.length
arguments.length:表示实际传入函数的参数的个数;
function.length: 指该函数有多少个必须要传入的参数,即形参的个数。形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。
剩余参数 vs 默认参数 vs 解构赋值
剩余参数
如果函数的最后一个命名参数以…为前缀,则它将组成一个数组。剩余参数是货真价实的数组而arguments对象只是类数组。
1
2
3
4function foo(...args) {
return args;
}
foo(1, 2, 3);//[1, 2, 3]默认参数
默认参数是在函数被调用时解析的,所以如果默认参数是可变动的,则每次的结果可能是不一样的。
解构赋值
数组的解构赋值:目测是按数组元素的顺序。(此处仅记录了数组的解构赋值)。
利用数组的解构赋值可以轻松交换值。
1
2
3
4let a = 1, b = 3;
[a, b] = [b, a];
console.log(a);//3
console.log(b);//1解析一个从函数返回的数组
这个自己写代码已经遇到过多次返回数组的情况,但是都使用的传统获取数组对应位置的元素的方法,明显使用数组解构更简洁。
1
2
3
4
5
6
7
8function f() {
return [1, 2];
}
var a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2忽略一些值
1
2
3
4
5
6
7function f() {
return [1, 2, 3];
}
var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3将剩余数组赋值给一个变量
1
2
3var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
5. 用正则表达式匹配提取值
1
2
3
4
5
6
7
8
var url = "https://developer.mozilla.org/en-US/Web/JavaScript";
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
var [, protocol, fullhost, fullpath] = parsedURL;
console.log(protocol); // "https"
函数递归
递归函数就使用了堆栈:函数堆栈。
应用1:获取树结构中所有的节点
1
2
3
4
5
6
7
8function walkTree(node) {
if (node == null) //
return;
// do something with node
for (var i = 0; i < node.childNodes.length; i++) {
walkTree(node.childNodes[i]);
}
}
箭头函数
箭头函数会捕捉闭包上下文的this值,以词法方式绑定this。
1
2
3
4
5
6
7
8
9function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();