物件實字
前面兩個章節我們都談過 JavaScript 的基礎,這邊依然要說 JavaScript 的基礎 — ”物件“。在 JavaScript 上常用的種類可以大概的分為兩項,一為物件,二為 Function,兩者我們都會很常碰見,但是最常做資料處理的就是物件,所以把物件的一些眉眉角角搞清楚也是很重要的!
首先要先說物件的讀取方式,通常物件的讀取方式有兩種,一種是點,一種是中括號。
var aaa = { name: '123'}console.log(aaa.name); -> 第一種讀取方式 點
console.log(aaa['name']); -> 第二種讀取方式 中括號
那你肯定會問,兩種都可以讀取差別在哪呢?其實之前菜雞如我一直也都不知道,傻傻的想能讀到值就好啦,一直到這次開始做筆記才發現兩者的不同。兩者的差別如下:
點的特性:
1. 只能單純讀取字串。
2. 能讀取的用法比較有限。
中括號的特性:
1. 可以用變數作為屬性名或訪問,而點方法不可以。
2. 可以用數字作為屬性名,而點語法不可以。
3. 可以動態訪問的屬性名,可以在程式執行時建立和修改屬性,點操作符就不行。
4. 如果屬性名中包含會導致語法錯誤的字元,或者屬性名是關鍵字或者保留字,也可以使用方括號表示法 ( 比如 空格[‘first name’] )。
var aaa = {};
aaa.name = '小明';
var myName = 'Rex';
console.log(aaa.myName); //undefined 訪問不到對應的屬性
console.log(aaa[myName]); //小明
簡單來說,中括號可運用範圍較大,點的方法通常只能用來呼叫字串。上方有提到 JavaScript 常用的種類第二種是 Function ,所以如果要執行一段函式我們會這樣呼叫:
var aaa = { run: function() { console.log('123'); }};// 點的呼叫方式->
aaa.run();// 中括號的呼叫方式->
aaa['run']();
物件的宣告與刪除
上方我們講解了使用,但是物件其實還有宣告及與變數刪除,下方就用 Code 解說怎麼使用吧!
var aaa = {};// 新增用法aaa.name = '我是後來加上的名字';aaa['habit'] = '寫Code';console.log(aaa.name); // 會得到 '我是後來加上的名字';// 刪除用法delete aaa.name;
雖然物件的變數可以刪除,但是這邊有個小地方需要注意,變數無法被刪除 屬性才可以,甚至你可以使用 delete 來刪除全域變數,不過通常我們不會這樣做。
var a = '123';b = '456';delete a; // 變數 a 無法被刪除
delete b; // 變數 b 屬性可以被刪除// 詳細可參考 MDN 傳送門
小提示:console.dir(); 可以看到物件的所有型別,陣列也算物件型別 可以自由新增屬性,Function 也算物件型別下的子型別, Function 的屬性無法覆蓋 只能新增不同名稱。
臨門來一腳
有時候我們會碰到 undefined 未定義物件的情況 ,這種情況一種處理方式是 一開始就給物件預設的名稱,後面給空物件或陣列或是後來再給物件或陣列。
// 解決方法一
var aaa = { name: '123', habit: { <-- 一開始就給預設屬性 // ... }};// 解決方法二aaa.habit = { <-- 第二種方式 // ...}
物件的參考特性
這個地方就要講到我們的記憶體了,相信很多文章常常會說到這個。你有想過宣告的變數都跑去哪了嗎?還有為何宣告後其他的地方可以使用這個變數?改變了另一個變數的屬性,為何上一個相同的變數屬性會跟著改變呢?這就要說到 傳值與傳參考 (值傳過去後就沒什麼關聯性),傳什麼值又傳什麼參考呢?只要先記得,傳得值基本是下面五項,傳的參考呢,就是 Function。
1.布林 Boolean、空 Null(註2)、未定義 Undefined、數值 Number、字串 String — > 傳值
2.function — > 傳參考
關於參考位置
講到這邊就常常會想起上方那張圖,當我們在宣告一個變數的時候,在前面章節說到的創建階段電腦會先幫我們的變數找一個記憶體位置存放,而當後面我們把存放完成的變數拿來賦予到其他值上的時候,那個值的記憶體位置就會指向原本儲存過的記憶體位置,這樣就能解省電腦的記憶體空間。
小筆記:求值策略
傳參照呼叫(Call by reference) 傳值是傳實際參數 不是拷貝的 (ex: C語言)
傳共用物件呼叫(Call by sharing) 如果被呼叫者修改了物件,呼叫者可以看見變化 (ex:JavaScript)
更詳細的解說可以參考 Alex 宅幹嘛 — [ Alex 宅幹嘛 ] 👨💻 深入淺出 Javascript30 快速導覽 | Day 14:JavaScript References VS Copying
影分身之術?
講到複製就必須要提到 深拷貝 及 淺拷貝,如果傳參考更改值都會影響到前一個,那要怎麼辦呢?就必須脫離前一個參考,自己另立門戶,所以深拷貝簡單說就是在創造一個看似一模一樣,但是已經是A貨等級的山寨品,跟原本的值八杆子打不著,下面就來看看怎麼深拷貝 及 淺拷貝吧。
// 先說說淺層複製 如果要把 aaa 的變數都加進新的陣列裡 這種方法會是 淺拷貝var aaa = { name = '123', habit = { sing: true, dance: false, };};var newArr = {};// 第一種方式for(var key in aaa){ console.log(key); -> name, habit newArr[key] = aaa[key];}
// 第二種 及 第三種方式 都是 JQueryvar bbb = jQuery.extend({}, family);var ccc = jQuery.Object.assign({}, family);// 這邊必須提一下 Object.assign 是 ES6(註1) 的新函式,{}的地方意思是先建立一個空物件,然後所有的屬性複製過去新的陣列 ccc,雖然第一層能順利地指向不同的記憶體位置,但是第二層開始又是一樣指向原本的記憶體位置,無法做到真正的深拷貝。// 有興趣可以參考這篇文章 傳送門
關於淺拷貝的問題就是,他傳值過來,你跟原本的變數指向的記憶體位置都是同一個地方,就如上方那張圖,所以改了值,原本的變數的屬性也會跟著變動,那解決方式就是下方的深拷貝了!
// 1. 目前最快的深拷貝方式 缺點是無法轉 FunctionJSON.parse(JSON.stringfy('666')); // 2. 如果使用 jQuery 可以使用 jQuery 的語法var obj2 = $.extend(true, {}, obj1);// 3. lodash 這是目前我最常用的 有興趣可以參考文件 傳送門_.cloneDeep();
額外補充
關於陣列塞值,如果新增的變數有跳號,中間沒有 value 得值會自動補上 empty。
var Arr = [
0: 1,
]Arr['1'] = 1;
Arr['3'] = 3;// Arr['2'] = empty
註1:ES 又稱 ECMAScript,Script 代表著腳本,而 ECMAScript 提供了腳本語言需要遵守的規則、細節和規範, JavaScript 是實現 ECMAScript 的規範後所誕生出來的語言。簡單點來說就是一些可以讓你更簡單做事情的Function 及 一些寫 Code 規範,更詳細的發展歷程可以點 傳送門 查看。
Conclusion & 結論
本次章節的內容雖然也是短短的,但是這卻是學了好一陣子才慢慢開始發現的知識,有些地方也是埋了滿滿的雷,像是深拷貝及淺拷貝,如果沒有處理好,一不小心就會噴錯;而最近常常在處理資料的轉換,對於物件好像又像從新認識一番,既熟悉又陌生的感覺,我想也是需要再加油的地方,不過這次寫了一點筆記,感覺又熟悉了一點呢,繼續努力的往前進!加油。
參考網站
六角學院 — JavaScript 核心篇
ITREAD — JavaScript中物件屬性通過點(.)和方括號([])取值的不同之處
MDN — 屬性的刪除
[ Alex 宅幹嘛 ] — 👨💻 深入淺出 Javascript30 快速導覽 | Day 14:JavaScript References VS Copying
Loadsh — index
鐵人幫AndyChen大大 — JS版本差異!ES5、ES6