【前端基礎】關於 JavaScript 的型別系統:基礎型別、物件型別

閱讀時間約 15 分鐘

在剛開始寫 JavaScript 可能大多數的人不會特別意識到 JavaScript 的型別系統有什麼特別之處,我是在看完 Youtube 上 CS50 的課程,才理解到在不同的程式語言中,會因為語言的特性而有不同的系統,JavaScript 就是偏向比較特別的那一種。

JavaScript 型別特別之處,源自於「弱型別」與「高階語言」的特性,前者會在遇到需要條件判斷時針對型別轉為真值(Truthy Value)與假值(Falsy Value),而後者意味著:JavaScript 無法直接針對硬體進行操作,會直接使用 JavaScript 所提供的介面操作對應環境(瀏覽器、伺服器)中的項目,這兩件事對於 JavaScript 的型別系統有兩大影響:

  1. 在一些條件下,JavaScript 部分型別的空值,會被自動轉型
  2. 我們無法針對 JavaScript 的記憶體位置進行操作,取而代之是相似的儲存機制,基礎型別會儲存在各自的記憶體位置,物件型別則會生成一個「記憶體參考位置」來進行其中的記憶體參考位置。

初學者可能會看到上方的敘述感到頭很痛,會想說:「這些記憶體、轉型到底跟 JavaScript 的型別有什麼直接關係?」

如果你也有這樣的疑惑,就跟我先從最基礎的型別開始了解吧!

JavaScript 中的型別

在 JavaScript 中主要會分為兩大型別,分別是:基礎型別與物件型別,兩者的差異有:

  1. 前者儲存方式單純(後續會更深入的聊到);後者則是以記憶體參考位置來儲存資料。
  2. 前者資料格式單一,不會同時存在多種型別;後者可以儲存複合的資料格式,一個變數內可以同時存在多種型別。

這邊我會以自己覺得好理解的資料格式順序介紹:

基礎型別:字串(string):

字串是一個在 JavaScript 非常重要的型別,在一些 API 資料格式,與 HTML Input 元素取出的值大部分都是以字串為主,字串型別通常會以單引號「’」或是「”」雙引號將文字包裹起來,例如:

const name = "Vivian";

const year = "2023";

只要是被引號包裹起來的,不論其中的內容物是數字、符號、字元,在 JavaScript 中都被視為字串型別。

針對字串 JavaScript 提供了一些可以用來處理字串的方法,這邊列舉一些常用的方法:

const name = "Vivian";

const year = "2023";

// string.length 可計算字元長度
const nameLength = name.length;
console.log(nameLength);
// 6

// string.toLowerCase() 可以將字串中的大寫字母轉為小寫
const nameLowerCase = name.toLowerCase();
console.log(nameLowerCase);
// vivian

// string.toUpperCase() 可以將字串中的小寫字母轉為大寫
const nameUpperCase = name.toUpperCase();
console.log(nameUpperCase);
// VIVIAN

//string.trim() 過濾字串前後的連續空白字元,在進行表單欄位驗證時非常方便
const trimName = `${name} `.trim();
console.log(trimName);
// Vivian

在實務上,字串的資料格式常常是在取得來自後台的文案、資料庫的使用者資料:信箱、電話號碼、姓名等,因為數字與符號都可以被使用者不小心輸入進去,因此字串方法五花八門,也會為了符合公司、業主需求,延伸出一些驗證手段,使用 trim 方法過濾掉連續空白字元,可以說是最基本一種表單驗證手段。


基礎型別:數字(number):

JavaScript 數字可以用來顯示整數與小數點位數,但要注意一點是,針對小數點的處理是使用浮點數計算法(非十進位),所以針對小數點的處理會有誤差,如果要針對小數點做運算,建議可以轉為整數做處理,或是可以使用一些函式庫做處理:

// 在 JavaScript 直接計算小數點會有誤差:
0.1 + 0.2 = 0.30000000000000004

// 轉為整數處理
let result = (0.1 * 10 + 0.2 * 10) / 10
// result = 0.3

接著我們來看一些常用的數字方法:

// 將字串轉為數字,常用在轉換表單資訊的數字
const num = Number('1234');
console.log(num);
// 1234

// 針對小數四捨五入
const num = Math.round(3.6);
console.log(num);
// 4

// 針對小數無條件捨去
const num = Math.floor(3.6);
console.log(num);
// 3

// 取得介於 0 與 1 之間的隨機小數,通常可以用來搭配一些運算方式讓 UI 依照這些亂數順序顯示
const randomNumber = Math.random()
console.log(randomNumber);
// 0.03365605210247358

在實務上,數字型別會用來儲存跟數量、時間有關的單位,要注意的是只有數字可以被拿來做數學上的運算,所以需要用到計算時,要特別注意自己拿到的資料,是否真的是數字型別。


基礎型別:布林(Boolean)

布林是一種用來顯示 true 或是 false 的資料格式,通常會用來進行條件判斷,我個人認為布林是基本型別中最容易令人誤解的資料型別,它看似很簡單,但卻會涉及複雜的真值、假值,與自動轉型的議題,由於這部分會需要完整理解 JavaScript 中的型別系統,才能有更清楚的理解,這部分我會獨立出一篇內容來做介紹。


基礎型別:NaN

NaN 是英文 not a number 的縮寫,這個型別可能會出現在字串數字混合運算時出現預期外錯誤,導致最後運算出來的結果因型別錯誤而產生的非數字的結果,型別有可能是 NaN。


物件型別:物件

在 JavaScript 中,只要不是「基本型別」,可以儲存多種複合資料格式的型別,都可以稱之為廣義的物件。

而狹義的物件會用大括號 { } 包裹鍵值(key value pairs),如果有多組鍵值的話會使用逗號來區隔,主要的用途為呈現多種複合的資料,舉一個常見使用者資料作為範例:

const user = {
name: 'Vivian',
age: 26,
gender: 'female',
email: '[email protected]',
isEmailVerified: true,
};

假設我們寫一串假資料來模擬使用者行為,上方這個範例就是一個很常見的使用者資訊,譬如說:使用者的名稱、年齡、電子信箱以及電子信箱是否經過驗證等,可以看出來這樣的資料結構會是較為複合,甚至可以說能夠組成相對應更加複雜的資料結構。

與基本型別最大的不同的是,這些鍵值可以被視作物件的屬性,這些屬性可以被視作這個物件整體的小小器官、組織,各自象徵這個物件的一些特性,例如:一個網站的使用者身份是由許多不同的資料組成。

我們還可以針對物件屬性進行複寫、取值的的動作:

// 覆寫
user.name = 'vvn';

// 讀取物件
console.log(user);
/* {name: 'vvn', age: 26,
gender: 'female',
email: '[email protected]',
isEmailVerified: true} */

// 讀取物件屬性
console.log(user.name);
// 'vvn'

不過這樣覆寫物件屬性的方式,並不是一個好的做法,原因後續我們會提到。

由於物件自己本身的方法並沒有很頻繁被使用到,會需要在特定的場景下才會派的上用場,原因我們後續會提到,所以這裡我們先不談廣義物件的方法。

或是可以參考我撰寫的系列文章:致 JavaScript 開發者的 Functional Programming 新手指南


物件型別:陣列

陣列是一種用來管例重複性資料的資料結構,也是物件型別的一種,與物件最大的不同是,陣列是有順序性的,通常會使用中括號 [ ] 並以逗號分隔資料單位,舉例來說:

let numbers = [1, 2, 3, 4, 5];
let fruits = ['apple', 'banana', 'orange'];

// 取用陣列資料
console.log(fruits[0])

// 修改陣列資料
fruits[0] = 'berry';
console.log(fruits);
// ['berry', 'banana', 'orange'];

在實務上,我們會用陣列來儲存更加複雜的資料格式,例如:商品列表、使用者列表、數據等,由於我們會需要針對這些複雜的資料格式進行重複的處理,有些甚至是跟使用者行為有關的 UI 行為,因此比起物件來說,前端工程師可能花更多的時間處理陣列這個資料格式,接著就讓我們來看看有哪一些常用的陣列方法吧!

  • forEach
// forEach 遍歷陣列,使用情境:直接針對陣列做操作(對新手來說較好理解,實務上非必要不太會使用)

function processElement(element) {
// 執行特定的邏輯
console.log(element);
}

let fruits = ['apple', 'banana', 'orange'];
fruits.forEach(processElement);

forEach 是一個藉由帶入 callback 函式來遍歷(從第一個到最後一個)陣列中元素的陣列方法,通常陣列方法的第一個參數會是遍歷當前元素,第二個參數會是元素的索引(index)。

由於 forEach 本身不會回傳值,所以通常要碼是直接更改陣列,或是要在新增一個空的陣列,搭配其他的陣列方法來進行處理。

由於直接修改陣列內容會因為物件本身的記憶體位置特性,導致污染原始資料,所以我們比較少用到,如果從 JavaScript 記憶體角度不好理解這件事的話,也可以從另外一個實務開發角度來看這件事。

假設我們撈取了一筆使用者資料的列表,我想要在 A 頁面進行資料的批次處理,B 頁面保持原始資料,為了不要頻繁的呼叫 API ,我們還是要將 A 頁面經處理的資料,與 B 頁面要使用的原始資料分隔開來,不然就會出現頁面資料彼此污染的狀況。

  • filter

在許多情境下我們會需要針對既有的資料,來進行內容的篩選來避免網路請求所需要的額外時間與流量,我們會在 filter 陣列方法中帶入一個 callback 函式,並針對回傳條件的布林值,回傳出一個全新的陣列,我們來看一個篩選一到十之間偶數的篩選方式:

// 假設有一個陣列包含數字資料
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 使用 filter 過濾偶數數字
let evenNumbers = numbers.filter(function(number) {
return number % 2 === 0;
});

console.log(evenNumbers); // 輸出: [2, 4, 6, 8, 10]

在實務上的應用可能會更加複雜一點,舉例來說:透過指定的類別、分類篩選出指定的商品列表。

  • map

map 的概念為「映射」,我們可以帶入一個 callback 函式針對陣列進行運算後回傳結構類似,但樣貌、規律、結果可能不同的列表,這樣說可能會有點抽象,讓我們來看簡單的範例:

// 假設有一個陣列包含數字資料
let numbers = [1, 2, 3, 4, 5];

// 使用 map 將每個數字平方
let squaredNumbers = numbers.map(function(number) {
return number ** 2;
});

console.log(squaredNumbers); // 輸出: [1, 4, 9, 16, 25]

上述的範例中,我們把一串數字陣列,套用了計算平方的邏輯,最終產出一串與原始資料結構有類似邏輯,但計算規律不同的陣列。

在實務上,前端工程師可能不太會處理到複雜數學的計算邏輯,但有可能拿一串原始資料整理出 UI 元件,例如:商品列表、使用者列表、選單之類的 UI 元件,此時 UI 元件如果有一些重複性的文案或是邏輯,就可以透過 map 一次性套用原始資料的內容。

mapfilter 的優勢很顯而易見,就是能做到遍歷陣列的目的,同時整理、處理資料,但又不會污染原始資料。

由於陣列時常用於處理重複性的資料,也常常會遇到一些來自使用者的客製化需求,掌握好陣列方法可以說是非常有效益的一件事,這裡簡單條列一些,會用到且容易了解的陣列方法。

  • push(element):向陣列末尾新增一個元素。
  • pop():移除並返回陣列末尾的元素。
  • shift():移除並返回陣列開頭的元素。
  • unshift(element):向陣列開頭新增一個或多個元素。
  • length:取得陣列的長度。
  • concat(array):合併多個陣列。
  • slice(startIndex, endIndex):回傳從起始索引到結束索引(不包括結束索引)的子陣列。
  • splice(startIndex, deleteCount, items):從指定索引位置開始刪除指定數量的元素,並可插入新的元素。
  • indexOf(element):返回指定元素在陣列中首次出現的索引,若不存在則返回 -1。
  • includes(element):判斷陣列是否包含指定元素,返回布林值。

如果你會對如何更好的使用陣列方法撰寫 JavaScript,我會推薦你來閱讀這一系列的文章:致 JavaScript 開發者的 Functional Programming 新手指南,其中會有一些更進階的陣列方法應用與一些前端的延伸套件介紹。

我是 Vivian,我們下次見。

為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
留言0
查看全部
發表第一個留言支持創作者!
在前端開發中,很常會有需要轉址的需求,且處理的手法滿因人而異的,所以今天就想要來整理一些常見的 JavaScript 頁面轉址方式,以及各自的差異。
Functional Programming 中文譯作函式程式設計,或是功能性程式設計,常簡稱為:FP,是一種透過使用純函式(Pure Funciton)進行軟體開發,且避免副作用的程式設計典範,比起宣告式的流程控制,在 FP 採用主要以表達式的方式撰寫程式碼。
Hoisting 可以說是 ES6 問世之後,去面試還是會爾偶被問到的面試考題,雖然 Hoisting 離 Modern JavaScript 的技術有點距離,實作上幾乎不太會用到,但透過了解 Hoisting 的概念,可以對這門語言有更深的了解與掌握度。
對於剛接觸前端開發不久的人來說,可能會對var、let 與 const 的差異略懂略懂,但又說不太出三者實際哪裡不一樣。
在一開始學習前端開發的時候,一直遇到講師在課程內容中提到 ES5、ES6 等關鍵字,當初的我,單純認為 ES5、ES6 是講述 JavaScript 的版本,所以在使用上就沒有想太多,反正就是 JavaScript 1.0 、2.0 的感覺吧?
在初學程式的時候,我曾經看室友開發專案到一半時,突然坐在那發呆,於是我好奇一問,室友說:「我在等程式編譯完成啊。」 還記得當初還是程式小菜雞的我,懞懂無知的說:「編譯?哈哈哈,我們 JavaScript 都不需要編譯耶,可以直接跑在瀏覽器上。」 室友一臉莫名其妙地回我:「噢,是嗎⋯⋯」
在前端開發中,很常會有需要轉址的需求,且處理的手法滿因人而異的,所以今天就想要來整理一些常見的 JavaScript 頁面轉址方式,以及各自的差異。
Functional Programming 中文譯作函式程式設計,或是功能性程式設計,常簡稱為:FP,是一種透過使用純函式(Pure Funciton)進行軟體開發,且避免副作用的程式設計典範,比起宣告式的流程控制,在 FP 採用主要以表達式的方式撰寫程式碼。
Hoisting 可以說是 ES6 問世之後,去面試還是會爾偶被問到的面試考題,雖然 Hoisting 離 Modern JavaScript 的技術有點距離,實作上幾乎不太會用到,但透過了解 Hoisting 的概念,可以對這門語言有更深的了解與掌握度。
對於剛接觸前端開發不久的人來說,可能會對var、let 與 const 的差異略懂略懂,但又說不太出三者實際哪裡不一樣。
在一開始學習前端開發的時候,一直遇到講師在課程內容中提到 ES5、ES6 等關鍵字,當初的我,單純認為 ES5、ES6 是講述 JavaScript 的版本,所以在使用上就沒有想太多,反正就是 JavaScript 1.0 、2.0 的感覺吧?
在初學程式的時候,我曾經看室友開發專案到一半時,突然坐在那發呆,於是我好奇一問,室友說:「我在等程式編譯完成啊。」 還記得當初還是程式小菜雞的我,懞懂無知的說:「編譯?哈哈哈,我們 JavaScript 都不需要編譯耶,可以直接跑在瀏覽器上。」 室友一臉莫名其妙地回我:「噢,是嗎⋯⋯」
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
這篇文章更偏向純紀錄性質,方便日後有需要時直接複製相同指令來完成 Bootstrap 與 Sass 的引入,也會做成一個專案起手式的模板放在 Github ,未來在建置新專案時可以透過直接複製專案,來省去前面重複的這過程。
Thumbnail
微前端是一種現代前端架構,旨在將大型前端應用拆分為獨立、可獨立部署的小模組。這與微服務在後端的策略相似。 本文將探討微前端的基本概念,以及如何在基於Gin的後端系統中實施它,從而實現真正的全棧模組化。
Thumbnail
let 和 const 是 JavaScript 在 ES6 版本中新的變數宣告方式。使用 let 宣告的變數可以重新賦值,而使用 const 宣告的變數賦值後則不能改變。這兩種新的宣告方式提供了比 var 更嚴格和清晰的變數作用域管理。
Thumbnail
JavaScript 陣列的操作方法,forEach() 是用於遍歷陣列的每個元素,並對每個元素執行提供的函數,map() 是創建一個新陣列,其結果是對原陣列中的每個元素調用提供的函數後返回的結果。
Thumbnail
本文將介紹陣列的基本操作方法,包括建立陣列、存取元素、陣列遍歷和修改陣列等,接下來將逐一介紹這些操作,並附上程式碼範例,讓你更易於理解和運用。。
Thumbnail
JavaScript 陣列的操作方法,push() 可以將值加入到陣列的最後一個位置 ,pop() 會移除(取出)陣列的最後一個元素,shift() 會移除陣列的第一個元素,unshift() 則會將指定的元素添加到第一個位置。
Thumbnail
JavaScript 的命名規則相當重要,它有些特定的慣例和限制。例如,變數和函式通常使用小駝峰式(firstName)命名。然後 JavaScript 對大小寫敏感,所以lastName和lastname是不同的變數。
Thumbnail
npm 是一個套件管理工具,開發中經常需要使用第三方套件,npm 是可以用來管理很多套件的工具,這邊指的套件可能是 Library, 框架, 工具等,例如 Bootstrap, jQuery, Vue.js, babel 都可以統一由它管理。
Thumbnail
本文題目來自網站codesignal,它是個可依自己選取的程式語言進行測驗,測驗難易程度會逐題增加,可透過解題來獲得分數以及徽章,相當有趣味性。在sumbit後可在左欄看到票選最高的解法,這些解法來自不同語言,當然你可以在上面篩選自己撰寫的程式語言。沒有所謂的最好的解法,只有最適合的方式。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
這篇文章更偏向純紀錄性質,方便日後有需要時直接複製相同指令來完成 Bootstrap 與 Sass 的引入,也會做成一個專案起手式的模板放在 Github ,未來在建置新專案時可以透過直接複製專案,來省去前面重複的這過程。
Thumbnail
微前端是一種現代前端架構,旨在將大型前端應用拆分為獨立、可獨立部署的小模組。這與微服務在後端的策略相似。 本文將探討微前端的基本概念,以及如何在基於Gin的後端系統中實施它,從而實現真正的全棧模組化。
Thumbnail
let 和 const 是 JavaScript 在 ES6 版本中新的變數宣告方式。使用 let 宣告的變數可以重新賦值,而使用 const 宣告的變數賦值後則不能改變。這兩種新的宣告方式提供了比 var 更嚴格和清晰的變數作用域管理。
Thumbnail
JavaScript 陣列的操作方法,forEach() 是用於遍歷陣列的每個元素,並對每個元素執行提供的函數,map() 是創建一個新陣列,其結果是對原陣列中的每個元素調用提供的函數後返回的結果。
Thumbnail
本文將介紹陣列的基本操作方法,包括建立陣列、存取元素、陣列遍歷和修改陣列等,接下來將逐一介紹這些操作,並附上程式碼範例,讓你更易於理解和運用。。
Thumbnail
JavaScript 陣列的操作方法,push() 可以將值加入到陣列的最後一個位置 ,pop() 會移除(取出)陣列的最後一個元素,shift() 會移除陣列的第一個元素,unshift() 則會將指定的元素添加到第一個位置。
Thumbnail
JavaScript 的命名規則相當重要,它有些特定的慣例和限制。例如,變數和函式通常使用小駝峰式(firstName)命名。然後 JavaScript 對大小寫敏感,所以lastName和lastname是不同的變數。
Thumbnail
npm 是一個套件管理工具,開發中經常需要使用第三方套件,npm 是可以用來管理很多套件的工具,這邊指的套件可能是 Library, 框架, 工具等,例如 Bootstrap, jQuery, Vue.js, babel 都可以統一由它管理。
Thumbnail
本文題目來自網站codesignal,它是個可依自己選取的程式語言進行測驗,測驗難易程度會逐題增加,可透過解題來獲得分數以及徽章,相當有趣味性。在sumbit後可在左欄看到票選最高的解法,這些解法來自不同語言,當然你可以在上面篩選自己撰寫的程式語言。沒有所謂的最好的解法,只有最適合的方式。