這個筆記不知道何時記下的反正頗有意思,很基礎,很理論。javascript
JavaScript是一種輕量級的腳本語言,也是一種嵌入式(embedded)語言,是一種對象模型語言。html
腳本語言又被稱爲擴建的語言,或者動態語言,是一種編程語言,用來控制軟件應用程序,腳本一般以文本(如ASCII)保存,只在被調用時進行解釋或編譯,在依靠特定的宿主環境提供API來實現操做和效果。常見的宿主環境有瀏覽器,服務器環境(操做系統)。
嵌入式語言一句話就是不能獨立作事,插入到其餘語言才能用的語言。
理論上<script><script>標籤能夠放HTML代碼的任意位置,實際開發中對於函數的調用,代碼的執行一般放入body標籤下面;函數的定義,類的定義以及外部文件的引入一般放入head標籤中。前端
在head標籤中寫引入文件的代碼便可。java
變量是用來臨時存儲數據內容的容器,在使用過程當中能夠隨時改變存儲的值。編程
是否編程語言的前提是是否有變量,有變量纔算得上真正的編程語言。
變量命名規則:使用var關鍵字聲明變量;數字,字母,下劃線,$,且不能數字開頭;能夠用各類命名法。var不寫則是全局變量;數組
JavaScript中中文能夠做爲變量名是能夠的,由於JavaScript語言自己就是使用ut8編碼,通常不使用中文做爲變量名,由於佔的空間大,顯得low
數據類型:數字,字符串,布爾,對象,null,undefined瀏覽器
在JavaScript中數據類型粉三大類:簡單類型(數字,字符串,布爾),複合類型(數組,對象,函數),特殊類型(null,undefined),注意JavaScript中沒有數組類型這一說法,用typeof判斷就說其是object。
對比一下PHP的數據類型:1.整形2.字符串3.浮點型4.null5.布爾類型6.資源型7.數組類型8.對象服務器
用typeof來判斷數據類型,返回類型有:Number,String,boolean,undefined,function,object;框架
注意沒有null這一類型,
爲何null的類型是object?編程語言
這是因爲歷史緣由形成的。 1995年JavaScript語言的初版, 當時, 只設計了五種數據類型(對象、 整數、 浮點數、字符串和布爾值) , 徹底沒考慮null, 只把它看成object的一種特殊值, 爲了兼容之前的代碼, 後來就無法修改了。
這並非說null就屬於對象, 本質上就是一個特殊值, 表示「沒有」。
而在ES6草案時, 也曾將 null 的數據類型修改成了 null ,可是由於兼容性問題, 後來又改回了object。
null和undefined的區別?
null與undefined均可以表示「沒有」, 含義很是類似;寬鬆比較時,二者值相等,都表示空,無,沒有;
可是, JavaScript的值分紅原始類型和合成類型兩大類, Brendan Eich(JS做者)以爲表示」無」的值最好不是對象;其次, JavaScript的最第一版本沒有包括錯誤處理機制, 發生數據類型不匹配時, 每每是自動轉換類型或者默默地失敗。我以爲, 若是null自動轉爲0, 很不容易發現錯誤。因而又設計了一個undefined。
具體的說有如下區別:
var n=null; var d=undefined; var s=(n==d) alert(s); var f=(n===d); alert(f);
var d=document.getElementById('div'); alert(typeof(d));//object alert(d);//null
var n=Number(null); var d=Number(undefined); alert(n);//0 alert(d);//NaN
5.出現undefined的幾種狀況:
A.變量聲明但沒有賦值時
var i; alert(typeof(i));//undefined
B.函數須要傳參但並無傳值時
function f(x){ return x;//undefined } var p=f(); alert(p);
C.訪問不存在的屬性時,出現undefined
var o={}; alert(typeof(o.p));
D.函數沒有返回值時,函數的返回值是undefined
function h(){}; alert(h());//undefined
加,減,乘,除,取餘,自增,自減,舉個有趣點的案例:
var i=10; var j=++i; var h=i++; var k=++i; //沒有賦值操做前自增和後自增是沒有區別的。 console.log(j);//11 console.log(k);//13 console.log(h);//11 console.log(i);//13
複合運算:
//複合賦值運算符 +=,-=,*=,/= //三目運算符 條件?代碼1:代碼2; 條件?true:false;
//比較運算符 < > == === <= >= != !==
邏輯運算符 ! || && 三目運算符等
邏輯與解析圖:
邏輯或解析圖
if else 和 switch的區別?
if結構不只能夠判斷固定值, 還能夠判斷範圍區間。switch結構只能判斷固定值狀況。
3.循環結構:while,for,do while等
4.continue和break的區別;
continue:跳出當前循環,繼續下次循環。break:跳出整個循環結構,也就至關於結束循環。
數組是一組有序數據的集合,在內存中表現爲一段連續的內存地址。
數組的聲明也很簡單:
var arr=[1,2,3,4];var arr=new Array(1,2,3,4);
var arr=new Array(2); arr[0]=1;arr[1]=2;arr[2]=3;
多維數組:數組的元素也是一個數組,則父數組是多爲數組。
var arr=[1,2,[3,4,5,[6,7]]];是個三維數組
獲取數組元素:經過下標獲取(數組[下標]),多爲數組的話全部下標都寫上,否則只的到所在行的所有元素。
數組的遍歷:
最經常使用的經過for循環,根據循環語法,在循環以前先獲取數組長度
var arr=['Apple','Huawei','SumSung']; var len=arr.length; for(var i=0;i<len;i++){ console.log(arr[i]); }
for...in循環遍歷數組:for..in能夠遍歷對象,也能夠遍歷數組,畢竟數組也是個特殊的對象。
var arr=['Apple','Huawei','SumSung']; for(var i in arr){ //每次遍歷是,系統自動將元素的索引下標放入變量i中 console.log(arr[i]); }
length屬性:返回數組的成員數量即數組的長度。
數組對象的經常使用方法:
- push方法:用於在數組的末端添加一個或多個元素,並返回新元素的數組長度。注意push方法會改變原數組。
var a=[]; a.push(1); alert(a);//1 a.push('a'); console.log(a);//Array[1,'a'] a.push(true,{}); console.log(a);//Array [ 1, "a", true, {} ]
- pop方法:用於刪除數組的最好一個元素,並返回該元素。注意,pop方法會改變原數組
var a=['a','b','c']; var b=a.pop();//c console.log(a);//Array['a','b'] console.log(b);//c
- join方法:用於參數分隔符,將全部數組成員一個字符串返回,若是不提供參數,默認用逗號分隔。不改變原數組。
var a=[1,2,3,4]; var b=a.join('|'); console.log(b);//1|2|3|4 var c=a.join(); console.log(c);
- concat方法:用於多個數組的合併,它將新數組的成員添加到原數組的尾部,而後返回一個新的數組,原數組不變。
var a=['hello']; var b=['world']; var d=a.concat(b); console.log(d);//Array [ "hello", "world" ] console.log(d.concat(['!'],['A']));//Array [ "hello", "world", "!", "A" ]
- shift方法:用於刪除數組的第一元素,並返回給該元素。注意改變原數組。
var a=[1,2,3]; var b=a.shift(); console.log(a);//Array [ 2, 3 ] console.log(b);//1
- unshift方法:用於在數組的第一個位置添加一個元素,並返回新加元素後的數組長度。注意該方法會改變原數組。
var a=[1,2,3]; var b=a.unshift(5); console.log(a);//Array [ 5, 1, 2, 3 ] console.log(b);//4
- reverse方法:用於顛倒數組中的元素,返回改變後的數組。注意,該方法將改變原數組。
var a=[1,2,3]; var b=a.reverse(); console.log(a);//Array [ 3,2,1 ] console.log(b);//Array [ 3,2,1 ]
- slice方法:用於提取原數組中的一部分元素(至關於截取),返回一個新數組,原數組不變。它的第一個參數爲起始位置(從0開始) , 第二個參數爲終止位置(但該位置的元素自己不包括在內) 。若是省略第二個參數, 則一直返回到原數組的最後一個成員。
var a = ['a','b','c','d','e']; console.log(a.slice(0)) // ["a", "b", "c", "d", "e"] console.log(a.slice(1)) // ["b", "c", "d", "e"] console.log(a.slice(1,3)); // ["b", "c"]
- splice方法:用於刪除原數組中的一部分元素,並能夠在被刪除的位置添加新數組成員,返回值是被刪除的元素。注意,該方法會改變原數組。splice的第一個參數是刪除的起始位置, 第二個參數是被刪除的元素個數
var a = ['a', 'b', 'c', 'd', 'e', 'f']; var a1 = a.splice(4, 2); console.log(a1); //Array["e", "f"] console.log(a); // Array["a", "b", "c", "d"] var b = ['a', 'b', 'c', 'd', 'e', 'f']; var a2 = b.splice(1, 2, 1, 2); console.log(a2); //["b", "c"] // console.log(b);//["a", 1, 2, "d", "e", "f"]
- forEach方法:用於遍歷數組的全部成員,執行某種操做;forEach方法的參數是一個函數,數組的全部成員會依次執行該函數,它接受三個參數,分別是當前位置的值,當前位置的編號和整個數組
var a = ['a', 'b', 'c', 'd', 'e', 'f']; a.forEach(function(v,k,h){ console.log(v); console.log(k); console.log(h); }); //第三個參數能夠寫能夠不寫,它帶便遍歷次數
函數就是製做工具的工具,好比計算器就是一個工具,而製做計算器的工具就是函數,也就是製做工具的工具。一次定義屢次使用。
用函數的好處:節省代碼的數量,減小代碼量,使代碼能夠重複使用,節省空間,節省時間,使程序代碼具備結構化,模塊化,後期維護更友好等等不少好處
屢次聲明同一個函數的話,最後一次聲明的函數會覆蓋前面的函數,前面的聲明在任什麼時候候都是無效的。
遞歸函數:函數內部調用函數自身,稱之爲遞歸。只要是遞歸必須的有判斷,否則它是個死循環,用別的函數解決的問題最好別用遞歸解決,遞歸佔內存大,不友好。
function Recursion(x){ if(x>1){ return x+Recursion(x-1); }else{ return 1; } } console.log(Recursion(100);
函數的參數有形參和實參:
形參就是函數聲明時須要接受的參數,能夠理解成暫時的佔位符,並沒有實際意義實參就是調用函數是傳遞進函數的具體的實際數據,也就是給佔替代位符的的值
函數體內部的return語句:表示將數據返回給調用者。return後面即便有語句,也不會執行,也就是return後面不執行.return語句無關緊要,沒有則不反悔任何值或者說返回undefined。
函數中的arguments對象:arguement是函數調用時的實參列表;只是實參列表
function Argu(a){ console.log(arguments); } Argu(1,2,3);
aruguments對象帶有一個callee屬性,返回他所對應的原函數。callee表明當前運行的函數
function Argu(a){ console.log(arguments.callee); } Argu(1,2,3);
函數能夠沒有名字嗎?固然能夠:(function(){})();
爲何要有自調用匿名函數?
由於有名函數有缺點,可能運行時會出現命名衝突,若是在編寫程序時,直接採起自調用匿名函數,則不會產生命名衝突問題。市場上不少框架,如JQuery.js,ext.js等都是採用匿名函數進行封裝。
使用自調用匿名函數結合aruguments對象實現遞歸:
var a = (function (n) { if (n > 1) { return n + arguments.callee(n - 1); } else { return 1; } })(100); console.log(a);
做用域指的是變量存在的範圍。JavaScript中做用域有兩種局部做用域和全局做用域。
局部做用域:變量只在函數的內部存在。在函數內使用var聲明的變量是局部變量,是人爲的聲明。全局做用域:變量在整個程序中存在,全部地方均可以讀取。全局變量一個是函數外聲明的變量;還有一個是函數內不使用var的變量(僅僅帶便變量被賦值),也就是若是不是人爲定義,系統會定義,系統定義的變量在整個程序中存在,不加var會污染全局。
function a(){ b=1 } a(); console.log(b);
局部變量會替代全局變量:函數內部聲明的變量會在函數內部區域覆蓋同名的全局變量。
這說明javascript的函數在查找自身函數定義開始,從「內」向「外」查找。
var a=3; function fun(){ var a=2; console.log(a); } fun();//2 console.log(a);//3
若是函數內部不使用var關鍵字,那麼函數內部的賦值將會影響全局變量。實際上,JavaScript默認喲偶一個全局的對象窗口,全局做用域的變量其實是被綁定到窗口對象上的一個屬性,所以,直接訪問全局對象a和訪問window.a是徹底同樣的
var a=3; function fun(){ a=2; console.log(a); } fun();//2 console.log(a);//2
做用域解釋圖:
JavaScript的函數定義有個特色,他會先掃描整個函數體呃逆的語句,把全部聲明的變量提高到函數的頂部,注意只是把聲明提高了,並不會提高變量的賦值。
function fun(){ console.log(a);//undefined var a=2; //JavaScript解析引擎來講至關於 /** *var a; *var b=1+a; *alert(b); *a=2; **/ } fun();
函數自己也是一個值,也有本身的做用域;函數的做用域與變量同樣,就是它聲明時所做的做用域,與其運行時所在的做用域無關
函數執行時的做用域是定義時的做用域,而不是調用時的做用域。
var a=3; var x=function(){ console.log(a); } function f(){ var a=4; x(); } f();//3
再看這個:
var x=function(){ console.log(a); } function y(f){ var a=2; f(); } y(x);//ReferenceError: a is not defined //函數執行時的做用域是定義時的做用域,而不是調用是的,因此,這代碼運行結果是這樣。
繼續看代碼
function fun(){ var a=2; function bar(){ console.log(a); } return bar; } var a=4; var f=fun(); f();//2
JavaScript代碼運行,分爲編譯階段和執行階段:
編譯階段:聲明變量,聲明函數(display),語法檢查等操做,一旦出錯不會執行下一階段,除了錯誤提示不輸出別的內容執行階段:變量的賦值,函數的調用,代碼的執行等操做,這一階段出錯的話出錯以前的內容執行;
<script> console.log(1); console.log(s); console.log(3); //執行結果是:1 錯誤提示:找不到變量s //緣由代碼編譯階段沒有問題,執行階段因爲發生了錯誤,錯誤後面不會執行 </script> <script> console.log(3); console.log(4) console.log(4); //執行結果是:錯誤提示:有語法錯誤請檢查 //緣由:代碼編譯階段就出錯再也不執行執行階段 </script>
在html中<script></script>是一段獨立的代碼,這一段代碼出錯不會影響下一個<script></script>代碼段的執行;無論前面的代碼段錯誤出如今編譯階段仍是執行階段都不會影響下一段代碼的執行。
爲何呢?
雖然script代碼段在一個頁面,可是script代碼並非一塊兒執行,而是分開解析與執行。JavaScript解析引擎從上而下讀取第一個代碼段-->放入內存-->編譯階段-->執行階段-->下一個JavaScript代碼段-->放入內存...等操做;
總之一句話,JavaScript解析引擎執行完一段代碼再執行下一段代碼,每一段代碼都是獨立的存在。所以,前一個代碼不管發生什麼錯誤都不會影響下一個代碼段的執行
看圖: