首頁  >  文章  >  web前端  >  JavaScript高階程式設計(第3版)學習筆記6 初識js物件_基礎知識

JavaScript高階程式設計(第3版)學習筆記6 初識js物件_基礎知識

WBOY
WBOY原創
2016-05-16 17:49:121083瀏覽

在房子裡面可以放你想放的任意事物——如果你有足夠的美學造詣,你甚至可以弄一個房中房試試——當然,為了方便管理,我們會給房子裡存放的所有事物都會取上一個不重複的名字,例如醫藥房間裡的各種藥品名稱。在ECMAScript中,你可以在物件中存放任意你想放的數據,同樣,我們需要為存放的資料取一個名字──也就是物件的屬性名,再存放各種資料。再看看ECMA-262中物件的定義:無序屬性的集合,其屬性可以包含簡單資料類型值、物件或函數。

  進入對象,我開始有些激動了,說實話,讓我想起做這系列學習筆記的最初原因,就是因為該書對對象的深刻論述,讓我對JavaScript的認知從客戶端驗證小工具轉變成一門強大的物件導向腳本語言,但我現在也有點犯錯了,因為關於對象,有太多太多的東西需要去細化,一時也不知該從哪個點切入,比如要想深入理解對象,作用域、執行環境、閉包這些概念是肯定離不開的,但如果連對象的概念都沒說就開始執行環境和閉包,又感覺像是空中樓閣。不過又一想,也就釋然了,這畢竟只是自己的個人學習筆記,又不是什麼教科書,我大可以用自己喜歡的方式來做自己的筆記(事實上,在前面的篇章中,我就有意識的重複那些我認為有意思的地方,這就是我喜歡的一種方式),當然,我還是會盡量以一種易於理解的方式來做這些筆記。

物件類型

  和5種簡單資料類型(Undefined、Null、Boolean、Number、String)相對應,物件(Object)也是一種資料類型,只是這種數據類型比較特別,它不但可以像簡單數據類型一樣訪問通常的數據,而且可以將動作行為作為一種特殊的數據加以訪問。

1、物件實例

  每個資料型態都有對應的值,例如Undefined型別只有一個值undefined,而數字5是Number型別的一個值。對於物件類型,我們把值稱為物件實例,那麼物件類型都可以有哪些(值)實例呢?任一物件都是物件類型的值(實例),例如簡單型別包裝物件(Boolean、Number、String)就是物件類型的值(實例)。

2、物件字面量

  既然任一個物件都是物件類型的實例,那麼物件實例怎麼表示呢?或者說我們在交流過程中怎麼書寫出物件實例呢?簡單資料型別的值很好表示,例如用符號「5」表示數字5,符號「true」表示Boolean值true,這些稱為字面量,那麼,有沒有物件字面量呢?答案是肯定的,而物件字面量就是用一對大括號({})來表示的。例如:

複製程式碼 程式碼如下:

{
name:


{
name:'linjisong'
getName:function(){
return this.name;
}
} 複製程式碼


程式碼如下:


[{
name:'linjisong ',
age:29
},{
name:'oulinhai', age:23 }]
這裡一對中括號([])用來表示數組,這是一個包含了兩個物件的陣列。透過物件字面量和陣列字面量,形成了難以想像的強大表現力,事實上,流行的JSON資料格式就是基於此。

3、建立物件實例

  熟悉一般物件導向的朋友都知道,要建立一個類別的實例,首先要定義這個類,然後用new關鍵字來創建這個類別的實例(別和我說還可以使用反射,我的Java可學的不好…)。但是在ECMAScript中,根本沒有類別的概念,那麼,物件實例要怎麼創建呢?

  在ECMAScript中儘管沒有類,但是也有某種程度上類似的概念,承擔這個角色的就是函數,可以透過new操作符和函數來建立物件實例-每一個物件實例都有一個用於建立這個實例的函數。最基本的函數就是Object(),它是用來建立最一般物件的函數,其它的諸如Number()函數,可以用來建立Number物件的實例,Boolean()函數,可以用來建立Boolean物件的實例:
複製代碼 代碼如下:

var obj = new Object();//Object ()函數,建立最一般的物件實例
var num = new Number(1);//Number()函數,建立Number物件的實例
var boo = new Boolean(true);//Boolean( )函數,建立Boolean物件的實例
console.info(typeof num);//object
console.info(typeof Number(1));//number
console.info(typeof boo); //object
console.info(typeof Boolean(true));//boolean

(1)可以看到,要建立一個物件實例,首先需要有一個函數(稱為建構函數),這個函數使用new呼叫時就是建立物件實例,不使用new時只是通常意義上的函數呼叫(如果這個函數在內部傳回實例了,函數呼叫也可以建立物件)。

(2)所謂的內建物件其實也就是內建了一些創建物件實例的函數而已,不同的函數創建不同的內建物件。

(3)關於要不要使用new操作符,我的建議是使用,如果不使用new操作符,有些情況下結果會出乎你的意料之外,像上例中的第5 、7行,實際上並沒有創建對象,而只是普通的函數調用,這個調用的作用就是轉換資料型別。

(4)使用new建立物件實例時,如果呼叫建構函式不需要傳入參數,也可以省略後面的函式呼叫操作符(()),當然,這種特性也不是什麼值得宣揚的事情。

(5)如果需要建立自訂物件的實例,那麼首先也需要定義一個建構函數,然後使用new運算元呼叫建立實例。這裡要注意,如果忘了new的話,可能會污染全域環境:
複製程式碼 程式碼如下:

function Person(){//先定義一個用來建立物件實例的(建構)函式
this.name = 'linjisong';
this.age = 29;
}

var person = new Person();//呼叫(建構)函式建立物件實例
console.info(person.age);//29

try{
console. info(age);//為了示範忘記使用new的情況,這裡先輸出全域的age,由於未定義,拋出例外
}catch(e){
console.info(e);// ReferenceError
}
var person2 = Person();//忘記使用new的情況下,只是普通的函數調用,由於函數沒有返回,這裡person2就是undefined了
console.info(person2); //undefined
console.info(age);//29,沒有使用new,內部的this指向了全域作用域,因為可以在全域存取age了

要避免這種問題,可以修改建構子:
複製程式碼 程式碼如下:

function Person() {
if(this instanceof Person)
{
this.name = 'linjisong';
this.age = 29;
}else{
return new Person();
}
}
var person2 = Person();
console.info(person2.age);//29,可以存取person2的age了
console.info(age);/ /全域環境中沒有age的定義了,拋出異常


這個建構子先判斷this值是否為Person型,如果不是,就在內部使用new調用,以確保傳回的值一定是Person型別實例。這種方式使得重構建構函式成為了可能,也許Boolean()、Number()、String()在實作上就是使用了這種方式來區分是建構函式還是轉換函式。如果你在呼叫Object()時省略new的話,結果也能回傳對象,估計也是在後台做了類似處理,同樣的情況還有本文後部分要講的函數型別建構子Function()。

(5)可能有人會問,既然有物件字面量,何必要用這麼複雜的方式來建立物件實例呢,直接寫物件字面量就不完了?用物件字面量創建物件實例,根本沒有使用什麼函數,看來,上面的「每個物件實例都有一個用於創建這個實例的函數」的說法並不正確。

  首先第一個問題,的確,可以使用物件字面量來建立函數,而且也非常簡潔,這甚至也是我首先推薦的一種創建方式,但是用這種方式創建物件實例,只能創建單例的實例,對於需要創建多個相同類型的對象實例來說並不適用,然後第二個問題,用對象字面量創建對象,實際上並不是沒有相應的構造函數,只是構造函數為Object(),使用物件字面量,後台可能不會去呼叫new Object(),但建立的物件仍然有指向這個函數的屬性,這可以從下面程式碼輸出中得到驗證:
複製程式碼 程式碼如下:

var person = {};
console.info(person.constructor=== Object);//true

這裡的constructor是每個實例物件都有的屬性,用來保存建立這個物件實例的函數,這就是下面要講的。

4、物件屬性與方法

  每一種資料型別都有各自的共通性,例如Number型別值都有可以和另一個Number型別值相加的特性,同樣,物件類型的實例也有一些相同的特性,這些特性就體現在它們都包含下面的屬性和方法(方法實際上也是一種屬性,只是屬性的值類型是函數的話,我們也稱之方法):

类别 属性/方法 说明
属性 constructor 指向用于创建当前对象的函数
方法 hasOwnProperty(propertyName) 检查给定的属性是否在当前对象实例中
propertyIsEnumerable(propertyName) 检查给定的属性是否能够是使用for-in语句来枚举
isPrototype(object) 检查传入的对象是否是另一个对象的原型
toLocalString() 返回对象的字符串表示,该字符串与执行环境的地区相对应
toString() 返回对象的字符串表示
valueOf() 返回对象的字符串、数值或布尔值表示,通常与toString()方法返回值相同

註:在《JavaScript高級程式設計(第3版)》第35頁中的Constructor將首字母大寫了,應該是一個印刷錯誤。

屬性和方法的存取有兩種方式:

(1)使用點號(.):如person.name。

(2)使用方括號([]):如person[name],使用這種方式,方括號內部可以是一個變數或表達式,這使得可以存取名稱包含特殊符號的屬性和方法。

  透過結合for-in和這裡的hasOwnProperty (propertyName),我們就可以遍歷物件實例本身的屬性而不包括從原型鏈繼承而來的屬性了:
複製程式碼 程式碼如下:

for(var propertyName in object){
  if(object.hasif(object.haspperorm)>
    //循環處理
  }
}
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn