iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
Modern Web

前端蛇行撞牆記系列 第 12

Day12 前端蛇行撞牆記 - 屬性描述器的定義方式

  • 分享至 

  • xImage
  •  

昨天我們介紹了六大屬性描述器,今天來介紹有哪幾種方式可以定義他們?
其實分為兩種方式:

建立物件的時候定義:

  • Object.create()

物件已建立完之後定義:

  • Object.defineProperty()
  • Object.definedProperties()

Object.create()

  • 先介紹Object.create()的用法:
Object.create(proto, propertiesObject)

建立但不定義屬性描述器:

const jade = {
  name: "Jade",
  age: 28,
  school: "TNUA",
  greet: function () {
    return `here is greet by ${this.name}`;
  },
};

const ann = Object.create(jade);

console.log(ann) // {} 所以是空物件

這一步只是讓 ann物件 跟 jade物件的 prototype 綁在一起而已 ,都還沒有設置他的 property ,所以現在ann裡面什麼也沒有,當然會是空物件。

我們再繼續設定下去,並且來看name的屬性描述器是什麼:

ann.name = "ann";

console.log(Object.getOwnPropertyDescriptor(ann, "name"));
// { value: 'ann', writable: true, enumerable: true, configurable: true }

console.log(ann);
// { name: 'ann' }

所以只要我直接用字面宣告的話,屬性描述器就會都是true。
當然這些也都可以在一開始建立時做到。

  • 建立並定義屬性描述器:

記得要先大括號因為屬性描述器也算是一個 object

const ann = Object.create(jade, {
  name: {
    value: "ann",
    writable: true,
    enumerable: true,
    configurable: true
  },
  age: {
    value: 20,
    writable: true,
    enumerable: true,
    configurable: true
  },
});

console.log(ann)
//
{ name: 'ann', age: 20 }

可是如果創建時定義只有寫最基本的value的話,其他就會被認定是false。

const ann = Object.create(jade, {
  name: {
    value: "ann",
  },
  age: {
    value: 20,
  },
});

console.log(Object.getOwnPropertyDescriptor(ann, "name"));

// 
{
  value: 'ann',
  writable: false,
  enumerable: false,
  configurable: false
}
// 全部都是false

所以要定義就全部一起定義。

不要任何原型的物件

另外如果想要創建一個沒有物件原型的物件的話,可以把Object.create()的第一個參數放null,就會是個沒有物件原型的物件了。

一般的則是長這樣,是會擁有Object的prototype的

Object.defineProperty()

  • 可以在已經創建好的物件再次跟對property定義屬性描述器。
  • 如果使用 Object.defineProperty() 定義屬性描述器只有寫value,其他屬性描述沒有特別去寫的預設值都會是 false

用法:

Object.defineProperty(obj, prop, descriptor)

建立:

const person = {};

// 沒有寫其他屬性特徵
Object.defineProperty(person, "name", {
  value: "Jade",
});

console.log(person); // !  {} 是空的!
console.log(person.name); // Jade 但還是有?!

console.log(Object.getOwnPropertyDescriptor(person, "name"));

// 因為沒有設定就都是false
{
  value: 'Jade',
  writable: false,
  enumerable: false,
  configurable: false
}

為什麼一開始是空物件是因為 enumerable: false ,不過其實name還是有value的!

Object.defineProperties()

  • 可以一次設定好幾個屬性特徵,跟Object.create()感覺有點像
const jade = {}

const ann = Object.defineProperties(jade, {
  name: {
    value: "ann",
    writable: true,
    enumerable: true,
    configurable: true
  },
  age: {
    value: 20,
    writable: true,
    enumerable: true,
    configurable: true
  },
})

console.log(ann);
// { name: 'ann', age: 20 }

Object.create() === Object.defineProperties() ???

做到上面那格時突然覺得這兩個根本超像,Object.create()也可以一次新增好多property啊!

但仔細想想就會感覺到他們本身就很不同:

  • Object.create()是用來建立要繼承物件的新物件
  • Object.defineProperties()是建立新物件一起定義屬性描述器,但沒有任何繼承

實際演練差異:
Object.create()需要一個變數去接,他無法直接改變物件

const jade = {};

const ann = Object.create(jade, {
  name: {
    value: "jade",
    enumerable: true,
    writable: false,
    configurable: false,
  },
  city: {
    value: "Taipei",
    enumerable: true,
    writable: false,
    configurable: false,
  },
});

console.log(ann);
// { name: 'jade', city: 'Taipei' }

如果沒有用變數去接的話就不會有任何改變

const jade = {};

Object.create(jade, {
  name: {
    value: "jade",
    enumerable: true,
    writable: false,
    configurable: false,
  },
  city: {
    value: "Taipei",
    enumerable: true,
    writable: false,
    configurable: false,
  },
});

console.log(jade);
// {}

可是以上只要改成defineProperties()的話就會直接改變到原本的物件

const jade = {};

Object.defineProperties(jade, {
  name: {
    value: "jade",
    enumerable: true,
    writable: false,
    configurable: false,
  },
  city: {
    value: "Taipei",
    enumerable: true,
    writable: false,
    configurable: false,
  },
});

console.log(jade);
// { name: 'jade', city: 'Taipei' }

總結:

  • 如果要自定義屬性描述器就全部都要定義,否則其他預設會是false。
  • 直接字面新增的話預設都會是true。

今天先這樣囉,明天見~


參考資料:008 深入瞭解JavaScript核心:函式、物件、原型鏈 (下)


上一篇
Day11 前端蛇行撞牆記 - 屬性描述器
下一篇
Day13 前端蛇行撞牆記 - Contructor function 建構式函式
系列文
前端蛇行撞牆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言