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(表示式){
case 值1:語句1;[break;]
case 值2:語句2;[break;]
case 值3:語句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) {...}
注:
- 相容IE6
for...in...
可以任意順序遍歷一個物件的可列舉屬性,包括原型,對於每個不同的屬性,語句都會被執行;for...in...
只遍歷可列舉屬性;- 如果一個屬性在一次迭代中被修改,在稍後被訪問,其在迴圈中的只是其稍後時間的
// 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...
在可迭代物件(Array
、Map
、Set
、String、TypedArray
、arguments
等)上建立一個迭代迴圈,呼叫自定義迭代鉤子,併為每個不同屬性的值執行語句
由於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能夠跳出或結束多層迴圈, 而不僅僅是當前層迴圈;