javascript
JS数据类型及函数的预编译
1.JS總體上分為:原始值和引用值
原始值分為:Number、Boolean、String、undefined、null;原始值不可改變的值,存儲(chǔ)在棧【stack】的,先進(jìn)后出!
? ? ? ? 引用值:array、Object、function、date、RegExp;原始值是可改變的,引用值大體是存儲(chǔ)在堆【heap】中;
說明:一個(gè)變量經(jīng)過聲明,但是沒有賦值,默認(rèn)情況下就是undefined!例如:
1 <body> 2 <script type="text/javascript"> 3 var b; 4 document.write(b); 5 </script> 6 </body> View Code2.JS錯(cuò)誤分為:低級(jí)錯(cuò)誤【語(yǔ)法解析錯(cuò)誤】和邏輯錯(cuò)誤【標(biāo)準(zhǔn)錯(cuò)誤,情有可原】,每個(gè)js語(yǔ)句后面都要以;【分號(hào)】結(jié)尾,但是函數(shù)、for循環(huán)、if語(yǔ)句后面不需要加分號(hào);
? ①. 低級(jí)錯(cuò)誤:
1 <script type="text/javascript"> 2 var a=1; 3 var b=2: 4 var c=3; 5 document.write(b); 6 </script> View Code像上面這種,本來b后面是需要加分號(hào)的,結(jié)果卻是加上了冒號(hào),所以這叫語(yǔ)法解析錯(cuò)誤!
? ②.邏輯錯(cuò)誤:
1 <script type="text/javascript"> 2 var a=1; 3 var c=3; 4 document.write(b); 5 </script> View Code上面這段代碼明明沒有變量b,但是我們這里愣是使用了document.write(b)將變量b的值輸出了,這是邏輯錯(cuò)誤!
?
3.一個(gè)html頁(yè)面中可以使用多個(gè)js代碼塊,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a=1; 4 </script> 5 <script type="text/javascript"> 6 document.write(a); 7 </script> 8 </body> View Code我們從上面的js代碼塊中聲明了變量a,但是是從下面的js代碼塊中輸出了變量a,這和從一個(gè)代碼塊中聲明a和輸出a沒有區(qū)別!要真說有沒有區(qū)別呢?實(shí)際上也是有點(diǎn)的,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a=1; 4 document.write(c); 5 </script> 6 <script type="text/javascript"> 7 var b=2; 8 document.write(b); 9 </script> 10 </body> View Code這樣有多個(gè)代碼塊的時(shí)候,當(dāng)一個(gè)代碼塊中【上邊的代碼塊】出了錯(cuò)誤并不會(huì)影響下面代碼塊!
?
4.運(yùn)算操作符:
+ 號(hào),作用:
? ? ? ? ? ? ①.數(shù)學(xué)運(yùn)算
? ? ? ? ? ? ②.任意數(shù)據(jù)類型和字符串相加都是字符串
5.凡是該返回一個(gè)數(shù)字的,但是又不知道這個(gè)數(shù)字是幾的時(shí)候就會(huì)返回一個(gè)NaN【Not a Number】
? ?eg:? ?
1 <body> 2 <script type="text/javascript"> 3 var a = 0/0; 4 document.write(a); 5 </script> 6 </body> View Code如果是1/0,則返回值就是無限的Infinity,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a = 1/0; 4 document.write(a); 5 </script> 6 </body> View Code如果是-1/0則結(jié)果就是負(fù)無窮【-Infinity】,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a = -1/0; 4 document.write(a); 5 </script> 6 </body> View Code?
6.==是比較運(yùn)算符,返回值為Boolean類型;如1==1,返回true;再例如:
1 <body> 2 <script type="text/javascript"> 3 a = Infinity == Infinity; 4 document.write(a); 5 </script> 6 </body> View Code返回值也是true;但是有一個(gè)特例:NaN,這家伙一急眼連自己都不認(rèn)識(shí),如下:
1 <body> 2 <script type="text/javascript"> 3 a = NaN == NaN; 4 document.write(a); 5 </script> 6 </body> View Code返回值為false;
?
7.&&【與】、||【或】、!【非】
? ?&&:與運(yùn)算符,當(dāng)&&連接兩個(gè)表達(dá)式或者數(shù)值的時(shí)候,先看&&號(hào)前面的數(shù)值,如果該值轉(zhuǎn)換成布爾值為false,則直接返回該值,
? ? ? ? ?如果該值轉(zhuǎn)換為布爾值為true,則直接返回&&后面的值。eg:
1 <body> 2 <script type="text/javascript"> 3 a = 0 && 2; 4 document.write(a); 5 </script> 6 </body> View Code返回值就為0,如果是下面的這個(gè)例子:
1 <body> 2 <script type="text/javascript"> 3 a = 1 && 2+2; 4 document.write(a); 5 </script> 6 </body> View Code則返回值就為4;
所以:&&運(yùn)算符連接兩個(gè)表達(dá)式或者變量的時(shí)候,全真才是真,有一個(gè)為假,就返回假!
當(dāng)&&連接多個(gè)表達(dá)式或者變量的時(shí)候,只要是&&前面的為真,那么它就往后走,直到遇到轉(zhuǎn)換成布爾值為false的值的時(shí)候就直接返回該值【不用管真或者假】,如果直到最后都是真,那么返回最后一個(gè)值!如下:
1 <body> 2 <script type="text/javascript"> 3 a = 1+2 && 2+2 && 3-3 && 1+3; 4 document.write(a); 5 </script> 6 </body> View Code返回值就是0,而如下代碼:
1 <body> 2 <script type="text/javascript"> 3 a = 1+2 && 2+2 && 3-2 && 1+3; 4 document.write(a); 5 </script> 6 </body> View Code返回值就是4;
注意:undifined、null、NaN、""【空串】、0、false ?這六個(gè)值轉(zhuǎn)換成Boolean值之后都是false!
?
||:或操作運(yùn)算符,它和&&運(yùn)算符的區(qū)別是:&&運(yùn)算符遇到false的時(shí)候停止,而||或運(yùn)算符是遇到true的時(shí)候返回,如果到最后沒遇到為true的,那么就把最后一個(gè)返回!例如:
1 <body> 2 <script type="text/javascript"> 3 var a= 4 || 3; 4 document.write(a); 5 </script> 6 </body> View Code返回的是4,而如果是:
1 <body> 2 <script type="text/javascript"> 3 var a= 0 || 3; 4 document.write(a); 5 </script> 6 </body> View Code返回的就是3,如果是:
1 <body> 2 <script type="text/javascript"> 3 var a= 0 || false || null; 4 document.write(a); 5 </script> 6 </body> View Code返回的就是null;
?
!是取反的意思,這個(gè)非運(yùn)算符會(huì)首先將運(yùn)算符后面的表達(dá)式或者數(shù)字給轉(zhuǎn)換成布爾值,然后取反操作,例如:
1 <body> 2 <script type="text/javascript"> 3 var a = 4; 4 document.write(!a); 5 </script> 6 </body> View Code返回值為false;
如果是:
1 <body> 2 <script type="text/javascript"> 3 var a = undefined; 4 document.write(!a); 5 </script> 6 </body> View Code則返回值為true;
當(dāng)然javaScript中還有&、|,這個(gè)&、|是二進(jìn)制的與、或【也就是會(huì)先把兩邊的數(shù)值轉(zhuǎn)換成二進(jìn)制,然后進(jìn)行相與的操作或者或的操作,實(shí)際開發(fā)中幾乎不用】!
?
在瀏覽器接收用戶輸入的數(shù)據(jù),案例如下:
1 <body> 2 <script type="text/javascript"> 3 var score =parseInt(window.prompt("input")); 4 if(score == 100){ 5 alert("滿分"); 6 } 7 </script> 8 </body> View Code?
if與&&的相互轉(zhuǎn)換,如下所示:
1 <body> 2 <script type="text/javascript"> 3 if(2>1){ 4 document.write("哈嘍"); 5 } 6 2>1 && document.write("哈嘍"); 7 </script> 8 </body> View Code上面兩種方式輸出都是一樣的,體現(xiàn)了if與&&的相互轉(zhuǎn)換!
?
8.注釋
? ? javascript就兩種注釋【和java是一致的】,一種是單行注釋//,另外一種是多行注釋/**/
? ? css注釋:就一種注釋,就是這種段落注釋/*注釋文字*/
? ? html注釋:一種:<!--注釋文字-->
?
9.if.... else if...else語(yǔ)句:
1 <body> 2 <script type="text/javascript"> 3 var score = window.prompt("score"); 4 if(score > 90 && score <= 100){ 5 document.write('alibaba'); 6 }else if(score > 80 && score <=90){ 7 document.write('tencent'); 8 }else if(score > 70 &&score <=80){ 9 document.write('baidu'); 10 }else if(score < 60 ){ 11 document.write('are you kidding me?'); 12 }else{ 13 document.write('滾'); 14 } 15 </script> 16 </body> View Code10.for循環(huán):
1 <script type="text/javascript"> 2 for(var i=1;i<10;i++){ 3 document.write(i); 4 } 5 </script> View Code11.while循環(huán)
1 <script type="text/javascript"> 2 var i=0; 3 while(i < 5){ 4 document.write(i); 5 i++; 6 } 7 </script> View Codedo...while循環(huán):
1 <body> 2 <script type="text/javascript"> 3 var i =window.prompt("變量i"); 4 do{ 5 document.write(i); 6 i++; 7 }while(i < 5) 8 </script> 9 </body> View Code?12.switch...case語(yǔ)句
1 <body> 2 <script type="text/javascript"> 3 var i =window.prompt("變量i"); 4 switch(i){ 5 case "a": 6 console.log("result a"); 7 break; 8 case 2: 9 console.log("result 2"); 10 break; 11 case true: 12 console.log("result true"); 13 break; 14 default: 15 console.log("完了"); 16 } 17 </script> 18 </body> View Code?
13.arr數(shù)組【遍歷、賦值、創(chuàng)建、length屬性】
1 <body> 2 <script type="text/javascript"> 3 var arr=[1,2,3,4,5,"bad",undefined,true]; 4 for(var i=0;i<arr.length;i++){ 5 document.write(arr[i]); 6 } 7 arr[0]=false; 8 for(var i=0;i<arr.length;i++){ 9 document.write(arr[i]); 10 } 11 </script> 12 </body> View Code?
14.對(duì)象
1 <body> 2 <script type="text/javascript"> 3 var zhangsan={ 4 lastName:"小李", 5 age:13, 6 sex:true, 7 handsome:false 8 } 9 10 console.log(zhangsan.lastName); 11 zhangsan.lastName="張三"; 12 console.log(zhangsan.lastName); 13 </script> 14 </body> View Code?
15.typeof可以返回?cái)?shù)據(jù)的類型,返回值【6個(gè)】可以是:Number、String、Boolean、Object、undefined、function;
? ? 對(duì)于Number數(shù)字類型、String字符串類型、及Boolean布爾類型沒啥可說的,那啥時(shí)候返回Object類型呢?
? ? 對(duì)于{name:"張三"}【對(duì)象】、[1,2,"數(shù)字"]【數(shù)組】、及null,我們使用typeof測(cè)試的時(shí)候都是返回Object類型!如下所示:
1 <body> 2 <script type="text/javascript"> 3 document.write(typeof([1,"ds"])); 4 document.write(typeof(null)); 5 document.write(typeof({name:"張安"})); 6 </script> 7 </body> View Code 1 <body> 2 <script type="text/javascript"> 3 var fun = function(){} 4 document.write(typeof(fun)); 5 </script> 6 </body> View Code返回值是function類型,如果我們對(duì)一個(gè)不定義或者定義為undefined,那么我們使用typeof進(jìn)行類型檢測(cè)的時(shí)候,也會(huì)返回undefined!
1 <body> 2 <script type="text/javascript"> 3 var fun = undefined; 4 document.write(typeof(fun)); 5 document.write(typeof(a)); 6 </script> 7 </body> View Code注意哦,Number(null)為0,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var num = null; 4 document.write(Number(num)); 5 </script> 6 </body> View Code?
16.function函數(shù):
? ? ?①.函數(shù)聲明
? ? ?②.函數(shù)執(zhí)行
? ? ?代碼案例:
1 <body> 2 <script type="text/javascript"> 3 function test(){ 4 document.write("哈哈"); 5 } 6 test(); 7 </script> 8 </body> View Code? ? 函數(shù)參數(shù):
①.形式參數(shù)
②.實(shí)際參數(shù)
? 注意:形式參數(shù)的個(gè)數(shù)可以比實(shí)際參數(shù)的多,也可以少【類似于其它語(yǔ)言的可變參數(shù)】!實(shí)際上在形式參數(shù)中
? ? ?有一個(gè)參數(shù)arguments的參數(shù),這個(gè)參數(shù)默認(rèn)會(huì)將所有的實(shí)參都接收!如下代碼所示:
1 <body> 2 <script type="text/javascript"> 3 function test(a,b){ 4 console.log(arguments); 5 document.write(a); 6 document.write(b); 7 } 8 test(13,14,15); 9 document.write("<br/>"); 10 function testFunction(a,b){ 11 console.log(arguments); 12 document.write(a); 13 document.write(b); 14 } 15 testFunction(13); 16 </script> 17 </body> View Code當(dāng)然也可以通過arguments.length查看實(shí)際參數(shù)的長(zhǎng)度,而函數(shù)名.length獲取形參的長(zhǎng)度!
1 <body> 2 <script type="text/javascript"> 3 function test(a,b){ 4 console.log(test.length);//形參的長(zhǎng)度 5 console.log(arguments.length);//實(shí)參的長(zhǎng)度 6 } 7 test(13,14,15); 8 </script> 9 </body> View Code? ? 函數(shù)返回值:
?
?17. JS運(yùn)行的兩大特點(diǎn):
①.單線程
? ? ? ? ②.解釋執(zhí)行
?
18. ?JS代碼執(zhí)行流程【js執(zhí)行的三部曲】:
1.語(yǔ)法解析【提前掃描一遍】
2.預(yù)編譯
? ? ? ?3.解釋執(zhí)行
?
我們現(xiàn)在就講預(yù)編譯:
?如下所示:正常情況下,我先聲明函數(shù),然后再調(diào)用函數(shù),是沒有問題的,如下:
1 <body> 2 <script type="text/javascript"> 3 function testFunction(){ 4 document.write("Hello World!"); 5 } 6 testFunction(); 7 </script> 8 </body> View Code這樣是沒問題的,但是如果我們是如下代碼:
1 <body> 2 <script type="text/javascript"> 3 testFunction(); 4 function testFunction(){ 5 document.write("Hello World!"); 6 } 7 </script> 8 </body> View Code將聲明寫在后面,函數(shù)調(diào)用寫在前面,你發(fā)現(xiàn)也是沒問題的,這是為什么呢?預(yù)編譯在起作用!接著如果是變量的話,正常如下:
1 <body> 2 <script type="text/javascript"> 3 var a = 123; 4 console.log(a); 5 </script> 6 </body> View Code正常情況下這也是沒問題的,先聲明再調(diào)用!但是如下,如果我先調(diào)用再聲明,如下:
1 <body> 2 <script type="text/javascript"> 3 console.log(a); 4 var a = 123; 5 </script> 6 </body> View Code你會(huì)發(fā)現(xiàn)返回值是undefined,但是沒有報(bào)錯(cuò)哦,如果我的代碼再變,如下:
1 <body> 2 <script type="text/javascript"> 3 console.log(a); 4 </script> 5 </body> View Code你會(huì)發(fā)現(xiàn)代碼報(bào)錯(cuò)了!上面其實(shí)基本上都是預(yù)編譯在起作用!
?
總結(jié):1.函數(shù)聲明整體提升【也就是無論函數(shù)在哪里聲明的,js在預(yù)編譯的時(shí)候會(huì)將這個(gè)函數(shù)的聲明提到j(luò)s代碼的最前面】
? ? ? ? ? ?2.變量 ?聲明提升【也就是說:對(duì)于變量而言,預(yù)編譯僅僅是聲明提升到j(luò)s代碼的最前面,賦值不提升】,所以剛才先
? ? ? ? ? ? ? 打印a的時(shí)候有一個(gè)是undefined,但是不報(bào)錯(cuò),因?yàn)槁暶髟陬A(yù)編譯的時(shí)候已經(jīng)提到j(luò)s代碼的最前面了!
? ? ? ? ? ? ?
預(yù)編譯前奏:
? ? ①.imply global 暗示全局變量:即任何變量,如果變量未經(jīng)聲明就賦值,此變量就為全局對(duì)象【window對(duì)象】所有!
? ? ? ?例如: ?a = 123 就相當(dāng)于window.a = 123;
1 <body> 2 <script type="text/javascript"> 3 a = 10; 4 console.log(a); 5 console.log(window.a); 6 </script> 7 </body> View Code再來個(gè)經(jīng)典案例,并附有解釋,如下:
1 <script type="text/javascript"> 2 function testFunction(){ 3 var a = b = 3;// 4 /* 5 注意賦值操作:一定是從右到做的一個(gè)順序 6 也就是說:上述代碼的執(zhí)行順序是:先將3賦值給b,然后再聲明a,然后將b賦值給a,但是在這個(gè)過程中 7 缺少了一部聲明b變量的過程,這就導(dǎo)致了b未聲明,我們說未聲明就賦值的變量是全局變量,此變量為 8 全局對(duì)象【window對(duì)象】所有!所以我們可以在控制臺(tái)上訪問window.b輸出3,但是訪問不 9 到window.a變量,因?yàn)閍變量不是全局變量 10 */ 11 } 12 testFunction(); 13 </script> 14 </body> View Code②.一切聲明的全局變量,全是window的屬性,window就是全局的域【相當(dāng)于一個(gè)倉(cāng)庫(kù)】!
? ? ? 例如:var a = 123; =====> window.a = 123;
? ? ? ? ? ? ? ? ?也可以這樣理解:var a ?= 123;就相當(dāng)于
window {
a:123;
}
? ? ? ? ? ? ? ? ? 即相當(dāng)于給window對(duì)象加了一個(gè)a屬性,屬性值為123;
? ? ? ? 其實(shí):
1 <body> 2 <script type="text/javascript"> 3 a = 10; 4 console.log(a); 5 </script> 6 </body> View Code這里的console.log(a)就相當(dāng)于console.log(window.a);
??
函數(shù)預(yù)編譯【四步】:預(yù)編譯的過程發(fā)生在函數(shù)執(zhí)行的前一刻【也就是這個(gè)函數(shù)要執(zhí)行了,但是還沒執(zhí)行的時(shí)候就先進(jìn)行預(yù)編譯操作,預(yù)編譯之后函數(shù)才會(huì)一行一行的執(zhí)行】!
①.創(chuàng)建AO對(duì)象【Activation Object:活動(dòng)對(duì)象,也叫執(zhí)行期上下文】,這個(gè)AO對(duì)象實(shí)際上就是這個(gè)函數(shù)產(chǎn)生的一個(gè)存儲(chǔ)空間庫(kù),即:AO{ }!
②.找形參和變量聲明,將變量名和形參名作為AO屬性名,值為undefined!
? ? ? ? ③.將實(shí)參值和形參統(tǒng)一
? ? ? ? ④.在函數(shù)體里面找函數(shù)聲明,函數(shù)聲明的名作為AO對(duì)象的名,值賦予函數(shù)體
預(yù)編譯之后進(jìn)行函數(shù)的執(zhí)行;
我們先來看看下面這個(gè)js函數(shù)的的執(zhí)行,請(qǐng)說出執(zhí)行結(jié)果:
1 <body> 2 <script type="text/javascript"> 3 function fn(a){ 4 console.log(a); 5 var a = 123; 6 console.log(a); 7 function a(){} 8 console.log(a); 9 var b = function(){}; 10 console.log(b); 11 function d(){} 12 } 13 fn(1); 14 </script> 15 </body> View Code我們先不說其執(zhí)行結(jié)果是啥:我們來看看其執(zhí)行過程,該函數(shù)執(zhí)行之前先進(jìn)行預(yù)編譯操作,預(yù)編譯之后再執(zhí)行;
我們來說一下預(yù)編譯的過程:
①.
創(chuàng)建AO對(duì)象,AO{
?}
②.找形參和變量聲明,將變量名和形參名作為AO屬性名,這里找到了形參a和變量聲明a和b,然后由于變量名和
? ? 形參名重復(fù),所以只保留變量名a就ok了【變量在后面】,然后將形參和變量名作為AO對(duì)象的屬性,值為undefined,
如下所示:
AO{
a:undefined,
b:undefined
}
③.將形參和實(shí)參相統(tǒng)一,這里的實(shí)參1就傳遞給了形參a,實(shí)際上也就是傳遞給了AO對(duì)象的屬性a,所以AO對(duì)象變?yōu)?#xff1a;
AO{
a:1,
b:undefined
}
④.在函數(shù)體里面找函數(shù)聲明,在上面的函數(shù)里面只有兩個(gè)函數(shù)聲明a和函數(shù)聲明d,注意:函數(shù)b不是函數(shù)聲明,
? ? 而是函數(shù)表達(dá)式,這是兩個(gè)概念,需要區(qū)分;函數(shù)聲明的名作為AO對(duì)象的名,值賦予函數(shù)體,如下所示:
AO{
a:function a(){},
b:undefined,
d:function d(){}
}
?
上面四步是預(yù)編譯的四步,編譯好了之后AO對(duì)象也就創(chuàng)建好了,這時(shí)候就可以進(jìn)行函數(shù)執(zhí)行了,函數(shù)執(zhí)行的時(shí)候,貌似我們使用console.log(a)輸出的是a,但是實(shí)際上輸出的是AO對(duì)象中的a屬性對(duì)應(yīng)的值!所以上面的函數(shù)第一次打印的時(shí)候打印的是AO中的a,AO中的a屬性對(duì)應(yīng)的屬性值是function a(){},所以此時(shí)我們用console.log(a)輸出的就是function a(){},而接著一行一行的執(zhí)行,又到了var a = 123;其實(shí)在預(yù)編譯的時(shí)候的第二步,我們將形參和變量名都作為了AO對(duì)象的屬性名,這其實(shí)本身就是變量聲明的提升,變量聲明已經(jīng)在編譯的時(shí)候提升上去了,所以在執(zhí)行的時(shí)候又聲明我這里就不用管了,但是此時(shí)a=123賦值還沒有讀呢,所以此時(shí)就會(huì)將AO對(duì)象的a屬性賦值為123,然后我們接著使用console.log(a);輸出的時(shí)候輸出的就是AO對(duì)象中的a的屬性值123,同理:function a(){}在預(yù)編譯的時(shí)候也已經(jīng)提升上去了,所以這里在執(zhí)行的時(shí)候就不用看了,然后繼續(xù)執(zhí)行后面的console.log(a);再次輸出123,然后執(zhí)行下面的var b = function(){};實(shí)際上這里僅僅是執(zhí)行了給AO對(duì)象的屬性b的賦值,即:
AO{
a:function a(){},
b:function(){},
d:function d(){}
}
并沒有變量b的聲明,因?yàn)樽兞縝的聲明在預(yù)編譯的時(shí)候已經(jīng)提升上去了,所以此時(shí)console.log(b)輸出的就是function(){};到此函數(shù)執(zhí)行結(jié)束!
?所以上面函數(shù)的輸出值為:
這道題的復(fù)雜程度包含:形參名和變量名和函數(shù)名重復(fù)的問題,所以我們需要解決一個(gè)優(yōu)先級(jí)順序的問題,包括:誰(shuí)覆蓋誰(shuí)的問題,再包括執(zhí)行順序是影響變量還是函數(shù)啦這樣的一些問題,什么能解決這樣的問題呢?就是預(yù)編譯能解決這樣的問題!
依據(jù)上述預(yù)編譯及執(zhí)行順序,我們?cè)賮砜匆粋€(gè)例子,如下所示:
1 <body> 2 <script type="text/javascript"> 3 function test(a,b){ 4 console.log(a); 5 c = 0; 6 var c; 7 a = 3; 8 b = 2; 9 console.log(b); 10 function b(){} 11 function d(){} 12 console.log(b); 13 } 14 test(1); 15 </script> 16 </body> View Code代碼的執(zhí)行結(jié)果為:
?注意:只有函數(shù)聲明可以提升,而函數(shù)表達(dá)式是不可以提升的!再來檢測(cè)一例子:
1 <body> 2 <script type="text/javascript"> 3 function test(a,b){ 4 console.log(a); 5 console.log(b); 6 var b = 234; 7 console.log(b); 8 a = 123; 9 console.log(a); 10 function a(){} 11 var a ; 12 b = 234; 13 var b = function(){} 14 console.log(a); 15 console.log(b); 16 } 17 test(1); 18 </script> 19 </body> View Code注意:預(yù)編譯不僅發(fā)生在函數(shù)里,還發(fā)生在全局!如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a = 123; 4 console.log(a); 5 </script> 6 </body> View Code正常情況下,輸出a的值是123是沒問題的,而如果我將console.log(a)提到前面,那么如下:
1 <body> 2 <script type="text/javascript"> 3 console.log(a); 4 var a = 123; 5 </script> 6 </body> View Code此時(shí),輸出a的值為undefined,因?yàn)樽兞柯暶魇强梢蕴崆暗?#xff01;而如果我將var a =123,直接去掉,那么如下:
1 <body> 2 <script type="text/javascript"> 3 console.log(a); 4 </script> 5 </body> View Code此時(shí)就會(huì)報(bào)錯(cuò)了,因?yàn)闆]有這個(gè)變量嘛!如果我是如下寫法:
1 <body> 2 <script type="text/javascript"> 3 console.log(a); 4 var a = 123; 5 function a(){} 6 </script> 7 </body> View Code此時(shí)輸出的a的值就是函數(shù)a了!這些其實(shí)都是預(yù)編譯的結(jié)果!
?
對(duì)于全局的預(yù)編譯而言實(shí)際上就三步【和函數(shù)的預(yù)編譯相比缺少了:實(shí)參給形參傳值這一步】:
①.創(chuàng)建GO對(duì)象【Global Object:全局對(duì)象,也叫執(zhí)行期上下文】,這個(gè)GO對(duì)象實(shí)際上就是這個(gè)函數(shù)產(chǎn)生的一個(gè)存儲(chǔ)空間庫(kù),即:GO{ }!
②.找變量聲明,將變量名和形參名作為GO屬性名,值為undefined!
? ? ? ? ③.在函數(shù)體里面找函數(shù)聲明,函數(shù)聲明的名作為GO對(duì)象的名,值賦予函數(shù)體
所以,做個(gè)小測(cè)試,如果我將console.log(a)輸出a的時(shí)候,你就會(huì)看到輸出的a的值是123,如下所示:
1 <body> 2 <script type="text/javascript"> 3 var a = 123; 4 function a(){} 5 console.log(a); 6 </script> 7 </body> View Code?
注意:這里的GO實(shí)際上就是window對(duì)象,也就是:GO == window;所以我們?cè)谌侄x好了變量自動(dòng)就會(huì)存儲(chǔ)到GO對(duì)象中,而GO對(duì)象就是window對(duì)象,所以我們可以直接使用window對(duì)象來訪問這些屬性,顯然是沒問題的!實(shí)際上GO和window是同一個(gè)事物的兩個(gè)名稱而已!所以我們看到下面兩句實(shí)際上是一樣的:
console.log(window.a);//這個(gè)window.a實(shí)際上也就是GO.a
console.log(a);//這個(gè)a會(huì)自動(dòng)去GO對(duì)象中去拿的
?
上面我們講到一個(gè)變量未經(jīng)聲明就賦值,那這個(gè)變量是屬于全局變量,該全局變量是屬于全局對(duì)象window所擁有的,換句話說:一個(gè)變量未經(jīng)聲明就賦值,實(shí)際上這個(gè)變量是放入到GO中去預(yù)編譯的,如下代碼:
1 <body> 2 <script type="text/javascript"> 3 function test(){ 4 var a = b = 4; 5 } 6 test(); 7 console.log(b); 8 console.log(a); 9 </script> 10 </body> View Codeb的值輸出的是4,而輸出a的時(shí)候報(bào)錯(cuò)了,需要注意:函數(shù)必須執(zhí)行,如果不執(zhí)行,即如果沒有【test()】,那么不會(huì)有預(yù)編譯,函數(shù)沒有經(jīng)過預(yù)編譯,那么b的值也是輸出不了的,這點(diǎn)千萬要注意!而且上述代碼相當(dāng)于:
AO{
a:4;
}
GO{
b:4;
}
即:b歸GO對(duì)象擁有,而a變量歸AO對(duì)象擁有!所以我們?cè)趖est()函數(shù)內(nèi)部如果輸出window.b是沒有問題的,因?yàn)閣indow==GO,而如果我們輸出window.a則不輸出不了,如下所示:
1 <body> 2 <script type="text/javascript"> 3 function test(){ 4 var a = b = 4; 5 console.log(window.b); 6 console.log(window.a); 7 } 8 test(); 9 </script> 10 </body> View Code輸出結(jié)果如下所示:
?
再引申一下給大家,你們說是先生成AO呢還是先生成GO呢?答案是:肯定是先生成GO對(duì)象啊,代碼如下所示:
1 <body> 2 <script type="text/javascript"> 3 console.log(test); 4 function test(test){ 5 console.log(test); 6 var test = 234; 7 console.log(test); 8 function test(){} 9 } 10 test(1); 11 var test = 123; 12 </script> 13 </body> View Code代碼會(huì)怎樣輸出呢?
代碼會(huì)首先進(jìn)行全局編譯,然后按著整體編譯的三步曲,生成GO對(duì)象,如下:
GO{
test:undefined;
}
緊接著將函數(shù)提升,得到如下所示:
GO{
test:function test(){}
}
然后就開始執(zhí)行代碼:
先執(zhí)行console.log(test);此時(shí)的test其實(shí)就是上面GO對(duì)象的屬性test,值為function test(){};接著就越過函數(shù)test,因?yàn)閯偛旁谡w預(yù)編譯的時(shí)候就已經(jīng)將函數(shù)test提升了,繼續(xù)往下走,執(zhí)行test(1),但是在執(zhí)行test(1)之前的一刻會(huì)有一個(gè)預(yù)編譯的過程,編譯test函數(shù),首先生成AO對(duì)象,然后將參數(shù)和變量名作為AO對(duì)象的屬性,如下所示:
AO{
? ?test:undefined
}
變成:
AO{
? ?test:123
}
然后將函數(shù)實(shí)參和形參統(tǒng)一【即傳值】,如下:
AO{
test:1
}
然后,我們可以緊接著函數(shù)名提升,并賦值:
AO{
test:function test(){}
}
上面是函數(shù)預(yù)編譯的過程,預(yù)編譯之后就開始執(zhí)行函數(shù)代碼,首先執(zhí)行console.log(test)輸出test屬性,但是這個(gè)test屬性是用AO對(duì)象的呢還是使用GO對(duì)象的呢,畢竟這兩個(gè)對(duì)象里面都有test屬性,這個(gè)時(shí)候AO對(duì)象和GO對(duì)象就會(huì)形成一個(gè)鏈條,這個(gè)鏈條以近的為主,如果AO有就使用AO對(duì)象的,AO沒有的情況下在使用GO的,所以此時(shí)會(huì)打印AO對(duì)象的test屬性,得到函數(shù)體function test(){},然后緊接著執(zhí)行test=234賦值操作,然后執(zhí)行下一條輸出console.log(test);此時(shí)輸出的就是234,所以最終結(jié)果就是:
?
再來下面的一端代碼我們來檢驗(yàn)一下學(xué)習(xí)情況:
1 <body> 2 <script type="text/javascript"> 3 global = 100; 4 function fn(){ 5 console.log(global); 6 global = 200; 7 console.log(global); 8 var global = 300; 9 } 10 fn(); 11 var global; 12 </script> 13 </body> View Code其過程如下:
首先是整體預(yù)編譯,【三部曲】,先生成GO對(duì)象,然后將變量和函數(shù)提升及函數(shù)賦值,得到如下:
GO{
global:undefined;
fn:function fn(){}
}
整體預(yù)編譯之后,然后整體執(zhí)行,先執(zhí)行g(shù)lobal =100,則轉(zhuǎn)變?yōu)?#xff1a;
GO
{
global:100;
fn:function fn(){}
},由于函數(shù)聲明在整體預(yù)編譯的時(shí)候已經(jīng)提升了,所以這里不管,接著執(zhí)行下面的fn()調(diào)用函數(shù)fn,注意,在調(diào)用函數(shù)fn的前一刻,我們先執(zhí)行預(yù)編譯的操作,預(yù)編譯fn,預(yù)編譯函數(shù)【函數(shù)編譯四部曲】,首先生成AO對(duì)象,然后變量提升,傳遞參數(shù),函數(shù)提升并賦值,如下所示:
AO{
global:undefined;
}
這是函數(shù)預(yù)編譯的四部曲,預(yù)編譯之后,緊接著進(jìn)行函數(shù)的執(zhí)行,執(zhí)行console.log(global),由于AO對(duì)象存在global屬性,所以這里輸出的是AO對(duì)象的global屬性【當(dāng)然如果AO對(duì)象不存在global屬性,會(huì)找到GO對(duì)象的global屬性,打印出來】,所以輸出undefined,然后繼續(xù)執(zhí)行g(shù)lobal = 200,此時(shí)AO對(duì)象的global屬性就變成了200,然后執(zhí)行console.log(global)輸出此時(shí)的200,最后再執(zhí)行g(shù)lobal = 300,就會(huì)將AO對(duì)象的global屬性改為300,此時(shí)總體執(zhí)行結(jié)束,所以最終的輸出結(jié)果為:
再來一段代碼,看輸出結(jié)果:
1 <body> 2 <script type="text/javascript"> 3 function test(){ 4 console.log(b); 5 if(a){ 6 var b = 100; 7 } 8 c = 234; 9 console.log(c); 10 } 11 var a ; 12 test(); 13 a = 10; 14 console.log(c); 15 </script> 16 </body> View Code需要注意:函數(shù)在預(yù)編譯的時(shí)候根本不會(huì)看if語(yǔ)句,不管它,直接將if語(yǔ)句內(nèi)部的var b變量聲明提升就OK了,之所以不看【不管】是因?yàn)檫€沒有到函數(shù)執(zhí)行呢,這里僅僅是預(yù)編譯,所以根本不用判斷是不是a為true!最終結(jié)果如下所示:
?
再來做兩個(gè)測(cè)試:
1 <body> 2 <script type="text/javascript"> 3 function bar(){ 4 return foo; 5 function foo(){} 6 var foo =11; 7 } 8 console.log(bar()) 9 </script> 10 </body> View Code這個(gè)輸出的就是函數(shù)foo,如下所示:
1 <body> 2 <script type="text/javascript"> 3 console.log(bar()); 4 function bar(){ 5 foo = 10; 6 function foo(){} 7 var foo = 11; 8 return foo; 9 } 10 </script> 11 </body> View Code輸出的結(jié)果是:11,如下所示:
所以講到這里如果我們?cè)僬f:
1.函數(shù)聲明,整體提升
? ? ? ? 2.變量 聲明提升
大家就懂啥意思了!
注意:如下所示,區(qū)分開來哦:
1 <body> 2 <script type="text/javascript"> 3 console.log(b); 4 var b = function(){} 5 </script> 6 </body> View Code輸出的b是undefined,這個(gè)屬于變量,聲明提升,而
1 <body> 2 <script type="text/javascript"> 3 console.log(b); 4 function b(){} 5 </script> 6 </body> View Code輸出的b是函數(shù)b(){},這個(gè)屬于函數(shù)聲明,整體提升,所以var a = function(){};這叫函數(shù)表達(dá)式,不叫函數(shù)聲明,這是兩個(gè)概念,要區(qū)分開來!
?
再來做一個(gè)復(fù)雜點(diǎn)的:
1 <body> 2 <script type="text/javascript"> 3 a = 100; 4 function demo(e){ 5 function e(){} 6 arguments[0] = 2; 7 console.log(e); 8 if(a){ 9 var b = 123; 10 function c(){ 11 //豬都能做出來 12 } 13 } 14 var c ; 15 a = 10; 16 var a; 17 console.log(b); 18 f = 123; 19 console.log(c); 20 console.log(a); 21 } 22 var a; 23 demo(1); 24 console.log(a); 25 console.log(f); 26 </script> 27 </body> View Code需要注意:arguments,是指的實(shí)參,而arguments[0]是與demo函數(shù)的第一個(gè)參數(shù)e同步的,當(dāng)arguments[0]的值發(fā)生變化之后,實(shí)際上也就是demo的第一個(gè)參數(shù)e的值發(fā)生了變化,所以最后GO對(duì)象和AO對(duì)象的最終結(jié)果如下所示:
還有一點(diǎn)注意:新版本的谷歌瀏覽器中if語(yǔ)句內(nèi)部不能再嵌套函數(shù)了,在老版本的瀏覽器中是可以的,所以這里輸出c的時(shí)候按正說應(yīng)該是輸出function()函數(shù)對(duì)象的,正是由于if語(yǔ)句內(nèi)部不能嵌套函數(shù),所以這里輸出的是undefined值!所以最終AO和GO對(duì)象為:
GO{
a:100;
demo:function(){},
f:123
}
AO{
e:2,
b:undefined,
c:undefined【按正常推理應(yīng)該是function(){}】
a:10
}
最終的結(jié)果為:
?
轉(zhuǎn)載于:https://www.cnblogs.com/python-machine/p/8058732.html
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的JS数据类型及函数的预编译的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: D3引擎用正则运算的方式,实现智能设备A
- 下一篇: gradle idea java ssm