iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 10
1
自我挑戰組

JavaScript 試煉之旅系列 第 10

物件(Object)的方法 Part 2

取出列舉特性

第一個方法: for...in

先來看一段關於 MDN對於 for...in 的解釋:

for...in 迴圈只迭代可列舉屬性。....迴圈將迭代全部可列舉屬性,包括了物件自身的和物件繼承自它的建構式之原型的可列舉屬性。(原型鏈上較接近物件的屬性覆蓋原型的屬性)

意思是使用 for...in 不只將物件自己的可列舉特性取出,也會將繼承而來的可列舉特性也一併取出

來看看個測試例子:

var obj = {
  sayHi:() => console.log('Hello!')
}

var obj2 = Object.create(obj);
obj2.name = "Bill";
obj2.habbit = "Read Books";

for( key in obj2){
  console.log(key);
}

透過 Object.create()obj 傳入obj2 當作 obj2 的原型物件,此時使用 for...in 可以發現取出來的特性包含了繼承而來的特性

Day10-1
第二個方法: Obejct.keys()

MDN: Object.keys() 方法會回傳一個由指定物件所有可列舉之屬性組成的陣列,該陣列中的的排列順序與使用 for...in 進行迭代的順序相同(兩者的差異在於 for-in 迴圈還會迭代出物件自其原型鏈所繼承來的可列舉屬性)。

MDN 的解釋中,可以歸納出幾個重點:

  1. 使用 Object.keys() 會得到指定物件的所有可列舉特性所組成的陣列。
  2. for...in 不同,並不會從原型物件中繼承來的可列舉特性也一併取出。

將上一個測試例子改寫一下:

var obj = {
  sayHi:() => console.log('Hello!')
}

var obj2 = Object.create(obj);
obj2.name = "Bill";
obj2.habbit = "Read Books";

const keys = Object.keys(obj2);
console.log(keys);

Day10-2

第三個方法: Object.getOwnPropertyNames()

透過 Object.getOwnPropertyNames() ,能回傳所有可列舉、不可列舉的特性所組成的陣列。

來個例子測試一下:

var obj = {
  name: 'Bill',
  habbit: 'Read books'
}

Object.defineProperty(obj,'weight',{
  value: '65kg',
  enumerable:false
})

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

Day10-3
將上述所提到取出列舉特性的部分做個表格歸納一下:

語法 可取得列舉特性 可取得原型物件列舉特性 可取得不可列舉特性
for...in O O X
Object.keys O X X
Object.getOwnPropertyNames O X O

物件的擴充性

關於怎麼判斷某物件是否可以擴充,或者如何設定某物件的擴充性,以下有一些方法可以達成。

第一個是: Object.isExtensible()

用來判斷某個物件是否具有擴充性

var obj = {
  name: "Bill",
  habiit: "Read books"
}

console.log(`obj物件是否具擴充性: ${Object.isExtensible(obj)}`); 

接下來來看看不可擴充的情況

第二個是: Object.preventExtensions()

物件的特性不能再被新增到物件中。

但需要注意的是,物件依然可以刪除原本已存在的特性

寫個測試的例子驗證一下:

var obj = {
  name: "Bill",
  habbit: "Read books"
}

Object.preventExtensions(obj);
console.log(`obj物件是否具擴充性: ${Object.isExtensible(obj)}`); 

obj.sayHi = () => console.log('Hello!');
delete obj.name;

var prop = Object.keys(obj);
console.log(`obj物件的特性有: ${prop}`);

為了檢查擴充性,所以新增了一個 sayHi 方法給 obj 物件,而透過結果可以發現,這個新增的特性並沒有被新增到 obj 中。

再來透過delete 刪除了 obj 物件的 name 特性,所以也就只剩下特性 habbit 了。

Day10-4

第三個是: Object.seal()

Object.seal() 有一些特性需要注意,如下:

  1. 物件變成不具擴充性(新特性無法加入)
  2. 密封(seal)的物件不能解密封
  3. 透過 Object.isSealed() 判斷該物件是否密封
  4. 現有特性無法被刪除,但可以修改特性的值
  5. 只對被指定的物件有效,該指定物件的原型物件則不起作用。

來寫個測試例子:

var obj = {
  name: "Bill",
  habbit: "Read books"
}

Object.seal(obj);
console.log('obj物件是否已經被密封(sealed): ' + Object.isSealed(obj));

// 查看 sayHi 方法能否被新增
obj.sayHi = () => console.log('Hello!');
console.log(obj);

// 查看 name 特性是否有被刪除
delete obj.name;
console.log(obj);

obj.name = "Jack";
// 查看 name 的特性是否被修改
console.log(obj);

Day10-5

第四個是: Object.freeze()

Object.freeze() 有一些特性需要注意,如下:

  1. 物件變成不具擴充性(新特性無法加入)
  2. 透過 Object.isFrozen() 判斷該物件是否凍結
  3. 現有特性無法被刪除並唯讀(代表值無法被修改)
  4. 只對被指定的物件有效,該指定物件的原型物件則不起作用。

來寫個測試例子:

var obj = {
  name: "Bill",
  habbit: "Read books"
}

Object.freeze(obj);
console.log('obj物件是否已經被凍結: ' + Object.isFrozen(obj));

// 查看 sayHi 方法能否被新增
obj.sayHi = () => console.log('Hello!');
console.log(obj);

// 查看 name 特性是否有被刪除
delete obj.name;
console.log(obj);

obj.name = "Jack";
// 查看 name 的特性是否被修改
console.log(obj);

Day10-6

物件的取值器(getter)、設值器(setter)

  1. 取值器(getter) 實際上會呼叫一個隱藏的函式來取回一個值。
  2. 設值器(setter) 實際上會呼叫一個隱藏的函式用來設定值的特性

當兩者搭配運用時,就會將其定義成 「存取器描述器」(accseeor descriptor)。

直接透過測試例子來看看怎麼運作:

先看看取值器(getter)的使用:

var obj = {
  get sayHi() {
    return 'Hello! ';
  } 
}

const respond = obj.sayHi;
console.log(respond);

取值器(getter) 會呼叫一個隱藏的函式(也就是 sayHi ),並回傳 Hello! 這個值給 respond 變數。

再看看設值器(setter)的使用:

var obj = {
  name:this.name,
  set getName(name) {
    this.name = name;
  } 
}

obj.getName = "Bill";
console.log(obj.name);
  1. 設值器(setter)會呼叫一個隱藏的函式(也就是 getName ),並將 Bill 這個值做為 getName 的參數傳入,此時 obj 物件 name 的特性值已變成 Bill
  2. 所以當我們想要取得 name 特性的值時,就可以拿到 Bill

最後看看兩者搭配的使用:

var obj = {
  name:this.name,
  
  get sayHi() {
    return 'Hello! ' + this.name;
  },
  
  set getName(name) {
    this.name = name;
  } 
}

obj.getName = "Bill";
const respond = obj.sayHi;
console.log(respond);
  1. 設值器(setter)會呼叫一個隱藏的函式(也就是 getName ),並將 Bill 這個值做為 getName 的參數傳入,此時 obj 物件 name 的特性值已變成 Bill
  2. 取值器(getter) 會呼叫一個隱藏的函式(也就是 sayHi ),並回傳 Hello! Bill 這個值給 respond 變數。

今天就先到這裡囉

明天見~


上一篇
物件(Object)的方法 Part 1
下一篇
傳值(By value)與傳參考(By reference)
系列文
JavaScript 試煉之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言