對象屬於一個複合的數據類型,在對象中可以封裝多個不同類型的屬性,比如 Number、string,函數,Object、數組等等。
在JavaScript中,String、Number、Boolean、Null、Undefined屬於基本數據類型,Object屬於引用對象類型。
JavaScript的變量都是存儲在棧內存中,基本類型的值也是在棧內存中保存,值與值之間互相獨立,修改一個變量不會影響到另外一個變量。
JavaScript的對象是在堆內存中存儲的,每創建一個新對象,就會在堆內存中創建一個新空間,而變量是保存的是對象在堆內存中的內存地址(引用),如果兩個變量指向的是同一內存地址,那麼一個變量修改屬性會影響到另外一個變量。
兩個基本類型的比較,比較的是數值,而兩個對象的比較,比較的是地址,如果兩個對象一模一樣但是內存地址不同,也會返回false。
對象的分類:
- 內建對象:由ES標準中定義的對象,在任何的ES實現中都可以使用,比如Math、String、Number、Boolean、Function等等。
- 宿主對象:由JS的運行環境提供的對象,目前來講主要是瀏覽器提供的對象,比如BOM、DOM。
- 自定義對象:由開發人員自己定義的對象。
創建自定義對象:
使用構造函數Object創建:
//創建一個對象
var obj1 = new Object();
console.log(obj1);
console.log(typeof obj1);
//往對象中保存數據
obj1.name = "yehaocong";
obj1.age = 26;
console.log(obj1)
//獲取對象中的屬性值
console.log(obj1.name)
console.log(obj1.age)
使用字面量創建對象:
var obj1 = {"id":"12345","pid":"54321"};
console.log(obj1);
console.log(typeof obj1);
//往對象中保存數據
obj1.name = "yehaocong";
obj1.age = 26;
console.log(obj1)
//獲取對象中的屬性值
console.log(obj1.name)
console.log(obj1.age)
獲取和設置對象屬性的兩種方式:
var obj = new Object();
//第一種方式使用 obj.屬性名 = 屬性值;
obj.name = "liaoxiaoyan";
//第二鍾方式使用 obh[屬性名] = 屬性值;
obj["age"]= "22";
//獲取
console.log(obj.name);
console.log(obj["age"]);
兩種方式的區別:
使用中括號的方式比較靈活,如果使用變量或者特殊符號作為屬性名時,第一種方式會報錯。
函數也可以是對象的屬性,如果一個函數作為對象的屬性進行保存,那我們就稱這個函數是這個對象的方法,調用這個刪除就説調用這個對象的方法。
var obj = {
name:"liaoxiaoyan",
age:22,
//定義方法
printAtt:function(){
//this屬性後面會説明,這裏就是代表obj對象的引用。
console.log(this.name);
console.log(this.age);
}
};
//調用方法
obj.printAtt();
遍歷對象的屬性:
/**
語法
for (var 變量 in 對象){
變量的值是屬性名
}
*/
var obj = {id:123456,name:"yehaocong",age:26};
for(var attName in obj){
//這裏要用中括號取值,用小數點取不了變量的值
console.log(attName + "=" + obj[attName]);
}
構造函數
在JavaScript中,構造函數與普通函數沒有區別,構造函數就是一個普通的函數,唯一區別是調用方式的不同,也就是計算同一函數,一種調用方式是普通函數,另外一種是構造函數。
還有一個規範是構造函數通常使用大寫字母開頭,但不是強制。
//創建一個函數
var Person = function(){
this.name="yehaocong";
this.age=26;
};
//普通函數使用方式
var result1 = Person();
//構造函數使用方式
var result2 = new Person();
//使用Object構造函數構造一個對象
var result3 = new Object();
//返回undefined,因為以普通函數調用Person方法不返回值。
console.log(result1);
//返回一個Person對象,因為這個返回值是以構造函數方法調用Person方法的。
console.log(result2);
//返回一個Object對象
console.log(result3);
構造函數的執行流程:
- 立即創建一個新對象。
- 將函數中的this屬性賦值給新創建的對象。
- 依次逐行執行函數中的代碼。
- 返回this。
使用同一個構造函數創建的對象,我們稱為一類對象,也將一類構造函數稱為一個類。我們使用構造函數創建一個對象,這個對象稱為這個類的實例。
使用instantceof可以判斷一個實例是否屬於某個類。
原型對象
我們所創建的每一個函數,解析器都會像函數中創建一個屬性prototype,這個屬性對應着一個對象,這個對象就是所謂的原型對象,如果函數作為普通函數使用prototype沒有任何作用,當函數以構造函數的形式調用時,他所創建的對象都有一個隱含屬性,指向改構造函數的原型,我們對象可以通過__proto__來訪問他。如果使用函數來訪問的話,需要使用prototype來訪問。
原型按照java來講,跟父類有點相似,而原型對象就有點像java的父類對象。
所有同一個類的實例都可以訪問到這個原型對象,我們可以將對象中的共享內容,統一設置到原型對象中。
當我們訪問對象的一個屬性或者方法時,它會現在對象自身中尋找,找到就使用,找不到就會到對象的原型對象中尋找,找到就直接使用。
以後我們創建對象時,可以把這些對象共享的屬性或者方法,統一設置到對象的原型對象中,這樣就不用重複為每一個對象添加,也不會影響到全局作用域,就可以使每個對象都具有這些功能了。
原型對象也是對象,所以他也有原型,如果我們需要一個對象的屬性,會先在對象本身尋找,如果沒找到,會到對象的原型對象中尋找,如果還沒找到,再到對象的原型對象的原型對象中尋找,直到找到Object對象的原型對象為止,因為Object對象的原型對象沒有原型對象。如果沒找到就返回undefined。
所以可以理解為一般對象的原型就是Object,原型對象就是Object對象,所以一般對象只會找到原型對象的原型對象就會停止,這就有點繼承的味道。