1. 程式人生 > >第三章 屬性高階

第三章 屬性高階

一、屬性描述符

1.獲取對應屬性的描述符

屬性描述符:屬性的特徵;也叫元屬性;修飾屬性的屬性

Object.getOwnPropertyDescriptor(obj,"name"); 第一個引數:對應的物件 第二個引數:對應物件的屬性


  var obj={   name:"wql",   age:38,   wife:"lss"   }   var res=Object.getOwnPropertyDescriptor(obj,"wife");   console.log(res)
//res是一個物件
{
    1. configurable: true
    2. enumerable: true
    3. value: "lss"
    4. writable: true
    5. __proto__: Object
}

 

2.為物件新增或修改屬性

var obj={
    name:"snw"
};
Object.defineProperty(obj,"age",{
    value:
18, writable:true, configurable:true, emumerable:true }); console.log(obj); //Object {name: "snw", age: 18} console.log(obj.age);//18 屬性描述符的預設值都是false

 

3.writable(可寫的)

writable決定是否可以修改屬性的值
 
當writable為false時,對應的屬性的值是無法修改的。
 // writable為false 時 configurable一般也為false
在預設情況下: 繼續修改的話會靜默失敗 在嚴格模式下: 會報錯

var obj={
name:"Lebron",
age:33,
team:"湖人"
}
//obj.team="騎士"; 位置在這兒能被修改
Object.defineProperty(obj,"team",{
writable:false
})
obj.team="熱火";
console.log(obj);

 

4.configurable(可配置的)

configurable來決定屬性是否可以配置
可配置:屬效能否重新定義 屬效能否刪除 當configurable為false時,對應的屬性是無法重新定義的,無法刪除的。但該物件是還可以繼續新增屬性的。 預設情況下
進行重新定義會報錯
進行刪除會靜默失敗 注意一個小小的例外: 當configurable為false時,writable可以進行重新定義,但只滿足由writable:
true ==> writable:false

   var obj={        name:"zyy",        age:20,        hobby:"eat"      }      Object.defineProperty(obj,"hobby",{       //value:"play",         writable:true,         configurable:false,         enumerable:false     })
     delete obj.hobby;      console.log(obj);

 

5.enumerable

//enumerable可列舉:控制了屬性的可列舉許可權
//可列舉:能否出現在物件的for in 迴圈中



var obj={
    name:"zyy",
    age:26,
    behavior:"play basketball"
}
Object.defineProperty(obj,"behavior2",{
    value:"eat",
    enumerable:false
})

for(var item in obj){
  console.log(item);
}

6.嚴格模式

<!--
    嚴格模式的語法比較嚴謹
        沒有通過var定義的變數 在嚴格模式底下就會報錯
        this的指向
            普通呼叫時 如果是嚴格模式 那this指向undefined
   嚴格模式的管理範圍:作用域

   在屬性描述符writable為flase的情況下 對屬性值進行修改 就會報錯不會靜默失敗
   在屬性描述符configurable為flase的情況下 對屬性進行刪除 就會報錯不會靜默失敗

-->
<script>
    function test() {
        "use strict"
        inner();
        function inner() {
            console.log(this)
        }
    }
    
    (function () {
        "use strict"
        test()
    })()

 

7.屬性的指定方式

/*屬性的指定方式:
       1. 字面量初始化的時候直接通過 鍵值對的形式指定
                屬性描述符的預設值基本都是true
       2. 通過物件點的形式來指定
                屬性描述符的預設值基本都是true
       3. 原始的指定形式的方式
`               屬性描述符的預設值基本都是false
               value:undefined
        4. var a = "a"; 給window新增的屬性
                configurable: false
                enumerable: true
                writable: true
        5.    b="b";給window新增的屬性
            屬性描述符的預設值基本都是true
   */

    var a = "a";
    b="b";
    console.log(Object.getOwnPropertyDescriptor(window,"a"))
    console.log(Object.getOwnPropertyDescriptor(window,"b"))
    delete  a;
    delete  b;
    console.log(a);
    console.log(b);

 

8.存在性檢查

var obj={
        a:undefined,
        wife:{
            name:"xxx"
        }
    };
    console.log(obj.a);

    //in關鍵字 會影響物件的直接屬性 也訪問原型鏈  可是不訪問物件的深層屬性
    console.log("a" in obj)
    console.log("b" in obj)
    console.log("toString" in obj)
    console.log("name" in obj,"------")

    //在js中所有的方法都是 淺不變形 的;只會影響物件的直接屬性 不訪問原型鏈 也不訪問物件的深層屬性
    console.log(obj.hasOwnProperty("a"));
    console.log(obj.hasOwnProperty("b"));
    console.log(obj.hasOwnProperty("toString"));
    console.log(obj.hasOwnProperty("name"));

    var res = Object.getOwnPropertyNames(obj);
    console.log(res);

 

9.訪問描述符(get&&set)

    // 屬性描述符 : 屬性的特徵  屬性的屬性
    // 資料描述符 : 具有writable 和 value屬性描述符 的屬性!
    // 訪問描述符 : 具有set 和 get屬性描述符 的屬性!

    var obj={
        get age(){
        return obj.__age__;
         },
       set age(val){
            if (val > 150){
               val =150;
       }else if(val < 0){
               val =0;
         }

 
 

      obj.__age__=val;
       }
   }

 
 

obj.age=33;
console.log(obj.age);

 

二、物件不變性

1.物件常量屬性

將屬性的writable和configurable設定為false

      var MathCopy = {};
      Object.defineProperty(MathCopy,"PI",{
           value:3.141592654,
           writable:false,
           configurable:false,
           enumerable:true
      })
       MathCopy.PI=1;
      console.log(MathCopy.PI)



 

2.禁止物件擴充套件

由於屬性描述符是對屬性的管理
 
所以想禁止物件擴充套件不能使用屬性描述符來控制,而是需要呼叫Object.preventExtensions(obj);
 
引數:要求禁止擴充套件的物件
 
 
預設情況下
    為物件新增新的屬性會靜默失敗
嚴格模式底下
    報錯
 
 
注意:禁止物件擴充套件只是禁止了物件去擴充套件屬性,
而之前的屬性是可以進行重新定義或者刪除的,
屬性值也是可以修改的

3.密封物件

在禁止物件擴充套件(Object.preventExtensions(obj);的基礎上把現有屬性的configurable都調整為false
  
呼叫Object.seal(obj)密封一個物件
  
密封之後禁止了物件去擴充套件屬性,原有的屬性不可以進行重新定義或者刪除,但屬性值是可以修改的

 var obj = {
        a:"a",
        b:'b'
    };
    Object.seal(obj);

 
 

       delete obj.a;
       obj.c="c";
       obj.a="aa";
    console.log(obj);

輸出:{a: "aa", b: "b"}   沒有被刪除,也沒有新增c

 

4.凍結物件(淺)

 
 

    在密封物件(Object.seal(obj))的基礎上把現有屬性的writable都調整為false

    呼叫Object.freeze(obj)密封一個物件

   凍結之後禁止了物件去擴充套件屬性,原有的屬性不可以進行重新定義或者刪除,屬性值不可以進行修改




var
obj = { a:"a", b:'b' }; Object.freeze(obj); delete obj.a; obj.c="c"; obj.a="aa"; console.log(obj);

 

5.凍結物件(深)

<script>
    var obj = {
        name: "zyy",
        age: 20,
        hobby: {
            No1: "playball",
            No2: "eat",
            No3: "sleep"
        }
    }
   
    function deep(obj) {
        var keys = Object.getOwnPropertyNames(obj);
        keys.forEach(function (key) {
            var val = obj[key]
            if (Object.prototype.toString.call(val) === "[object Object]") {
                deep(val)
            }

        });
        return Object.freeze(obj)

    }
deep(obj);
obj.hobby.No1="watch";
console.log(obj)


</script>

三、屬性查詢和設定

1.基本規則

/* 資料描述符
        configurable: true
        enumerable: true
        writable: true
*/

    // 查詢: 先在物件的直接屬性中找 找到了就返回 找不到上原型鏈 整體原型鏈都沒有 返回 undefined
    // 設定: 隻影響物件的直接屬性

 

2.完整的規則(查詢)

 // [[Get]]:代表的屬性查詢的演算法
        // [[Get]]:
        //     1.在物件中查詢是否具有相同名稱的屬性,如果找到,就會返回這個屬性的值。
        //     2.如果沒有找到,則遍歷原型鏈
        //     3.無論如何都沒找到,返回undefined
        //     4.訪問描述符具體看get方法的邏輯

 

3.完整的規則(設定)

/*
    [[Put]]:代表的屬性設定的演算法

    obj.a="a";
    [[put]]:
        1.
            如果屬性直接存在於物件中 不在原型鏈上
            找到直接存在於物件中的屬性
            -資料描述符(沒有setter/getter)
                直接修改物件中的屬性(注意writbale的值)
            -訪問描述符
                直接呼叫set方法
        4.
            如果屬性直接存在於物件中  也在原型鏈上
            找到直接存在於物件中的屬性
            -資料描述符(沒有setter/getter)
                直接修改物件中的屬性(注意writbale的值)
            -訪問描述符
                直接呼叫set方法
        2.
            如果屬性不直接存在於物件中也不在原型鏈上
            在物件的直接屬性中新增一個屬性(資料描述符)
                value:"a"
                writable:true
                configurable:true
                enumerable:true

    3.
        如果屬性不直接存在於物件中  在原型鏈上
             ①.該屬性是資料描述符(沒有setter/getter)
                -writbale為true
                    直接在物件中新增一個屬性,我們稱之為遮蔽屬性
(√)(√)(√)(√)-writbale為false
                    報錯,不會生成遮蔽屬性

(√)(√)(√)(√) ②.該屬性是訪問描述符
                呼叫set,不會生成遮蔽屬性
    */

    // Object.prototype.a="a";
    Object.defineProperty(Object.prototype,"a",{
        set:function(val){

        }
    })
    var obj={};
    obj.a="aaaa";
    console.log(obj,Object.prototype)
</script>

 

object

靜態方法
    Object.create()
    Object.defineProperty()
    Object.getOwnPropertyDescriptor()
    Object.getOwnPropertyNames()
    Object.preventExtensions()
    Object.seal()
    Object.freeze()
    Object.keys()
例項方法
    Object.prototype.toString()
    Object.prototype.valueOf()
    Object.prototype.propertyIsEnumerable()