JAVASCRIPT面向物件(基礎知識)第一章
面向物件的程式設計
面向物件(Object-Oriented)是以類為概念,通過類可以建立各具無序屬性(包含了基本值、物件、函式)的物件。在ECMA-262把物件定義為“無序屬性的集合,其屬性可以包含基本值、物件和函式。”,我們也可以把ECMAScript的物件想象成散列表。
理解物件
在java中對面向物件的理解,是一切皆為物件,對於這種語言把面向物件已做到極致。那麼在JAVASCRIPT中跟它有一定的區別,比較傳統的生成物件的方式是通過new一個類,如下程式碼
var dog = new Object();
dog.name = "Small Yellow";//一般家裡的狗各種洋氣的名字,我家的狗是土狗,就叫小黃了(哈哈)
dog.age = 5;
dog.bark = function(){
console.log("my name is "+this.name);
}
注意:
1. 物件的建立形式,通過關鍵字new
2. 物件的屬性和函式賦值或者取值,以點的方式來操作
字面量建立物件,以函式式通過new建立的物件dog和字面量建立的dog是一樣的,這個因人或場景而異,程式碼如下
var dog = {
name: "Small Yellow" ,
age: 5,
bark: function(){
console.log("my name is "+this.name);
}
}
屬性型別
在物件內部才用的特性,描述了屬性的各個特徵,為了表示特性內部值,規範把其放在兩隊方括號中,如資料屬性[[Configurable]],[[Enumerable]],[[Writable]],[[Value]]和訪問器屬性[[Configurable]],[[Enumerable]],[[Get]],[[Set]]:下面一一簡單介紹一下
資料屬性
資料屬性包含了一個數據值的位置,在這個位置可以讀取和寫入值
- [[Configurable]]: 表示能否通過delete刪除屬性從而重新定義屬性,或者能否把屬性修改為訪問器屬性。像為dog物件定義的資料屬性,它的這個特性預設值為true
- [[Enumerable]]:表示能否通過for-in迴圈返回屬性。像為dog物件上定義的資料屬性,它的這個特性預設為true
- [[Wriable]]:表示能否修改屬性的值,像為dog物件上定義的資料屬性,它的這個特性預設為true
- [[Value]]:包含這個屬性的資料值,讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值儲存在這個位置上。而這個特性預設值為undefined
如下小例子介紹初始化物件後,資料屬性的描述,具體參考程式碼和註釋區域
var dog = {
name: "Small Yellow"//[[Configuration]]預設值為true,[[Enumerable]]預設值為true,[[Writable]]預設值為true,[[Value]]特性將被設定為"Small Yellow",而這個值的任何修改都會反應到這個位置
}
Object.defineProperty的使用
這個方法接收三個引數:屬性所在的物件、屬性的名字和一個屬性描述符。主要是對於屬性描述符進行講解,在javascript中描述符(descriptor)物件的屬性必須是:configurable,enumerable,writable,value。設定其中一個或多個值,可以修改對應的特性值。
對於上面的小例子,我們也可以向如下進行設定
var dog = {};//首先建立一個空物件
Object.defineProperty(dog, "name", {
writable:false,//[[writable]]設為false後,再賦值視為無效操作
value:"Small Yellow"
});
console.info(dog.name); // "Small Yellow"
dog.name = "Samll Dark";
console.info(dog.name); // "Small Yellow" 任然保持writable設定的初始值
注意:在嚴格模式下,如果屬性為只讀狀態,強行再次賦值時,會丟擲異常
繼續探究configurable特性
當configurable為false時,此時表示不能從物件刪除此屬性和把資料屬性改為訪問器屬性。
var dog = {};
Object.defineProperty(dog,"name",{
configurable:false,
value:"Small Yellow"
});
console.info(dog.name); //"Small Yellow"
delete dog.name;
console.info(dog.name); //"Small Yellow"
注意:在嚴格模式下,configurable為false時,如果強行刪除物件的該屬性時,那麼輝丟擲異常。而且,一旦把屬性的configurable為false後,那麼吃後悔藥也沒法了,它是不能夠再次恢復為true了,如果強行設定為true,不但沒有任何效果,而且會丟擲異常。具體程式碼如下
var dog = {};
Object.defineProperty(dog,"name",{
configurable:false,
value:"Small Yellow"
});
//丟擲異常,在chrome(其它瀏覽器只要支援es5規範,就ok,只是筆者習慣了chrome這種簡約的瀏覽器,同時也推薦大家使用chrome瀏覽器進行技術探究)控制檯可以直接觀察到
Object.defineProperty(dog,"name",{
configurable:false,
value:"Small Yellow"
});
使用defineProperty方法時需注意幾點
- 在呼叫defineProperty()方法時,如果不指定configurable、enumerable和writable,它們的預設值都為false。
- IE8是最先實現Object.defineProperty()方法的瀏覽器版本,但是其現實的不徹底,只能在DOM物件上使用這個方法,而且只能建立訪問器屬性,所以不推薦IE8來嘗試。
訪問器屬性
在java或者c++這種面向物件的語言,訪問器是其一大特色。但是JAVASCRIPT也會有相對應的訪問器,但是與像java語言相比,存在很多不同之處
訪問器屬性不包含資料值,它們包含一對setter(設定函式)和getter(負責返回有效的值)函式,但這兩個函式並不是必須存在的。訪問器也會存在如下的4個特性
那麼先上程式碼,緊接著會結合程式碼來講訪問器內部的4個特性
var codeVersion = {//程式碼管理
_year:2016,//程式碼入庫時間
during:1//程式碼已經管理多少年
}
Object.defineProperty(codeVersion,"year",{
get: function(){
return this._year;
},
set: function(newYear){
if(newYear >= 2016){
this._year = newYear;
this.during += newYear - 2016;
}
}
});
codeVersion.year = 2017;
console.info(codeVersion.during);
- [[Configurable]]: 表示能否通過delete刪除屬性從而重新定義屬性,或者能否把屬性修改為訪問器屬性。像為codeVersion物件定義的訪問器屬性,它的這個特性預設值為true
- [[Enumerable]]:表示能否通過for-in迴圈返回屬性。像為codeVersion物件定義的訪問器屬性,它的這個特性預設值為true
- [[Get]]:讀取屬性時呼叫的函式,預設值為undefined
- [[Set]]:寫入屬性時呼叫的函式,預設值為undefined
能定義一個屬性,那麼也能同時定義多個屬性,下面來講述一下defineProperties()方法的使用
此方法接受兩個物件型別的引數,第一個引數物件是要新增或刪除其屬性的物件,第二個引數是要修改的屬性組合的物件,具體格式如下面程式碼
var codeVersion = {};
Object.defineProperties(codeVersion,{
_year:{
configurable:true,
enumerable:true,
writable:true,
value:2016
},
during:{
writable:true,
value:1
},
year:{
get:function(){
return this._year;
},
set:function(newYear){
if(newYear >= 2016){
this._year = newYear;
this.during += newYear - 2016;
}
}
}
});
讀取屬性的特性
通過es5的Object.getOwnPropertyDescriptor()方法,可以獲得到屬性描述符物件,那麼如果獲取的是資料屬性,那麼返回的物件有configurable,enumerable,writable和value;如果獲取的士訪問器屬性,那麼返回的物件有configurable,enumerable,get和set
var codeVersion = {};
Object.defineProperties(codeVersion,{
_year:{
writable:true,
value:2016
},
during:{
writable:true,
value:1
},
year:{
get:function(){
return this._year;
},
set:function(newYear){
if(newYear >= 2016){
this._year = newYear;
this.during += newYear - 2016;
}
}
}
});
var descriptor = Object.getOwnPropertyDescriptor(book,"_year");
console.info("set type is "+typeof descriptor.set);//set type is undefined
console.info("get type is "+descriptor.get);//get type is undefined
console.info("value => "+descriptor.value);//value => 2016
console.info("configurable => "+descriptor.configurable);//configurable => false
console.info("writable => "+descriptor.writable);//writable => true
console.info("enumerable => "+descriptor.enumerable);//enumerable => false
var descriptor = Object.getOwnPropertyDescriptor(book,"year");
console.info("set type is "+typeof descriptor.set);//set type is function
console.info("get type is "+descriptor.get);//get type is function
console.info("value => "+descriptor.value);//vale => undefined
console.info("configurable =>"+descriptor.configurable);//configurable => false
console.info("writable => "+descriptor.writable);//writable => undefined
console.info("enumerable => "+descriptor.enumerable);//enumerable => false