Javascript笔记(六)之程序结构与流程控制语句

一、程序结构简介

1、几个基本概念

程序结构分为顺序结构、分支结构、循环结构,通常伴随着这几种程序结构存在的还有流程控制语句;
在ECMA-262规定来一组流程控制语句,语句定义了ECMAScript中的主要语法,语法通常由一个或多个关键字来完成给定的任务,例如:判断、循环、退出等;

语句:在ECMAScript之中,所有的代码都是由语句来构成都。语句表明执行过程中都流程、限定与约定,形式上可以是单行语句,或者由一对大扩号{}括起来都复合语句,在语法描述之中,复合语句整体可以作为一个单行语句处理;

语句的种类:
1、声明语句
变量声明语句、标签声明语句
2、表达式语句
变量赋值语句、函数调用语句、属性赋值语句、方法调用语句
3、分支语句
条件分支语句、多重分支语句
4、循环语句
for、for…in、for…of、while、do…while
5、控制结构
继续执行子句、终端执行子句、函数返回子句、异常触发子句、异常捕获与处理
6、其他语句
空语句;with语句、debugger语句

2、顺序结构

顺序结构是最为简单的结构,程序自上而下依次执行的结构就成为顺序结构

二、分支结构

程序结构分为顺序结构、分支结构、循环结构,通常伴随着这几种程序结构存在的还有流程控制语句

1、if语句

随着条件的不同,我们可以由if结构、if…else…结构、if…else if…else结构。

在if语句的括号里的表达式会进行自动转换为Boolean类型,如果为true,则执行后面一条语句,否则不执行后面那一条语句;
在if条件成立之后,只执行其后的一条语句,如果要执行多条语句,那么必须使用{}包含在内,形成一个代码块;

1.1、if结构

if(表达式)[{]
	// 循环体;
[}]

大括号不存在,则循环体为单行语句,否则为复合语句;

1.2、if…esle…结构

if(表达式) {
     // 表达式为true执行的位置
} else {
	// 表达式为false执行的位置
}

1.3、if…esle if…else结构

if(表达式1) {
     // 表达式1为true执行的位置
}else if(表达式2) {
	// 表达式1为false,表达式2为true执行的位置
}... else{
	// 表达式n-1为false,表达式n为true执行的位置
}

2、条件表达式:三目运算符

	条件表达式?成立执行的表达式:不成立执行的表示;

3、switch…case结构

	switch(表达式){
		case1:语句1;[break;]
		case2:语句2;[break;]
		case3:语句2;[break;]
		case 值n:语句2;[break;]
		[default:] //都不匹配执行的语句;
	}

注: switch语句会先计算表达式,然后在每个case语句去比较表达式的值,使用严格运算符(===),并将控制权转换给该子句;如果都没有则执行defualt子句,然后switch语句执行结束,defualt子句是最后一个子句,但不是必须的;

break语句是可选的,该语句确保可以在相关的case语句执行后,结束switch之后的语句,如果省略,则会继续执行switch语句中的下一条语句;

defualt语句的顺序不是固定的,可以在case之前;

case表达式之中可以使用复杂的运算

三、循环结构

1、while语句

while(表达式) {
   // 循环体
}

while语句中的表达式,也会自动进行类型转换,转换为Boolean类型,当表达式为true的时候,则执行循环体中的内容,否则不执行;

2、do..while语句

do {
  // 循环体
}while(表达式);

do..while语句先运行循环体,在判断,所以该语句结构,不管表达式是否成立,都会执行一次,循环体至少执行一次;

3、for语句

for ([initialization]; [condition]; [final-expression]){
    // 循环体 
}

for循环也被成为for i循环,通常的用法如下

for(var i = 0 ;i < 条件; i++){
    // 循环体
}

4、for...in...语句

语法介绍

for (variable in object) {...}
或者兼容性表达式
for (var variable in object) {...}

注:

  1. 兼容IE6
  2. for...in...可以任意顺序遍历一个对象的可枚举属性,包括原型,对于每个不同的属性,语句都会被执行;
  3. for...in...只遍历可枚举属性;
  4. 如果一个属性在一次迭代中被修改,在稍后被访问,其在循环中的只是其稍后时间的
// for in 遍历对象
var personObj = {
    name:"xiaojia",
    age:26,
    hobby:'football,programming',
    test:function(){
        console.log("111");
    }
}

for(var key in personObj){
    console.log(key,personObj[key]);
}
/* 以下为输出结果
name xiaojia
age 26
26
hobby football,programming
football,programming
test function (){
        console.log("111");
    }
*/

// for in 遍历数组
var arr = ["xiaojia",26,"编程"]
for(var key in arr){
    console.log(key,arr[key]);
}
/* 以下为输出结果
0 xiaojia
1 26
2 编程
*/

for...in...潜在问题与解决方案

1、for...in...只遍历可枚举的属性,包括继承来的属性,不可枚举的属性在重写之后,也变得可枚举,此时可以使用hasOwnProperty()或者Object.defineProperty来解决;

Object.prototype.test = "test1";
Array.prototype.test2 = "test2";

Object.prototype.say1 = function(){
    console.log("你好");
};


Array.prototype.say2 = function(){
    console.log("你好");
};

var arr = ["xiaojia",26,"编程"]
for(var key in arr){
    console.log(key,arr[key]);
}

/*
0 xiaojia
1 26
2 编程
test2 test2
say2 function (){
    console.log("你好");
}
test test1
say1 function (){
    console.log("你好");
}
*/

显然,我们就出现了不属于数组的属性,而是Object继承而来的,我们这里也输出了;解决方案就是使用hasOwnProperty()或者Object.defineProperty来解决;

// 解决方法一:
Object.prototype.test = "test1";
Array.prototype.test2 = "test2";
Object.prototype.say2 = function(){
    console.log("你好");
};
Array.prototype.say3 = function(){
    console.log("你好");
};
var arr = ["xiaojia",26,"编程"]
for(var key in arr){
    if(arr.hasOwnProperty(key)){
        console.log(key,arr[key]);
     }
}

/*
0 xiaojia
1 26
2 编程
test2 test2
say2 function (){
    console.log("你好");
}
test test1
say1 function (){
    console.log("你好");
}
*/

// 解决方法二:使用Object.defineProperty来解决(支持IE9,也支持IE8,但是只支持Dom对象和非标准行为)
Object.defineProperty(Object.prototype,'say',{
            value:function(){
                console.log('say1!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });

Object.defineProperty(Array.prototype,'say',{
            value:function(){
                console.log('say2!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });
var arr = ["xiaojia",26,"Java开发工程师"]
for(var key in arr){
    console.log(key,arr[key]);
}
/*
0 xiaojia
1 26
2 编程
*/

2、for...in...在遍历数组的时候,key为string,而不是int类型;

// for in 存在的问题2
Object.defineProperty(Object.prototype,'say',{
            value:function(){
                console.log('say1!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });

Object.defineProperty(Array.prototype,'say',{
            value:function(){
                console.log('say2!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });
var arr = ["xiaojia",26,"编程"]
for(var key in arr){
    console.log(typeof key);
}
/*
string
string
string
*/

5、for...of...语句(ES6语法)

for (variable of iterable) {
    //statements
}

注: 此为ES6的语法结构,for...of...在可迭代对象(ArrayMapSet、String、TypedArrayarguments等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

由于for...in结构存在问题,所以ES6就推出来一个for..of语法

Object.defineProperty(Object.prototype,'say',{
            value:function(){
                console.log('say1!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });

Object.defineProperty(Array.prototype,'say',{
            value:function(){
                console.log('say2!');
            },
            enumerable: false //让say属性不可枚举,需设置enumerable属性值为false
        });


var arr = ["xiaojia",26,"编程"]
for(var value of arr){
    console.log(value,typeof value);
}

/*
xiaojia string
26 'number'
编程 string
*/

注: IE不兼容,edge12兼容

6、死循环

当条件的恒成立的时候,就构成来死循环了;

7、for...of...for...in...的区别

结论:
1、for...in...循环的是key,for...of...循环的是value
2、推荐在循环对象属性的时候,使用for...in...,在遍历数组的时候使用for...of...fori或者Array.prototype.forEach()
3、for...of...是ES6新引入的特性,修复了ES5的for...in...的不足
4、for...of...不能循环普通的对象,需要通过和Object.keys()搭配使用
5、for...of...不兼容IE,for...in...兼容ie6

四、流程控制语句

1、break

break用于终止switch语句的执行,和跳出当前循环,也可以跳出指定标号位置的循环;

2、continue

continue用于结束当前循环,继续下一轮循环;

3、标号的使用

所谓标号,就是label:,一般就是为某个代码段设置一个标记,方便break和continue能够跳出或结束多层循环, 而不仅仅是当前层循环;

你可能感兴趣的:(前端笔记之javascript)