javascript的物件問題及總結

剛好遇見你_尋發表於2018-05-28

一  js中的物件是什麼?

  • 是一個容器,封裝了屬性(property)和方法(method),由若干鍵值對(key-value)組成
  • 是對實物的抽象,實物間關係轉換成了物件間關係,模擬現實的情況,轉換為針對物件的程式設計。

– 例如將動物抽象成一類物件,此類物件有著動物中特有的屬性和動作,不同於植物,而動物中又分有豬,狗,雞不同型別的事物物件,這些型別事物對像既有著動物型別的屬性和動作,又有著自身獨特型別的屬性和動作,可以這樣一直細分下去,直到每一種動物的個例,也就是物件的例項了,它不僅具備上層事物共有的屬性和方法,也有著自己獨特個性,是一個獨特的個體。

1-1 js的物件如何建立?

— 物件可通過物件字面量({}),建構函式(如new Object(),或自定義),Object.create等方式建立。

1-1-1 物件字面量,與new Object()建立物件方式的異同?

相同點:建立的物件在使用上是一致的,var a = {}  // 是var a= new Object()的語法糖

不同點:初始化的過程有些區別,new Object()是通過建構函式例項化物件,{ }是直接建立JSON物件,且在初始化時可以直接賦值,相比{ }比較高效

1-1-2 訪問及修改物件的屬性

— 物件是由鍵值對組成,物件的鍵名又稱屬性(property),都是字串型別,鍵名符合標識名條件或是數字可省略” “,系統會預設自動轉為對應的字串,鍵值可以是任意型別,若鍵值是函式,則該屬性又可被稱為方法,像函式般呼叫。

  • 使用 . 或 [ ]  訪問或修改增添物件的屬性
  • delete刪除屬性
  • in檢查是否屬於自身的屬性
  • Object.keys(obj)檢視所有自身可列舉屬性,Object.getOwnPropertyNames(obj)包括自身不可列舉的屬性如陣列中的”length”,都返回屬性名陣列
  • for…in 迴圈遍歷物件本身屬性
  • Object.observe(obj,function(changes))觀察物件屬性變化

1-1-2eg1:物件字面量式建立

  <script>
    //物件字面量式建立
    var obj = {
      name: `fermin`,
      run: function () {
        alert(`run`);
      } 
    };
    obj.age = 18;          //新增屬性
    console.log(obj.age);  //18
    delete obj.age;   
    //刪除屬性,注意:不能刪除繼承的屬性,會返回false,刪除不存在的屬性不會報錯,且返回true
    alert(obj.age);  // undefined,訪問不存在的屬性返回undefined
    alert("age" in obj);
    //false,  注意:in對物件擁有的屬性都返回ture,無論是否是繼承的,無法識別繼承屬性
    console.log(Object.keys(obj)); //["name","run"] //Object.keys()返回所有本身屬性名
    for (let i in obj) {
      console.log(i); 
     //name run //for..in 遍歷可enumerable的自身和繼承的屬性,可加obj.hasOwnProperty(i),過濾為自身屬性
    }
    obj.run();      //run //用點號訪問屬性和方法
    obj[`run`]();   //run //用[]訪問屬性和方法
    alert("toString" in obj); //true 
</script>

建構函式:建構函式建立物件是借用Object.create(原型) 來實現。

1-1-2eg2:new Object() 建立  (訪問和修改物件屬性與上述相同)

<script>
    //new Object()建立
    var obj = new Object(); //new可以省略
    obj.name = `fermin`;
    obj.age = 18;           //新增屬性
    obj.run = function () {
        alert(`run`);
    };                    //新增屬性
    delete obj.age;   //刪除屬性  //delete只能刪除物件的屬性如:var a=1; delete a  //false
    alert(obj.age);  // undefined,訪問不存在的屬性返回undefined
    alert("age" in obj);//false
    console.log(Object.keys(obj)); //["name","run"] 
    for (let i in obj) {
      console.log(i);  //name run 
    }
    obj.run();      //用點號訪問屬性和方法
    obj[`run`]();   //用[]訪問屬性和方法 
    alert("toString" in obj);  //true
</script>

1-1-2eg3:自定義建構函式

<script>
    //自定義建構函式
    function Person(name) {
      this.name = name; 
    }
    var obj = new Person("fermin");
    obj.age = 18;
    obj.run = function () {
      alert("run");
    }; //新增屬性
    alert(Object.keys(obj)); //name,age,run
    for (let i in obj) {
      console.log(i); //name age run
    }
    obj.run(); // run
    obj[`run`](); // run
    alert("toString" in obj); //true
</script>

1-1-2eg4:Object.create(原型)   //  Object.create(Object.prototype) <==> new Object()

<script>
    //Object.create(原型);
    var obj = Object.create(null); 
    //原型為null,不能繼承Object.prototype中的屬性
    obj.name = `fermin`;
    obj.age = 18;           //新增屬性
    obj.run = function () {
        alert(`run`);
    };                    //新增屬性
    delete obj.age;   //刪除屬性
    alert(obj.age);  // undefined,訪問不存在的屬性返回undefined
    alert("age" in obj);//false
    console.log(Object.keys(obj)); //["name","run"] 
    for (let i in obj) {
      console.log(i);  //name run 
    }
    obj.run();      //用點號訪問屬性和方法
    obj[`run`]();   //用[]訪問屬性和方法 
    alert("toString" in obj);  //false //沒有繼承Object.prototype中的屬性
</script>

1-1-3 new一個物件的過程

var obj = new Function();

  • 建立一個空物件     // var obj = {};
  • 將例項的__proto__屬性指向建構函式的prototype原型 //  obj__proto__ = Function.prototype
  • 將建構函式的指標指向例項  // Function.call(obj)

1-1-3eg1:模擬new過程

<script>
function Person(name) { this.name = name; } var obj = Person("fermin"); //不用new obj = {}; obj.__proto__ = Person.prototype; Person.call(obj); obj.age = 18; obj.run = function () { alert("run"); }; //新增屬性 alert(Object.keys(obj)); //name,age,run for (let i in obj) { console.log(i); //name age run } obj.run(); // run obj[`run`](); // run alert("toString" in obj); //true </script>

1-1-4 函式中this的指向問題  (避免在函式中包含多層this,往往第一層代表呼叫的物件,第二層就表示window了)

— this的指向在函式執行時才能確定,總是指向呼叫該函式的物件

  • 由new呼叫,指向新建的物件                                 //在建構函式執行
  • 由call,apply,bind呼叫,指向繫結的物件            //在強制繫結物件執行
  • 由上下文呼叫,指向所屬的上下文物件                  //在物件屬性執行
  • 沒有所屬物件時,嚴格模式指向undefined或指向全域性物件(window或global)  //在普通函式執行

1-1-4-eg1:

<script>
    var obj1= {
      a:3,
      b:{
        a:10,
        fn:function(){
          console.log(this.a); //undefined
          console.log(this); //window
        }
      }
    };
    var j = obj1.b.fn;
    j();
    //將fn賦值給變數j時,obj呼叫fn沒有執行,所以它最終指向的是window,而不是obj
    
    var obj2 = {
      a : `A`,
      fn: function () {
         console.log(this.a);
      }
    };
    obj2.fn();       //"A"          // this ===obj2
    obj2.fn.call({a: `AA`}); //"AA" // this === {name: `AA`}
    var fn1 = obj2.fn;
    fn1();           //undefined   //this === window
</script>

二  object物件的方法

2-1  六個例項物件方法,繼承Object.prototype

  • valueOf():返回當前物件對應的值,預設返回物件本身  // var o1 = new Object (); o1.valueOf === o1   //true
  • toString():將物件轉換為字串形式並返回  // var o2 = {a : 1}; o2.toString()  // [object Object]    //用Object.prototype.toString.call()  更準確的判斷型別[object,物件型別11種/ Number/ String/ Boolean/ Object/ Array/ Function/ Null/ Undefined/ RegExp/ NaN/ Infinite]
  • toLocalString():將對像轉換為本地對應的字串並返回
  • hasOwnPropoty():判斷某個屬性是否是自身的非繼承屬性,是的返回true
  • isPrototypeOf(): 判斷當前物件是為另一物件原型,是返回true
  • propertylsEnumerable():判斷某個屬性是否可列舉

2-2  物件屬性的特徵 attributes 物件用Object.getOwnPropertyDescriptor(obj,字串屬性名)讀取。

  • value:表示該屬性的值,預設undefined
  • writable:表示該屬性的值是否可改,預設true
  • enumerable:表示該屬性名是否可列舉,預設true   //改為false時,for..in 及Object.keys()JSON.stringify()不遍歷該屬性,可成私密屬性
  • configurable:表述該對像是否可配置,預設true     //var 宣告的變數會為false,沒宣告為false,如a=1或this.a=1   //改為false時,writable可從true改為false,當writable為true可改value值,其他值不可修改,不能再用delete刪除該屬性
  • get:表屬性取值函式(getter)預設undefined   //定義後,writable不能為true且定義value的值 // get,set為存取器的命令,常使用於某屬性值需依賴物件內部資料場合。 //  利用存取器可以實現資料物件與DOM物件的雙向繫結
  • set:表屬性存值函式(setter)預設underfined  //定義後,writable不能為true且定義value的值

2-3 定義物件屬性的attributes物件,下面兩種方法定義後,屬性中的writable,enumerable,configurable的值預設值又都會變為false

  • Object.defineProperty(obj,字串屬性名,attributesObj)
  • Object.defineProperties(obj,{字串屬性名: attributesObj,字串屬性名: attributesObj,…})

2-3-eg1:定義單一attribules屬性

<script>
  var o = Object.defineProperty({}, "p", {
    value: 3,
    writable: false,
    enumerable: true,
    configurable: false
  });
  alert(o.p);  //3
  o.p = 33;
  alert(o.p);  //3  //writable為false,修改不了該屬性的值 
</script>

2-3-eg2:定義多個attributes屬性

<script>
  var o = Object.defineProperties({}, {
    p1: {
      value: 3,
      enumerable: true,
      writable: true, //configurable值沒設定,預設為false
    },
    p2: {
      get: function () {
        return this.p1 + 6;
      },         //有get,就不能直接定義其value值
      enumerable: true,
      configurable: true
    }
  });
  alert(o.p1);  //3
  o.p1 = 4;     //writable,值為true後,可直接用.或[]修改該屬性值,
  alert(o.p1);  //4
  alert(o.p2);  //10 
  Object.defineProperty(o, "p1",{value:33});
  //若再修改p1其它屬性值會報錯,因為一開始configurable為false
  alert(o.p1);  //33 
  //PS:當writable值為false,configurable值為true,只能在defineProperty()中修改
</script>

 2-4  物件的拷貝

–將一物件所有屬性拷貝到另一個物件上,有重複的屬性,將被覆蓋

<script>
    var extend = function (to, from) {
      for (var property in from) {
        var descriptor = Object.getOwnPropertyDescriptor(from, property);
        if (descriptor && (!descriptor.writable 
          || !descriptor.enumerable
          || !descriptor.configurable
          || !descriptor.get
          || !desciptor.set)) {
          Object.defineProperty(to, property, descriptor); //都拷貝
        } else {
          to[property] = from[property];  
          //這個else遇存取器定義屬性只拷貝值,適用於descriptor的5個特徵都具備
        } 
      }
      return to; 
    };
    var aa = extend({a:1, b:2}, {a:11, bb:22});
    console.log(aa); //{a:11, b:2, bb:22}  
</script>

2-5  控制物件的狀態

  • Object.preventExtensions(obj)   //無法再新增新屬性,嚴格模式下新增會拋錯,可用delete刪除現有屬性
  • Object.isExtensible(obj)   //沒使用Object.preventExtensions(obj)返回false,使用了返回true
  • Object.seal(obj)  //無法新增新屬性,也無法刪除舊屬性,現有屬性的configurable會變為false
  • Object.isSeal(obj) //沒使用Object.seal(obj)返回false,使用了返回true,且isExtensible返回false
  • Object.isFrozen(obj)  //是否被凍結,指不可擴充套件,所有屬性不可配置,所有資料屬性(即沒有getter或setter元件的訪問器的屬性)都是不可寫的。

2-5-eg:

<script>
    var o = new Object();
    Object.preventExtensions(o);
    o.p = 1;
    console.log(o.p); // undefined
    console.log(Object.isExtensible(o)); //false
</script>

 

 

相關文章