iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
自我挑戰組

重新開始 JavaScript系列 第 21

[Day21] 物件的基礎概念2

今天來介紹如何判定物件與純值以及關於物件未被定義的屬性

物件與純值

在 JavaScript 只有兩種型別,純質與物件,而 物件可以新增屬性,純值不能

物件

昨天 Day20 - 物件的基礎概念 有提到可以透過物件實字來宣告物件,且可使用點記法、括號法來新增物件的屬性

const family = {name: 'Carol'};
family.money = 200;
console.log(family); // {name: 'Carol', money: 200}

純值

而所謂的 純值 就是在 Day13 - JavaScript 的原始型別 所提到的 JavaScript 原始型別,分別有:

  • Number 數字型別
  • String 字串型別
  • Boolean 布林值
  • Null 空
  • Undefined 未定義
  • BigInt 整數數值
  • Symbol

純值是無法新增屬性的,可看以下範例:

在純字串下新增屬性,會發現沒有改變

const nickName = 'Carol';
nickName.money = 200;
console.log(nickName); // Carol

利用建構式所新增字串非純值

另外使用建構式所新增的字串並非純值,我們可以使用是否可新增屬性來判定,利用 typeof 也可得出 object 的結果

以下範例中,使用 new String() 建構式所得出的字串並不能新增屬性,所以它並不是純值

const nickName = new String('Carol');
console.log(typeof nickName); // object
console.log(nickName); // String {'Carol'}

nickName.money = 200;
console.log(nickName); // String {'Carol', money: 200}

陳列

陣列是物件型別,所以可以新增屬性

const array = [];
array.a = 1;
console.log(typeof array); // object
console.log(array); // [a: 1]

函式

雖然使用 typeof 檢驗函式的型別,會得出 function 結果,但函式是屬於物件型別下的子型別,也是物件型別,只是比物件多了被呼叫的能力

在以下範例中,可看到函式可以新增屬性:

使用 console.dir(),可看到函式的物件格式,且可被展開

function fn() {
    console.log('Carol');
}
fn.a = 1;

console.log(typeof fn); // function
console.dir(fn); // ƒ fn()

要注意的是: 函式的屬性 name 為函式本身名稱,不可被覆蓋

以下範例中,可看到使用 fn.name = '123' 並無法更改函式的 name 屬性,因 name 是函式本身名稱所以無法被覆蓋,fn.a = 1 則因函式是物件所以可以被新增

function fn() {
    console.log('Carol');
}
fn.a = 1;
fn.name = '123';
console.dir(fn);

未被定義的物件屬性

當查看 未被定義的物件屬性,會顯示 undefined 而非 is not defined,且未被定義的物件屬性也無法再新增屬性

以下範例中,可以看到物件下未定義的屬性值是 undefined,且因這個屬性 members 不存在所以也無法在 members 下新增屬性 mom,故顯示錯誤訊息 Uncaught TypeError: Cannot set properties of undefined (setting 'mom')

const family = {
    name: 'Carol'
}
console.log(family); // {name: 'Carol'}
console.log(family.members); // undefined

family.members.mom = 'aa';
console.log(family); // 報錯 - Uncaught TypeError: Cannot set properties of undefined (setting 'mom')

在物件的未定義屬性下新增屬性的解決方法

  • 直接定義屬性,先給予一個預設值

    直接屬性 members,先給予一個空物件,最後再覆蓋

    const family = {
        name: 'Carol',
        members: {}
    }
    family.members.mom = 'aa';
    console.log(family); // {name: 'Carol', mom: {name: 'aa'}}
    
  • 直接在未定義屬性下新增一個物件結構

    雖然屬性 members 未被定義,但可直接在 members 下新增一個物件結構

    const family = {
        name: 'Carol'
    }
    family.members = {
        mom = 'aa'
    };
    console.log(family); // {name: 'Carol', mom: {name: 'aa'}}
    

補充 - 查看全域屬性

昨天 Day20 - 物件的基礎概念 有提到以下範例,b = 2b 其實是全域的屬性而非變數,所以可被刪除

var a = 3;
b = 2;
console.log(delete a); // false
console.log(delete b); // true

結合今天所講的內容,以下範例中 a 並非變數且未被定義,而要查看全域中不存在的屬性,使用 console.log(全域屬性); 會報錯,而未被定義的物件屬性值為 undefined,所以可改用 console.log(window.全域屬性); 得出值為 undefined

// a 為未被定義的全域屬性
console.log(a); // Uncaught ReferenceError: a is not defined

可改為

console.log(window.a); // undefined

參考文獻

六角學院 - JavaScript 核心篇


上一篇
[Day20] 物件的基礎概念
下一篇
[Day22] 傳值跟傳參考概念
系列文
重新開始 JavaScript32

尚未有邦友留言

立即登入留言