iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 13
0
Modern Web

教練我想學 JavaScript 系列 第 13

Day 13 物件與點

在其他的程式語言中 物件與函數是兩個不同的東西,
但是在 JavaScript 裡 它們是非常非常相關的
它們在很多情況下幾乎是一樣的
所以讓我們來談談物件和函數

我們先來看物件和點
記得之前說過物件的值也可以是另一個「名稱/值」的組合

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 30 影片截圖

物件的值可以是純值、另外一個物件(名稱/值配對)、函數(在物件裡稱作方法),
屬性或方法與物件本身有所連結,物件可以參考到屬性和方法

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 30 影片截圖

在記憶體中
核心物件會有一個記憶體的位址
然後可以參考到這些電腦記憶體中的屬性和方法的位址

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 4 節講座 30 影片截圖

屬性和方法的位址可能有關,也可能無關
但無論如何,物件能夠參考到這些位址空間
找到這些屬性、方法的所在

來看看 JavaScript
如何找出那些物件的屬性和方法的記憶體位置

我要建立一個新的物件 var person
用「等於」這個指派運算子 然後再使用 new 這個特殊的運算子來新增物件,
程式碼如下:

var person = new Object();

有其他方式可以更快的新增物件
但現在我先用 new object 的語法建立一個新的物件
因為這比較清楚表示我們在幹嘛
現在已經建立好一個新物件
然後它會在記憶體裡
現在我新增一些屬性和方法
例如,person
然後用一個稱為「Computed Member Access」的運算子
在中括號裡我放進值的名稱
讓我存在記憶體中的東西
比如,[firstname]
它還不存在,所以令他等於 Jimmy
這會在記憶體中創造這個東西,然後給他那個名字
然後這個物件就能夠參考到它在記憶體中的位子
所以,它會知道 [firstname] 在記憶體中的位子
並且知道是純值的字串
這就是屬性 一個稱為 firstname 的屬性
這是其中一種取用屬性的方法
程式碼如下:

var person = new Object();
person['firstname'] = "Jimmy";

回到運算子優先性和相依性表格

運算子優先性,你會發現我們有「Computed Member Access」
在很上面
它是左到右相依的 這是中括號
所以這是一個運算子
這個運算子能夠找出物件的屬性和方法

用這個字串去取用是其中一種方法
然後設定「lastname
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

這個運算子好用的地方是我可以將字串指派給一個變數
在中括號中使用變數,如果值是會改變的,就很適合用這種方式來取用屬性
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

var firstNameProperty = "firstname";

console.log(person);
console.log(person[firstNameProperty]);

我們來看 Console 中的結果:

這個中括號是「Computed Member Access 運算子」
它把物件當做一個參數,然後字串當做另一個參數
然後找到屬性,並回傳它的值
我也將物件本身輸出
我可以看到這兩個屬性:firstname 和 lastname
還有另一個屬性 proto
現在不用管他
但之後會講到這個
現在只要專注在我建立的東西就好 firstname 和 lastname
我用中括號這個特殊運算子找到 firstname

講講另一個運算子
更常見、清楚
很簡單就能打出來的運算子 可以取用屬性和方法

你可以用字串
但這個比較清楚,也很容易打出來
接下來我要 console.log 出 firstname
但我要用一個不同的運算子 「點」運算子
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

var firstNameProperty = "firstname";

console.log(person.firstname);

這個點運算子是個函數
當它接在物件之後時
回到運算子優先性和相依性表格

你可以看到這是優先性第二高的

它是從左到右的 需要兩個參數
物件名稱和屬性名稱
我沒有放在引號內

console.log(person.'firstname'); // 錯誤的寫法

雖然本質上它是這樣運作的
它會將字串傳入物件
這是你想要的值的名稱
不過不需要這樣做 這樣不正確
別這樣做

如果你放在點後面,語法解析器會自動瞭解

console.log(person.firstname); // 正確的寫法

你打出來的東西就是想要傳入的字串
這樣我們打字可以更快
我們到 Console 看結果:

所以這個點就和中括號一樣
這是取用成員的方式
這叫做成員取用
成員取用運算子 成員就是物件的成員
手指和腳指就是你身體的成員
所以它會幫你找到物件的成員,像是方法和屬性
所以它會找到這個屬性,因為只是個字串
他不會呼叫出方法
而是呼叫屬性

所以我可以console.log 出 person.lastname
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";


var firstNameProperty = "firstname";

console.log(person.firstname);
console.log(person.lastname);

Console 中的結果:

很易讀、打字也很簡單
就是這樣
它會找到記憶體的位址
然後這個名稱從物件去參照
我也可以用這個方法去設值

其實,屬性的種類有很多種
除了純值外,還可以是另外一個物件
我可以新增一個名稱/值的配對
設定 person.address
我不設定字串、數值或布林
而是另一個用 new 運算子創造出來的物件,
程式碼如下:

var person = new Object();
person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

person.address = new Object();

所以這是物件中的物件
然後我可以用「點運算子」增加屬性
給我的子物件

程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

person.address = new Object();
person.address.street = '123 Main St.';

這些都是運算子 我們要怎麼知道誰先運算呢
就要回到相依性來判斷
成員取用運算子是左到右相依
是左相依性的, 所以在點左邊會先被執行
然後才是右邊

所以在 person 和 address 中間的這個點會先執行
然後看 person 這個物件
然後找屬性和方法的名字
最後在記憶體中找到它們

接下來是第二個點,它會找到這個物件
在記憶體中找到,進而找尋它的屬性或方法 叫 street

在這個情況下 他無法找到這個屬性,所以我設一個值給他
然後它就會自動建立這個屬性,並且賦予他值

我可以在替 person.address 增加其他屬性
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

person.address = new Object();
person.address.street = '123 Main St.';
person.address.city = 'New York';
person.address.state = 'NY';

我可以不斷建立子物件
我可以不斷這樣建立 因為它是左相依性的
物件可以不斷包含其他物件
這很強大
物件本身和屬性方法都待在記憶體內
這些點、中括號都只是函數
它們是運算子 一個取出資訊的方式

我們分別用這兩種運算子來取值,
程式碼如下:

var person = new Object();

person['firstname'] = "Jimmy";
person['lastname'] = "Huang";

person.address = new Object();
person.address.street = '123 Main St.';
person.address.city = 'New York';
person.address.state = 'NY';

console.log(person.address.street);
console.log(person.address.city);
console.log(person["address"]["state"]);

Console 中的結果:


他們本質上是一樣的

也請記得, 雖然我們可以用點也可以用中括號去取用屬性和方法
最好還是只要用點運算子就好
他很簡潔、很清楚 也很容易除錯
建議用點運算子存取物件的屬性
除非你真的需要用動態字串取用屬性
一些可能會改變的字串
但剛開始的時候, 只要用點運算子就好
這就是物件和點

物件實體

可以使用物件實體語法(object literal syntax)來建立物件,JavaScript可以使用{}來建立物件,{}不是運算子,當JavaScript解析語法時看到大括號,而你不是當作if條件式或迴圈時,它就是假設你在創造物件。對JavaScript來說它就是建立物件到記憶體中,還有屬性和方法到記憶體,
程式碼如下:

var Jimmy = {
  firstname: 'Jimmy',
  lastname: 'Huang',
  address: {
    street: '123 Main St.',
    city: 'New York',
    state: 'NY'
  }
};

可在函數呼叫時把物件當作參數傳入
程式碼如下:

var Jimmy = {
  firstname: 'Jimmy',
  lastname: 'Huang',
  address: {
    street: '123 Main St.',
    city: 'New York',
    state: 'NY'
  }
};

function greet(person) {
console.log("Hi " + person.firstname);
}

greet(Jimmy);

Console 中的結果:

可在呼叫函數時同時創造物件,
程式碼如下:

function greet(person) {
console.log("Hi " + person.firstname);
}

//這個物件在被呼叫時同時建立(到記憶體中)
greet({    
  firstname: 'John',
  lastname: 'Doe'
});

Console 中的結果:

也可使用點(成員取用)運算子來新增物件的屬性
程式碼如下:

var Jimmy = {
  firstname: 'Jimmy',
  lastname: 'Huang',
  address: {
    street: '123 Main St.',
    city: 'New York',
    state: 'NY'
  }
};

//可以結合.運算子與物件實體語法
Jimmy.address2 = {
  street: '333 Seconed St.'
}
console.log(Jimmy);

Console 中的結果:

所以不論物件實體語法
或是用點運算子建立物件
都是一樣的
對於 JavaScript 引擎來說
就是在建立物件到記憶體中 還有屬性和方法到記憶體

所以我用的語法對 JavaScript 引擎沒差
都是建立同樣的東西
JavaScript 能夠用以上兩種語法建立物件
重要的是你要用哪種語法?
物件實體語法真的很強大
他可以寫出很簡潔的程式碼 也很易懂
這就是物件實體語法(object literal syntax)
用大括號去定義 用冒號區隔名稱和值


上一篇
Day 12 存在(exeistence)、布林(Boolean) 與預設值
下一篇
Day 14 函數就是物件
系列文
教練我想學 JavaScript 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言