JS進階
一、JS的資料類型
1.基本類型
JS共有5大基本類型,分別是:
1)Undefined。他只有一個值:undefined。如果一個變數被定義但是沒有給他賦值,那麼這個時候系統會預設給這個變數賦值為undefined。
2)Null。它同樣也只有一個值:null。他是一個參考型別,當一個準備儲存對象的變數因為種種原因還沒有指向一個對象的時候,可以給這個變數賦值為null,通常也是這麼做的。
3)Number。數實值型別,他是C#中的整型和浮點型的集合,它具體是什麼類型還要看它被賦值的情況,一般來說賦值為什麼類型他就為什麼類型。另外注意 var num = 1.0;這個時候num是個整型,只有小數點後有確切的不為0的值的時候才是浮點型。關於Number類型還有一些其他知識點,如:NaN表示該值不是一個數字,isNaN()可以判斷傳入的值時候為Number類型;parseInt()可以將傳入的參數轉成數實值型別,如果包含非數實值型別字串的話,會自動將字串去掉,parseInt("123blue")的傳回值為123,字串blue部分被忽略,因此parseInt()方法可以理解為嘗試把傳入的參數轉換成整型,轉換不了的話會將轉換不了的部分忽略。parseFloat()方法與parseInt()方法類似。
4)Boolean。布爾類型,類似C#中bool類型,有true和false兩個取值,但是沒有類似C#中0對應False,1對應true這樣的與數位對應關係。
5)String。字串類型,儲存的是0到16位的UNICODE程式碼群組成的字元序列。
2.複雜類型
1)Object類型。是JS的頂級“父類”(因為JS中沒有類的概念,說他是父類只是為了理解上的方便),是一組資料和方法(功能)的集合,但它不具備傳統物件導向語言所支援的類和介面。Object類型本質是一個無序的索引值對列表,類似於集合,json格式。它包含7個方法,分別是:
constructor() 建構函式?
hasOwnProperty(propertyName) 檢查屬性是否在當前對象中
isPrototypeOf(object) 檢查對象是不是該對象原型
propertyIsEnumerable(propertyName) 檢查屬性是否能用for-in來迴圈
toString()
valueOf()
建立Object可以有多種方式:
通過new 關鍵字:var s = new Object(); s.name="james"; s.age=27;
通過JS的簡單定義方式:var s = {}; s.name="james"; s.age=27;
對象字面量標記法:var s = {"name":"james","age":"27"};PS:json格式資料的key可以不用雙引號括起來,value如果不是字串的話也可以不用雙引號括起來,但是推薦key和value都要用雙引號括起來,以避免不必要的麻煩。
訪問Object對象的屬性的方法:
s.name 直接點出來。
s["name"];使用方括弧(類似於索引器)的優點是可以通過變數來動態訪問屬性:var proName="name"; alert(s[proName]);
2)Array類型。是資料的有序列表
與其他數組的不同:
數組元素可以是任何類型,同一個數組的元素類型也可以不一樣,相當於C#中的List<object>
長度可以任意改變
數組的length屬性可讀寫(可以利用這一點刪除數組元素)
數組的棧方法 後進先出
push() 往裡加
pop() 從棧頭往外拿,拿出來以後數組中的元素數量就會發生變化
數組的隊列方法 先進先出
shift() 從隊列尾部往外拿
unshift() 從隊列尾部往裡加
排序
sort() 排正序,將數組中的資料按照一定的順序排列,參數可以傳遞一個匿名方法(類似於介面)
reverse() 翻轉排列
串連數組
concat() 樣本:var colors=["a","b"];var newcolor=colors.concat("yellow",["c","d"]);結果colors有了5個元素。concate方法中若傳入數組,會把該數組拆分,將其中元素加入目標數組中。若傳入json格式資料,一個json資料就看成一個元素加入數組。
3)Function類型。函數是對象,函數名是指標
聲明方式(3種):
function sum(x,y){return x+y;}
var sum=function(x,y){return x+y;}//函數運算式
var sum=new Function("x","y","return x+y;");//對象建立,不推薦(解析兩次)
Function類型沒有重載。Function類型本質上就是一個資料類型,和其他類型一樣,多次賦值的時候,後一次賦值會覆蓋(替代)前一次賦值。多個同名函數其實就是對同一個函數對象賦值,後一個賦值會覆蓋前面的賦值,所以執行的都是最後一次的函數定義。
講Function的屬性之前需要先瞭解JS代碼的執行環境和範圍以及其他一些知識點:
a)執行環境:就是當前函數(方法)所處在的父環境。比如在window下執行的函數他的執行環境就是window。真正的全域執行環境是Global,只不過大多數瀏覽器不公開代碼訪問,只是通過window來間接訪問。
b)if等語句沒有用塊狀範圍,JS的範圍與C#的不同,if,for等用大括弧括起來的代碼並不能形成一個塊狀範圍。
c)用var聲明變數時,會他把添加到最近的可用環境,若不用var則把他添加的父環境中,這就理解了不用var定義的一個變數是全域變數的原因。
d)聲明語句會首先執行,不管你把它放到哪裡。雖然JS代碼是從上到下順序執行的,但是遇到聲明的語句,編譯器就會先執行聲明語句,以保證其他語句執行的過程中不會因為遇到沒有聲明的變數而報錯。
e)記憶體回收。將一個儲存對象的變數設定為null,相當於切斷了變數(棧)和引用值(堆)之間的關係,記憶體回收站就會自動回收
Function的內部屬性:
arguments
他是一個數組,儲存傳入的參數。
callee是一個指標,儲存擁有這個arguments對象的函數對象,也就是這個函數的堆地址,當函數需要調用自己的時候,可以使用callee,不用出現自己的函數名,從而降低耦合度。
this
指向當前函數所在的執行環境,也就是函數在執行時所處的範圍
函數對象的屬性和方法
length
函數定義的具名引數的個數
函數名.length
prototype(原型)
儲存它們所有執行個體方法的真實所在
apply([要改變的範圍])
改變該函數對象的範圍 也就是改變this的值
範例程式碼
複製代碼 代碼如下:
function sum(x, y) {
alert(this);
return x + y;
}
//window.sum(1,2);
function callS() {
callS.callSum1(1, 2);
}
callS.callSum1 = function (x, y) {
alert(this);
var s = sum.apply(this, arguments);
//sum(1, 2);
return s;
}
callS();
call()方法與apply()方法類似
以上兩個方法不是繼承而來的,可以擴充函數賴以存在的範圍,這樣做最大的好處是對象和方法不需要有任何耦合關係。兩者傳入的第一個參數都是要改變成的範圍,第二個參數apply傳入的是一個參數數組,call傳入的是每一個具名引數。
二、實值型別和參考型別
講了這麼多基本類型(除null以外都是實值型別)和複雜類型(基本上都是參考型別),我們需要瞭解語言設計者為什麼要設計實值型別和參考型別。兩者的區別是什嗎?
1.實值型別內容長度固定,儲存值的存在範圍參考型別內容長度不固定,可以儲存不定長度的資料;
2.實值型別只能單純的儲存值,如整型,字串等。而參考型別可以儲存對象的堆地址,可以使多個變數指向同一個對象;
3.也是最主要的一點,參考型別可以緩解棧的儲存壓力(實值型別儲存在棧中)。
4.在JS文法中基礎資料型別 (Elementary Data Type)不能動態添加屬性而引用資料類型可以動態添加屬性。
三、檢測類型的關鍵字
1.typeof
判斷基本類型的類型 返回true or false
2.instanceof
判斷複雜(引用)類型的類型 返回true or false
如果用它判斷基本類型 則永遠返回false
四、eval()方法
eval()方法相當強大,他就相當於一個解析器。它只接受一個參數,就是要執行的JS代碼字串。當解析器發現eval()時,他會把eval()中的參數解析出來,插入到eval執行的位置,效果相當於在相應的位置直接寫入JS代碼。
五、建立對象
1)簡單原廠模式
2)建構函式模式。每一個執行個體都包括所有的方法,這樣會浪費記憶體。
3)原型模式。把方法儲存在原型中,這樣所有執行個體可以調用這個方法,而不用每個執行個體都要儲存這個方法