JS對象屬性使用的問題

JS屬性操作的基礎知識

Js對象的屬性是可以動態擴展的譬如:定義了一個js對象,就可以設置它的屬性。代碼如下:
Object.prototype.test = “test1”;//定義一個Object的擴展屬性,以後所有的Object都有該屬性
Object.test1 = “abc”;//定義一個Ojbect的靜態屬性
var obj = {};//定義一個Object對象,也可以寫爲:var obj = new Object();
obj.prop1 = “prop1”;//設置obj的prop1屬性,若該屬性存在則爲其重新設置值,若不存在則添加該屬性.
obj.prop2 = “prop2”;//設置obj的prop2屬性.
obj[“prop3”] = “prop3”;//同上,設置prop3屬性.
var prop4 = “prop4”;
obj[prop4] = “testProp4”;//設置obj的prop4屬性,很多人問如何把一個變量設置爲一個對象的屬性.
alert(obj.prop1);//彈出”prop1”
alert(obj[“prop2”]);//彈出”prop2”
alert(obj[“test”]);//彈出”test1”
alert(obj.test1);//彈出undefined
alert(Object.test1);//彈出”abc”;
var obj1 = {};
alert(obj1.prop1);//彈出undefined
alert(obj1.test);//彈出”test1”

可能出現的問題

我們原定用對象的方式存entity.如下:
var obj = new Object()
obj[“name”] = “name1”;
obj[“sex”] = “男”;
這種方法存儲的是擴展屬性,因此必須用下面方法遍歷:
for(var key in arr){
key…//name,sex…
arr[key]…name1,男…
}

但是如果我們給Object加了擴展屬性.如
Object.prototype.remove = function(index){

}
那麼遍歷出來的值就多了一個
for(var key in arr){
key…//remove,name,sex…
arr[key]…remove的函數實體,name1,男…
}
這是無法避免的.

而如果我們給Object加上擴展屬性則,所有的對象都會有這個屬性.所有對象遍歷出來的結果與實際不符合.

這個問題可能會在以後暴露.如果我們以後引入了其它JS框架,它們很多都是擴展js的對象屬性.那麼將會發生莫名其妙的錯誤.
這裏給出一個流行的javascript的HashMap的實現

<script language="javascript">
   function HashMap()
  {
      /** Map 大小 **/
      var size = 0;
      /** 對象 **/
      var entry = new Object();

      /** 存 **/
      this.put = function (key , value)
      {
          if(!this.containsKey(key))
          {
              size ++ ;
         }
          entry[key] = value;
      }

      /** 取 **/
      this.get = function (key)
      {
          return this.containsKey(key) ? entry[key] : null;
      }

      /** 刪除 **/
      this.remove = function ( key )
      {
          if( this.containsKey(key) && ( delete entry[key] ) )
          {
              size --;
          }
      }

      /** 是否包含 Key **/
      this.containsKey = function ( key )
      {
          return (key in entry);
      }

      /** 是否包含 Value **/
      this.containsValue = function ( value )
      {
          for(var prop in entry)
          {
              if(entry[prop] == value)
              {
                  return true;
              }
          }
          return false;
      }

      /** 所有 Value **/
      this.values = function ()
      {
          var values = new Array();
          for(var prop in entry)
          {
              values.push(entry[prop]);
          }
          return values;
      }

      /** 所有 Key **/
      this.keys = function ()
      {
          var keys = new Array();
          for(var prop in entry)
          {
             keys.push(prop);
         }
          return keys;
      }

      /** Map Size **/
      this.size = function ()
      {
          return size;
      }

      /* 清空 */
      this.clear = function ()
      {
          size = 0;
          entry = new Object();
      }
  }

  var map = new HashMap();

  /*
  map.put("A","1");
 map.put("B","2");
 map.put("A","5");
 map.put("C","3");
 map.put("A","4");
 */

 /*
 alert(map.containsKey("XX"));
 alert(map.size());
 alert(map.get("A"));
 alert(map.get("XX"));
 map.remove("A");
 alert(map.size());
 alert(map.get("A"));
 */

 /** 同時也可以把對象作爲 Key **/
 /*
 var arrayKey = new Array("1","2","3","4");
 var arrayValue = new Array("A","B","C","D");
 map.put(arrayKey,arrayValue);
 var value = map.get(arrayKey);
 for(var i = 0 ; i < value.length ; i++)
 {
     //alert(value[i]);
 }
 */
 /** 把對象做爲Key時 ,自動調用了該對象的 toString() 方法 其實最終還是以String對象爲Key**/

 /** 如果是自定義對象 那自己得重寫 toString() 方法 否則 . 就是下面的結果 **/

 function MyObject(name)
 {
     this.name = name;
 }

 /**
 function MyObject(name)
 {
     this.name = name;

     this.toString = function ()
     {
         return this.name;
     }
 }
 **/
 var object1 = new MyObject("小張");
 var object2 = new MyObject("小名");

 map.put(object1,"小張");
 map.put(object2,"小名");
 alert(map.get(object1));
 alert(map.get(object2));
  map.remove("xxxxx");
 alert(map.size());

 /** 運行結果 小名 小名 size = 1 **/

 /** 如果改成複寫toString()方法的對象 , 效果就完全不一樣了 **/

 </script>

這種方法的原理就是用property,用Object的擴展屬性.來存儲內容
這會有一個問題.
如果我們使用了prototype.js它上面定義了一個Object的繼承方法:
Object.prototype.extend = function(obj){
……
}
那麼,下面代碼會出現問題.

     this.keys = function ()
     {
         var keys = new Array();
         for(var prop in entry)//遍歷所有entry的屬性     var entry = new Object();prop是Ojbect的擴展屬性.
         {
            keys.push(prop);
         }
        return keys;
     }

我們獲得的keys裏會包含”extend”這一項.這和我們要的不一致,這在一般的應用很難出問題,然而如果遇到這種情況,可能就找不到原因了。如果我們開發的時候寫了這樣的代碼:map.put(“extend”,”test”);或者map.remove(“extend”);就會覆蓋prototype 定義的Object.prototype.extend方法,那麼以prototype.js爲基礎的所有東西將都不能使用。
js的很多開源框架都對Object作了擴展.擴展的函數名是不可預知的.所以要避免這種情況.因爲如果出現錯誤,可能很難找出原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章