1. 程式人生 > >JAVASCRIPT面向物件(基礎知識)第一章

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