1.對象和屬性
對象是一種復核數據類型,它們將多個數據值幾種在一個單元中,而且允許使用名字來存取這些值,即對象是一個無序的屬性集合,這個屬性都有自己的名字和值,存儲在對象中的以命名的值可以是數字和字符串這樣的原始值,也可以是對象。
2.對象的創建
對象是由運算符new來創建的,在這個運算符之后必須有用于初始化對象的構造函數名。
創建一個空對象(即沒有屬性的對象)
var o = new Object();
js還支持內部構造函數,它們以另一種簡潔的方式初始化新創建的對象
var now = new Date();
var new_year = new Date(2009,09,19);
3.屬性的設置和查詢
4.屬性的枚舉
for/in循環列出的屬性并沒有特定順序,而且它只能枚舉出所有用戶定義的屬性,但是卻不能枚舉出那些預定義的屬性或方法,并且它可以
枚舉出被設為undefined的屬性,但是它不能列出被delete刪除的屬性。
5.未定義的屬性
如果要讀取一個不存在屬性的值,那么得到的結果是一個特殊的js值,undefined
可以使用delete來刪除一個對象的屬性,注意:刪除一個屬性并不僅僅是把該屬性設置為undefined,而是真正從對象中移除了該屬性。
6.構造函數
它由new運算符調用,傳遞給它的是一個新創建的空對象引用,將該引用作為關鍵字this的值,而且它還要對新創建的對象進行適當的初始化。
注意:構造函數如何使用它的參數來初始化this關鍵字所引用的對象的屬性,記住,構造函數只是初始化了特定的對象,但并不返回這個對象。
構造函數通常沒有返回值,他們只是初始化由this值傳遞進來的對象,并且什么也不返回..但是,構造函數可以返回一個對象值,如果這樣做,被返回的對象就成了new表達式的值了,在這種情況下,
this值所引用的對象就被丟棄了。
7.方法
方法有一個非常重要的屬性,即在方法主體內部,關鍵字this的值變成了調用該方法的對象。
方法和函數的區別,其實他們沒有什么技術上的差別,真正的區別存在于設計和目的上,方法是用來對this對象進行操作的,而函數通常是獨立的,并不需要使用this對象。
8.原型對象和繼承
js對象都“繼承”原型對象的屬性,每個對象都有原型對象,原型對象的所有屬性是以它為原型的對象的屬性,也就是說,每個對象都繼承原型對象的所有屬性,
一個對象的原型是有創建并初始化該對象的構造函數定義的,js中的所有函數都有prototype屬性,它引用一個對象,雖然原型對象初始化時是空的,但是你在其中定義的任何屬性都會被構造函數創建
的所有對象繼承。
構造函數定義了對象的類,并初始化了類中狀態變量的屬性,因為原型對象和構造函數關聯在一起,所以類的每個成員都從原型對象繼承了相同的屬性,這說明原型對象是存放方法和其他常量屬性的理
想場所。
繼承是在查詢一個屬性值時自動發生的,屬性并非從原型對象賦值到新的對象的,他們只不過看起來像是那些對象的屬性,有兩點重要的含義,一是:使用原型對象可以大量減少每個對象對內存的需求
量,因為對象可以繼承許多屬性;而且即使屬性在對象被創建之后才添加屬性到它的原型對象中,對象也能夠繼承這些屬性。
屬性的繼承只發生在讀屬性值時,而在寫屬性值時不會發生。
因為原型對象的屬性被一個類的所有對象共享,所以通常只用他們來定義類中所有對象的相同的屬性,這使得原型對象適合于方法定義,另外原型對象還適合于具有常量的屬性的定義,
a.原型和內部類
不只是用戶定義的類有原型對象,像內部類同樣具有原型對象,也可以給他們賦值,
e.g String.prototype.endsWith = function(o){
return (e == this,charAt(this.length-1));
}
9.面向對象的js
在面向對象的程序設計中,共有的概念是強類型和支持以類為基礎的繼承機制,根據這個評判標準,就可以證明js不是面向對象語言。
js對象可以具有大量的屬性,而且還可以動態的將這些屬性添加到對象中,這是對面對象c++和java做不到的,
雖然js沒有類的概念,但是它用構造函數和原型對象模擬了類。
js和以類為基礎的面向對象語言中,同一個類可以具有多個對象,對象是它所屬的那個類的實力,所以任何類都可以有多個實例,js中的命名延勇了java中的命名約定,即命名類時以大寫字母開頭,命名對象時以小寫字母開頭,類幫助我們區分代碼中的類和對象。
實例屬性
每個對象都有它自己單據的實力屬性的副本,為了模擬面向對象的程序設計語言,js中的實例屬性是那些在對象中用構造函數創建的或初始化的屬性。
實例方法
實例方法和實例數據非常的相似,實例方法是由特定對象或實例調用的,實例方法使用了關鍵字this來引用他們要操作的對象或實例,但是和實例屬性不同額一點是每個實例方法都是由類的所有實例共享的,在js中,給類定義一個實例方法,是通過把構造函數的原型對象中的一個屬性設置為函數值類實現的,這樣,由那個構造函數創建的所有對象都會共享一個以繼承的對函數的引用,而且使用上面素數的方法調用語法就能夠調用這個函數。
類屬性
類屬性是一個與類相關聯的變量,而不是和類的每個實例相關聯的變量,每個類屬性只有一個副本,它是通過類存取的,可以簡單的定義了構造函數自身的一個屬性來定義類屬性
類方法
類方法是一個與類關聯在一起的方法,而不是和類的實例關聯在一起的方法,要調用類方法,就必須使用類本身,而不是使用類的特定實例。由于類方法不能通過一個特定對象調用,所以使用關鍵字this對它來說沒有意義,和類屬性一樣,類方法是全局性的,
超類和子類
面向對象語言中有類層次的概念,每個類都有一個超類,他們從超類中繼承屬性和方法,類還可以被擴展,或者說子類化,這樣其他子類就能繼承它的行為,js中繼承是以原型為基礎的,而不是以類基礎的繼承機制,但是我們仍舊能夠總結出累世的類層次圖,在js中,類Object是最通用的類,其他所有類都是專用化了的版本,或者說的是Object的子類,另一種解釋方法是Object是所有內部類的超類,所有類都繼承了Object的基本方法。
舉例說明:
類Complex的對象就繼承了Complex.prototype對象的屬性,而后者又繼承了Object.prototype的屬性,由此可以推出,對象Complex繼承了兩個對象的屬性,在Complex對象中查詢某個屬性時,首先查詢的是這個對象本身,如果在這個對喜愛那個中沒有發現要查詢的屬性,就查詢Complex.prototype對象,最后,如果在那個對象中還沒有最后按到要查詢的屬性,就查詢Object.prototype對象,注意類層次關系中的屬性隱藏。參考P153
10.作為關聯數組的對象
運算符“.”類存取一個對象屬性,而數組更常用的存取書香運算賦是[],下面的兩行代碼是等價的:
obj.property ====== obj["property"],他們的語法區別是,前者的屬性名是標識符,后者的屬性名卻是一個字符串,
在c、c++、java和其他類似的強類型語言中,一個對象的屬性數是固定,而且必須預定義這些屬性的名字,由于js是一種弱類型語言,它并沒有采用這一規則,所以在用js編寫的程序,可以為對象創建任意數目的屬性,但是當你采用“.”運算符來存取一個對象的屬性時,屬性名時是用標識符表示的,而js程序性中,標識符必須被逐字的輸入,他們不是一種數據類型,因此程序不能對他們進行操作。
constructor屬性
每個對象都有constructor屬性,它引用的是用來初始化該對象的構造函數。但是并不是所有的對象都具有自己唯一的constructor屬性,相反,如果這個屬性是從原型對象繼承來的。
js會為我們定義的每一個構造函數都創建一個原型對象,并且將那個對象賦給構造函數的prototype屬性。但是之前沒有說明原型對象初始時是非空的,在原型對象創建之初,它包括一個constructor屬性, 用來引用構造函數,也就是說,如果有一個函數f,那么屬性f.prototype.constructor就總是等于f的。
由于構造函數定義了一個對象的類,所以屬性construtor在確定給定對象的類型時是一個功能強大的工具。
并不能保證constructor屬性總是存在的,例如,一個類的創建者可以用一個全新的對象來替換構造函數的原型對象,而新對象可能不具有有效的constructor屬性。
toString()方法
toLocaleString()方法
valueOf()方法
js需要將一個對象轉化成字符創之外的原型類型時,就調用它,這個函數返回的是能代表關鍵字this所引用的對象的值的數據。
hasOwnProperty()
如果兌現局部定義了一個非繼承的屬性,屬性名是由一個字符串實際參數指定的,那么該方法就返回true,否則,它將返回false。
propertyIsEnumerable()
如果對象定義了一個屬性,屬性名是由一個字符串實際參數指定的,而且該屬性可以用for/in循環枚舉出來,那么該方法返回true,否則返回false。
注意:該方法只考慮對象直接定義的屬性,而不考慮繼承的屬性,因為返回false可能是因為那個屬性是不可枚舉的,也可能是因為它雖然是可以枚舉的,但卻是個繼承的屬性。
怎么判斷一個屬性是可枚舉的?
isPrototypeOf()
如果調用對象是實際參數指定的對象的原型對象,該方法返回true,否則返回false,該方法的用途和對象的constructoe屬性相似。