Object.defineProperty()方法學習筆記


這是js中一個非常重要的方法,ES6中某些方法的實現依賴於它,VUE通過它實現雙向綁定

此方法會直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性, 並返回這個對象

參數

Object.defineProperty(object, attribute, descriptor)

這三個參數都是必輸項

第一個參數為目標對象

第二個參數為需要定義的屬性或者方法

第三個參數為目標屬性所擁有的特性

 

前兩個參數都很明確,重點是第三個參數 descriptor, 它有以下取值

descriptor

value: 屬性的值

writable: 屬性的值是否可被重寫(默認為false)

configurable: 總開關,是否可配置,若為false, 則其他都為false(默認為false)

enumerable: 屬性是否可被枚舉(默認為false)

get: 獲取該屬性的值時調用

set: 重寫該屬性的值時調用

 

一個例子 

var a= {}
Object.defineProperty(a,"b",{
   value:123
})
console.log(a.b)  //123
a.b = 456
console.log(a.b)  //123
a.c = 110
for (item in a) {
    console.log(item, a[item])    //c 110
}

因為 writable 和 enumerable 默認值為 false, 所以對 a.b 賦值無效,也無法遍歷它

configurable

總開關,是否可配置,設置為 false 后,就不能再設置了,否則報錯, 例子

var a= {}
Object.defineProperty(a,"b",{
  configurable:false
})
Object.defineProperty(a,"b",{
  configurable:true
})
//error: Uncaught TypeError: Cannot redefine property: b

writable

是否可重寫

var a = {}; 
Object.defineProperty(a, "b", { 
    value : 123,
    writable : false 
});
console.log(a.b);
// 打印 123 a.b = 25; // 沒有錯誤拋出(在嚴格模式下會拋出,即使之前已經有相同的值) console.log(a.b); // 打印 123, 賦值不起作用。

enumerable

屬性特性 enumerable 定義了對象的屬性是否可以在 for...in 循環和 Object.keys() 中被枚舉

var a= {}
Object.defineProperty(a,"b",{
  value:3445,
  enumerable:true
})
console.log(Object.keys(a));// 打印["b"]

enumerable改為false

var a= {}
Object.defineProperty(a,"b",{
  value:3445,
  enumerable:false //注意咯這里改了
})
console.log(Object.keys(a));// 打印[]

set 和 get

如果設置了 set 或 get, 就不能設置 writable 和 value 中的任何一個,否則報錯

var a = {}
Object.defineProperty(a, 'abc', {
    value: 123,
    get: function() {
        return value
    }
})
//Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object> at Function.defineProperty 

對目標對象的目標屬性 賦值和取值 時, 分別觸發 set 和 get 方法

var a = {}
var b = 1
Object.defineProperty(a,"b",{
  set:function(newValue){
      b = 99;
    console.log("你要賦值給我,我的新值是"+newValue);
  },
  get:function(){
    console.log("你取我的值");
    return 2 //注意這里,我硬編碼返回2
  }
})
a.b = 1 //打印 你要賦值給我,我的新值是1
console.log(b)        //打印 99
console.log(a.b)    //打印 你取我的值
                    //打印 2    注意這里,和我的硬編碼相同的

上面的代碼中,給a.b賦值,b的值也跟着改變了。原因是給a.b賦值,自動調用了set方法,在set方法中改變了b的值。vue雙向綁定的原理就是這個。

擴展

Reflect.defineProperty()

 可以使用ES6的靜態方法 Reflect.defineProperty(), 使用起來和 Object.defineProperty 完全一樣,唯一的不同是修改屬性的配置出錯時,返回false, 不拋錯。  例子:

var a = {}
Reflect.defineProperty(a, "b", {
    value: 2,
    configurable: false
})
Reflect.defineProperty(a, "b", {
    value: 2,
    configurable: true
})
//  返回false
var a = {}
Reflect.defineProperty(a, "b", {
    value: 2,
    configurable: false
})
Object.defineProperty(a, "b", {
    value: 2,
    configurable: true
})
//Uncaught TypeError: Cannot redefine property: b at Function.defineProperty (<anonymous>)  at <anonymous>:6:8

Object.defineProperties

此方法可以一次設置多個屬性,例子:

var a = {}
Object.defineProperties(a, {
    c: {
        value: 1
    },
    d: {
        value: 2
    }
})
// 返回{c: 1, d: 2}

用Object.defineProperty實現黑科技

使 a==1 && a==2 && a==3 為true

var b = 1
Object.defineProperty(window, "a", {
    get: function() {
        return b++
    }
})
console.log(a==1 && a==2 && a==3) //返回true

除此之外,還可以用對象的 toString() 方法來實現

var a = {
    b: 1,
    toString() {
        return this.b++
    }
}
console.log(a==1 && a==2 && a==3)  //返回true

 

ps: 這是本人在博客園寫的第一個博客,歡迎大家多對支持和提出意見建議

 

參考:https://www.cnblogs.com/weiqu/p/5860945.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM