11、強制轉換 強制轉換主要指使用Number、String和Boolean三個構造函數,手動將各種類型的值,轉換成數字、字元串或者布爾值。 1>Number強制轉換 參數為原始類型值的轉換規則: 原始類型的值主要是字元串、布爾值、undefined和null,它們都能被Number轉成數值或NaN ...
11、強制轉換
強制轉換主要指使用Number、String和Boolean三個構造函數,手動將各種類型的值,轉換成數字、字元串或者布爾值。
1>Number強制轉換
參數為原始類型值的轉換規則:
- 原始類型的值主要是字元串、布爾值、undefined和null,它們都能被Number轉成數值或NaN。
- NaN:not a number,當數學計算得不到數字結果時,該值就是NaN(Number類型)。
- isNaN:判斷變數是否為NaN。
Number(324) | 值:324 | 字元串如果可以被解析為數值,則轉換為相應的數值 |
Number('324abc') | 值:NaN | 字元串:如果不可以被解析為數值,返回NaN |
Number('') | 值:0 | 空字元串轉為0 |
Number(true) 、Number(false) | 值:1、0 | 布爾值:true 轉成1,false 轉成0 |
Number(undefined) | 值:NaN | undefined:轉成 NaN |
Number(null) | 值:0 | null:轉成0 |
Number函數將字元串轉為數值,要比parseInt函數嚴格很多。基本上,只要有一個字元無法轉成數值,整個字元串就會被轉為NaN。
參數為對象的轉換規則:簡單的規則是,Number方法的參數是對象時,將返回NaN。
Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
實際上,Number背後的真正規則複雜得多,內部處理步驟如下:
1:調用對象自身的valueOf方法。如果返回原始類型的值,則直接對該值使用Number函數,不再進行後續步驟。
2:如果valueOf方法返回的還是對象,則改為調用對象自身的toString方法。如果返回原始類型的值,則對該值使用Number函數,不再進行後續步驟。
3:如果toString方法返回的是對象,就報錯。
2>String強制轉換參數為原始類型值的轉換規則:
數值:轉為相應的字元串。
字元串:轉換後還是原來的值。
布爾值:true轉為"true",false轉為"false"。
undefined:轉為"undefined"。
null:轉為"null"。
參數為對象的轉換規則:String方法的參數如果是對象,返回一個類型字元串;如果是數組,返回該數組的字元串形式。
String內部處理步驟如下:
1:先調用對象自身的toString方法。如果返回原始類型的值,則對該值使用String函數,不再進行以下步驟。
2:如果toString方法返回的是對象,再調用valueOf方法。如果返回原始類型的值,則對該值使用String函數,不再進行以下步驟。
3:如果valueOf方法返回的是對象,就報錯
/*
* 強制類型轉換
* - 指將一個數據類型強制轉換為其他的數據類型
* - 類型轉換主要指,將其他的數據類型,轉換為String 、Number 、Boolean
*
*/
/*
* 將其他的數據類型轉換為String
* 方式一:
* - 調用被轉換數據類型的toString()方法
* - 該方法不會影響到原變數,它會將轉換的結果返回
* - 但是註意:null和undefined這兩個值沒有toString()方法,如果調用他們的方法,會報錯
*
* 方式二:
* - 調用String()函數,並將被轉換的數據作為參數傳遞給函數
* - 使用String()函數做強制類型轉換時,
* 對於Number和Boolean實際上就是調用的toString()方法
* 但是對於null和undefined,就不會調用toString()方法
* 它會將 null 直接轉換為 "null"
* 將 undefined 直接轉換為 "undefined"
*
*/
//1.調用被轉換數據類型的toString()方法
var a = 123;
a = a.toString();
console.log(typeof a); //string
a = true;
a = a.toString();
console.log(typeof a); //string
a = null;
a = a.toString();
console.log(typeof a); //報錯,Uncaught TypeError: Cannot read property 'toString' of null
a = undefined;
a = a.toString();
console.log(typeof a); //報錯,Uncaught TypeError: Cannot read property 'toString' of undefined
//---------------------------------------------------------------------------------------------
//2.調用String()函數,並將被轉換的數據作為參數傳遞給函數
a = 123;
a = String(a);
console.log(typeof a); //string
a = null;
a = String(a);
console.log(typeof a); //string
a = undefined;
a = String(a);
console.log(typeof a); //string
//3.我用Java中的方法,發現也是可以的
var b = 123;
b = "" + b;
console.log(typeof b); //string
3>Boolean強制轉換
參數為原始類型值的轉換規則:轉換規則相對簡單:除了以下六個值的轉換結果為false,其他的值全部為true。
undefined、null、-0、0或+0、NaN、''(空字元串)
參數為對象的轉換規則:所有對象(包括空對象)的轉換結果都是true。
十二、自動轉換
(自動轉換具有不確定性,而且不易除錯,建議在預期為布爾值、數值、字元串的地方,全部使用Boolean、Number和String函數進行顯式轉換。)
自動轉換的規則:預期什麼類型的值,就調用該類型的轉換函數。比如,某個位置預期為字元串,就調用String函數進行轉換。如果該位置可能是字元串,也可能是數值,那麼預設轉為數值。
1:自動轉換為布爾值:當JavaScript遇到預期為布爾值的地方(比如if語句的條件部分),就會將非布爾值的參數自動轉換為布爾值。系統內部會自動調用Boolean函數。
if ( !undefined && !null && !0 && !NaN && !'' )
{ console.log('true'); } // true
// 寫法一 expression ? true : false
// 寫法二 !! expression
2:自動轉換為字元串:當JavaScript遇到預期為字元串的地方,就會將非字元串的數據自動轉為字元串。系統內部會自動調用String函數。字元串的自動轉換,主要發生在加法運算時。當一個值為字元串,另一個值為非字元串,則後者轉為字元串。(+號的拼接字元串的作用)
'5' + 1 // '51' | '5' + true // "5true" | '5' + false // "5false" | '5' + {} // "5[object Object]" |
'5' + [] // "5" | '5' + function (){} // "5function (){}" | '5' + undefined // "5undefined“ | '5' + null // "5null" |
3:自動轉換為數值:當JavaScript遇到預期為數值的地方,就會將參數值自動轉換為數值。系統內部會自動調用Number函數。
自動轉換為數值舉例 | |||
'5' - '2' =3 | '5' * '2'=10 | false - 1=-1 | true - 1= 0 |
'5' * [] = 0 | '1' - 1 = 0 | false / '5' = 0 | 'abc' - 1 = NaN |
4.除加法運算符有可能把運運算元轉為字元串,其他運算符都會把運運算元自動轉成數值。
+'abc' // NaN -'abc' // NaN +true // 1 -false // 0
特殊:(具體原因通過度娘尋根問底)
null == undefined // true
null == false // false
undefined == false // false
var str; //undefined console.log("只定義未初始化的str類型"+typeof(str)+"只定義未初始化的str值"+str) var strone=""; //string console.log("初始化為\"\"的str類型"+typeof(strone)+"初始化為\"\"的str值"+strone) var strtwo=new String(); //無值相當於""; if(""==strtwo) console.log("初始化為new String()的str類型"+typeof(strtwo)+"初始化為new String()的str值"+strtwo) var strthree=null; //object console.log("初始化為null的str類型"+typeof(strthree)+"初始化為null的str值"+strthree) var strfour={}; //object console.log("初始化為{}的str類型"+typeof(strfour)+"初始化為{}的str值"+strfour)
十三、三大結構
1.順序結構
2.選擇結構
3.迴圈結構(當迴圈結構和直到型迴圈結構)
十四、JavaScript語句
(一)選擇語句
1)if語句
(1)單一選擇結構:if(){}
var x=5,y=8; if(y>x) { alert("x>y");}
(2)二路選擇結構:if(){}else{}
// 判斷:如果第一個值大於第二個值則alert(OK!) var x=5,y=8; if(y> x){ document.write('OK!'); } else{ document.write('NOT OK!'); }
(3)三目運算符:?: (condition ? if_true : if_false;)
var x=5,y=8; alert(x> y? 'OK!' : 'NOT OK!')
(4)多路選擇結構:if(){}else if(){}else if(){}else{}
多路選擇結構流程圖:
//此處給出主要代碼為例 if(sScore >= 0 && sScore < 60) { alert('不及格,平常幹啥啦!'); } else if(sScore >= 60 && sScore < 70) { alert('剛剛及格,繼續努力!'); } else if(sScore >= 70 && sScore < 80) { alert('一般,再接再厲!'); } else if(sScore >= 80 && sScore < 90) { alert('良好,穩住,你可以的!'); } else if(sScore >= 90 && sScore < 100) { alert('優秀,戒驕戒躁,爭取滿分!'); } else if(sScore == 100) { alert('勞逸結合,註意身體!'); } else { alert('分數非法!'); }
2)switch語句(考慮多路選擇的案例轉換為switch實現,提示:case後的是具體的情況,多路選擇是以表達式的方式進行判斷,即點和麵的關係。如:80-90範圍這個面通過除以10,然後通過parseInt進行取整。(面轉成點))
語法:switch(condition){case :break;default:}
break具體講解:阻止代碼向下一個case運行。防止case穿透(穿透性用的好還是挺6的,有時間後續補充案例:給定依據具體日期得出這是本年的第多少天的案例)。
default具體講解:匹配不存在時做的事情。
switch:嚴格檢查類型(形似===的檢查),如果不統一,條件不成立(比如說數字的字元串和case後的Number後的數字無法匹配,需轉成相同的類型)
// 判定 switch(iWeekday){ //利用穿透性 case 0: case 7: alert('星期天'); break; case 1: alert('星期一'); break; case 2: alert('星期二'); break; case 3: alert('星期三'); break; case 4: alert('星期四'); break; case 5: alert('星期五'); break; case 6: alert('星期六'); break; default: alert('非法數據!'); }
(二)迴圈語句
1)for迴圈語句
// for迴圈語法 /* for(var i = 0; i < 10; i++){ code... } */ for(var a = 4; a < 10; a++) { document.write(a); } // for迴圈的嵌套 for(var i = 0; i < 5; i++) { for(var j = 0; j < 5; j++) { document.write(i*j + '、'); } document.write('<br>'); }
2)for in語句(可以遍曆數組和對象,經常用於遍歷對象)
遍曆數組
var names = ["nick", "jenny"]; for(var index in names){ console.log(index); console.log(names[index]); }
遍歷對象
var obj = {name: '張三', age: 24, hobby: ['打籃球', '搏擊', '打乒乓球']}; for(var attr in obj) { console.log(obj[attr]); }
3)while迴圈語句
/* while語法 while(condition){ code... } */ var a = 4; while(a < 10) { document.write(a); a++; }
4)do-while語句
/* do...while語法 do{ code... }while(condition); */ var a = 4; do{ document.write(a); a++; } while(a < 10); // while和do...while的區別:執行的順序不一樣 //do...while至少會執行一次代碼塊,while有可能一次都不執行。
(三)Label語句
//label語句 跳出雙重迴圈 例:條件 i=5 j=5 時 跳出嵌套的雙重for迴圈 num=55; var num = 0; outPoint: for (var i=0;i<10;i++) { for (var j=0;j<10;j++) { if (i==5 && j==5) { break outPoint; } num++; } } console.log(num); //控制台輸出
(四)異常處理
try { //這段代碼從上往下運行,其中任何一個語句拋出異常該代碼塊就結束運行 } catch (e) { // 如果try代碼塊中拋出了異常,catch代碼塊中的代碼就會被執行。 //e是一個局部變數,用來指向Error對象或者其他拋出的對象 } finally { //無論上述代碼怎麼,finally代碼塊始終會執行 }
補充:break和continue的區別
// break和continue for(var i = 0; i < 10; i++) { if(i === 5) { break; } document.write(i); } for(var i = 0; i < 10; i++) { if(i === 5) { continue; } document.write(i); } // 區別:break終止迴圈,continue跳過當前迴圈。 // 共同點:都不會執行後面的代碼
十五、函數
函數的概念:函數就是把完成特定功能的一段代碼抽象出來,使之成為程式中的一個獨立實體,起個名字(函數名)。可以在同一個程式或其他程式中多次重覆使用(通過函數名調用)。
註:編寫好的函數代碼只有通過調用才會執行,不調用的時候不會執行(自執行函數特例)。
函數的作用(好處):
1,使程式變得更簡短而清晰
2,有利於程式維護
3,可以提高程式開發的效率 ,
4,提高了代碼的重用性(復用性)
1>函數的創建方式
// 函數聲明式的方式創建函數 function funcName() {} // 函數表達式的方式創建函數 var funcName = function () {}; // 通過構造函數的方式創建函數 // 構造函數:出現在new運算符後的函數,稱為構造函數 var funcName = new Function ();
函數聲明式和函數表達式的區別
// 函數聲明式的方式必須指定函數名 function sum() { alert(1); } sum(); // 函數表達式的方式可以沒有名字 (function () { alert(1); })();
2>函數的調用方式
//創建函數 function hello() { document.write('hello '); document.write('world '); } // 方式1:手動調用 hello(); // 方式2:事件驅動的方式 var oBox = document.getElementById('box'); oBox.onclick = function () { hello(); };
3>函數的參數(形參和實參)
1.手動傳遞的形參和實參
//函數定義時,定義的變數為形參:a,b function sum(a, b) { alert(a + b); }//函數調用時,傳遞的參數值為實參:4,8 sum(4, 8);
補充:對象中,冒號前面的數據可以稱為鍵、下標、或者key,冒號後面的值稱為值或者value
2.JS解析器內置定義的arguments (在函數內部的內置的對象參數,無需自定義可直接使用)
arguments 值類型(對象類型),包含的是實參的個數和數據
function sum(a, b) { // 通過下標的方式獲取某一個值 console.log(arguments[0]); // 通過遍歷的方式獲取所有的值(下標0起始) for(var i = 0; i < arguments.length; i++) { console.log(arguments[i]); //分別控制台列印5,3,8 } a++; //a和arguments[0]和指向相同結果可想而知,相同為6 console.log(arguments[0]); //6 console.log(a); //6 } //手動調用函數 sum(5, 3, 8);
3.return(返回函數執行的結果)
// return關鍵詞 function sum(a, b) { var c = a + b; return c;/*!return只能返回參數只能有一個。return a,b,c 最終返回的結果是c的結果,不會報錯*/ /*!return 後面的代碼不會執行*/ alert('hello world!');//永遠不會被執行 // 函數預設返回的值是undefined } var d = sum(4, 7); console.log(d);
十六、js的解析順序
第一步:載入第一個script代碼塊
第二步:語法檢查
第三步:預解析(將var聲明的變數和聲明式創建的函數放到代碼的最前面)
第四步:開始正式執行代碼,從上往下。
第五步:載入第二個script代碼塊。
sum(); var sum = function () { console.log(a + 8); } alert(a); //undefined alert(b); //報錯 var a = 5; //代碼預解析時,先將a和sum變數放到代碼最前方,然後創建代碼 var a,sum;然後自上而下執行代碼 //預編譯的代碼結構: //var a,sum; //sum(); //var sum = function () { // console.log(a + 8); //} //alert(a); //undefined //alert(b); //報錯 //a = 5;
十七、對象
由若幹個鍵值對組成的無序集合。每個屬性存放一個原始值,對象或函數
屬性:用屬性值來描述他的狀態
行為:用來改變隊形的行為方法
1>對象申明
var obj = { name: 'jimmy', introduce: function () { console.log('我叫jimmy!'); } }; // 通過Object構造函數創建對象 // var obj = new Object(); // 通過自定義的構造函數創建對象 // function Animal() {} // var dog = new Animal(); // console.log(dog);
2>對象的操作
創建對象:
var bird = {feather: '羽毛', 'color': 'white', "type": '鳥類'}; var dog = {};
<1>對象調用
console.log(bird.feather);
console.log(bird["feather"]);
<2>對象增加
方式1:通過.的方式
dog.name = '旺財'; dog.wagTails = function () { console.log('旺財正在搖尾巴!'); }; // dog.wagTails();//調用
方式2:通過[]的方式
dog["name"] = '大黃'; dog['tongues'] = function () { alert('大黃正在吐舌頭!'); } //dog.tongues(); //console.log(dog);
<3>對象修改
bird.feather = 'wing';
bird.color = 'pink';
<4>對象刪除
delete bird.feather;
<5>對象清空
bird = {};
<6>對象銷毀
// JS的垃圾回收機制:JS引擎檢測記憶體,如果某個對象沒有被變數引用,那麼就會直接回收該對象 var obj = {size: 100000000}; obj = null;
十八、值傳遞和址傳遞(引用傳遞)
- 值傳遞:如果變數的值是基本數據類型,那麼傳遞值的時候採用的是值傳遞(把值複製一份給另外一個變數)。
- 址傳遞:如果變數的值是引用數據類型,那麼傳遞值的時候採用的是址傳遞(把地址複製一份給另外一個變數)。
- 相關聯想函數指針(地址)
- 值類型和引用類型記憶體存儲的位置分為棧(小區域少量數據)和堆(大片區域大量數據)
//值類型(值相同,重新開闢記憶體空間) var a= 10; var b = a; a = 0; console.log(b);//10 //引用類型(地址相同,一起變) var a = {num: 10}; var b = a; a.num = 0; console.log(b.num);//0
var a = { name: '張三' }; var b = { name: a }; var c = b; var d = { name: '李四' }; c.name = d; console.log(b.name.name);//張三
十九、常用函數類型
1>回調函數(指針:通過函數名稱的方式執行的函數)
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用為調用它所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。
因此,回調本質上是一種設計模式,並且jQuery(包括其他框架)的設計原則遵循了這個模式。
在JavaScript中,回調函數具體的定義為:函數A作為參數(函數引用)傳遞到另一個函數B中,並且這個函數B執行函數A。我們就說函數A叫做回調函數。如果沒有名稱(函數表達式),就叫做匿名回調函數。
因此callback 不一定用於非同步,一般同步(阻塞)的場景下也經常用到回調,比如要求執行某些操作後執行回調函數。
例子
一個同步(阻塞)中使用回調的例子,目的是在func1代碼執行完成後執行func2。
var func1=function(callback){ //do something. (callback && typeof(callback) === "function") && callback(); } func1(func2); var func2=function(){ }
function sum(a, b, fn) { var c = a + b; if(c > 9) { fn(); } console.log(c); } sum(7, 5, function () { alert(1); });
回調函數的使用場合
資源載入:動態載入js文件後執行回調,載入iframe後執行回調,ajax操作回調,圖片載入完成執行回調,AJAX等等。
DOM事件及Node.js事件基於回調機制(Node.js回調可能會出現多層回調嵌套的問題)。
setTimeout的延遲時間為0,這個hack經常被用到,settimeout調用的函數其實就是一個callback的體現
鏈式調用:鏈式調用的時候,在賦值器(setter)方法中(或者本身沒有返回值的方法中)很容易實現鏈式調用,而取值器(getter)相對來說不好實現鏈式調用,因為你需要取值器返回你需要的數據而不是this指針,如果要實現鏈式方法,可以用回調函數來實現setTimeout、setInterval的函數調用得到其返回值。由於兩個函數都是非同步的,即:他們的調用時序和程式的主流程是相對獨立的,所以沒有辦法在主體裡面等待它們的返回值,它們被打開的時候程式也不會停下來等待,否則也就失去了setTimeout及setInterval的意義了,所以用return已經沒有意義,只能使用callback。callback的意義在於將timer執行的結果通知給代理函數進行及時處理。
2>遞歸函數(自身調用自身的函數)
/* 遞歸函數調用分析: { var num = 1; num++; // 2 if(num < 5) { { var num = 2; num++; // 3 if(num < 5) { { var num = 3; num++; // 4 if(num < 5) { { var num = 4; num++; // 5 if(num < 5) { print(num); } console.log(num); // 5 } } console.log(num); } } console.log(num); } } console.log(num); } */ function print(num) { num++; if(num < 5) { print(num); } console.log(num); } print(1);
3>匿名函數
(function () {})();
4>構造函數
function Person() { alert(1); } var obj = new Person(); console.log(obj);
二十、數組
定義:數組是一個可以存儲一組或一系列相關數據的容器。
為什麼要使用數組?
1:為瞭解決大量相關數據的存儲和使用的問題。
2:模擬真實的世界(班級、軍隊)。
1>數組的操作
1)創建數組
(1)構造函數的方式:var a=new Array();
(2)隱式聲明的方式:var b=[];
2)數組的賦值
構造函數函數的方式
(1)直接賦值:var a=new Array(數據1,數據2,…);
註:var a=new Array(數值) 如果括弧中只有一個元素,並且這個元素是數值類型的,那麼他就是指定數組的長度。 並且它的值都是undefined。
數組的屬性:length 屬性(獲取整個數組的長度)。
(2)先聲明後賦值:var a=new Array(); a[0]=1; a[1]=2; a[2]=3;
隱式聲明賦值
(1)直接賦值: var a=[1,2,3,4];
(2)聲明以後再賦值: var a=[]; a[0]=1; a[1]=2; a[2]=3;
註:JS數組可以存儲任何類型的值。eg: arr[3] = function () {};
3)訪問數組
通過數組的(中括弧)下標訪問。
arr[0-(length-1)] //數組下標從0開始,他的最大值,是length-1。
arr['name'] //關聯數組 通過下表字元串進行訪問
4) 修改數據:
arr[3] = '修改的數據';
5)刪除數據:
delete arr[1];
6)遍曆數組
1:for迴圈。
for(var i = 0; i < arr.length; i++) { console.log(arr[i]); }
2:while迴圈。
var i = 0; while(i < arr.length) { console.log(arr[i]); i++; }
3:for in迴圈。(遍曆數組不常用)
數組的遍歷。
for(var attr in arr){ //attr 數組的下標 console.log(arr[attr]) }
對象屬性的遍歷。
// 使用for in 遍歷對象 var obj = {name: '小明', age: 24, hobby: ['打籃球', '搏擊', '打乒乓球']}; for(var attr in obj) { console.log(obj[attr]); }
2>數組分類
1:按照下標的類型
1.下標是數字的類型叫做(索引數組)
var arr = ['1', '2' , '3'];
2.下標是字元串類型叫做(關聯數組),必須通過對象模擬的形式才能實現,一般不用。
var arr = []; arr['name'] = '張三'; arr['age'] = '28';
3:按照維度來分類
1.一維數組常用的數組就是一維數組
2.二維數組,通過對象模擬的形式才能實現。
聲明二維數組:
var arr=[[1,2,3],[4,5,6]]; alert(arr[1][1]); //值5