淺析JavaScript對(duì)象轉(zhuǎn)換成原始值
前言
首先拋出幾個(gè)問(wèn)題:
console.log(Boolean({})); console.log(Number([])); console.log(Number([6])); console.log(([] + []).length); console.log(({} + {}).length);
打印結(jié)果都是啥?不知道各位能答對(duì)幾題。文章末尾,我們會(huì)揭曉答案。這篇文章建議大家耐心閱讀,相對(duì)來(lái)說(shuō)比較繞而且乏味 - -。
三種算法
JavaScript 將對(duì)象轉(zhuǎn)換為原始值時(shí)遵循的算法規(guī)則比較復(fù)雜,這些規(guī)則冗長(zhǎng)、晦澀,我們先簡(jiǎn)單了解一下,具體實(shí)現(xiàn)后面再詳細(xì)展開(kāi)。
對(duì)象轉(zhuǎn)換成原始值有三種基本算法:
- 偏字符串算法。該算法返回原始值,而且只要可能就返回字符串。
- 偏數(shù)值算法。該算法返回原始值,而且只要可能就返回?cái)?shù)值。
- 無(wú)偏好算法。該算法不傾向于任何原始值類型,而是由類定義自己的轉(zhuǎn)換規(guī)則。JavaScript 內(nèi)置類除了 Date 類,其他都實(shí)現(xiàn)了偏數(shù)值算法。Date 類實(shí)現(xiàn)了偏字符串算法。
對(duì)象轉(zhuǎn)換成布爾值
對(duì)象到布爾值的轉(zhuǎn)換最簡(jiǎn)單:所有對(duì)象都轉(zhuǎn)換為true
。這個(gè)轉(zhuǎn)換不需要使用前面介紹的轉(zhuǎn)換算法,直接適用于所有對(duì)象,包括空數(shù)組、包裝對(duì)象:
console.log(Boolean([])); // => true const wrapperObject = new Boolean(false); // 這是一個(gè)對(duì)象,而不是原始值 console.log(Boolean(wrapperObject)); // => true
對(duì)象轉(zhuǎn)換成字符串
在將對(duì)象轉(zhuǎn)換成字符串時(shí),首先使用偏字符串算法將它轉(zhuǎn)換為一個(gè)原始值,然后將得到的原始值再轉(zhuǎn)換為字符串。
這種轉(zhuǎn)換會(huì)發(fā)生在把對(duì)象傳給一個(gè)接收字符串參數(shù)的內(nèi)置函數(shù)時(shí),比如將String()
作為轉(zhuǎn)換函數(shù),或者將對(duì)象插入模板字面量中時(shí)就會(huì)發(fā)生這種轉(zhuǎn)換:
console.log(String({})); // => '[object Object]' console.log(String([])); // => '' console.log(String(function () {})); // => 'function () {}'
對(duì)象轉(zhuǎn)換成數(shù)值
當(dāng)需要把對(duì)象轉(zhuǎn)換為數(shù)值時(shí),首先使用偏數(shù)值算法將它轉(zhuǎn)換為一個(gè)原始值,然后將得到的原始值再轉(zhuǎn)換為數(shù)值。
接收數(shù)值參數(shù)的內(nèi)置函數(shù)和方法都以這種方式將對(duì)象轉(zhuǎn)換為數(shù)值,除數(shù)值操作符之外的多數(shù)操作符也按照這種方式把對(duì)象轉(zhuǎn)換為數(shù)值:
console.log(Number([])); // => 0 console.log(Number({})); // => NaN console.log(+[]); // => 0
上面的栗子了解一下即可,具體的轉(zhuǎn)換算法后面會(huì)詳細(xì)解釋。
轉(zhuǎn)換時(shí)使用的方法
toString()
、valueOf()
,所有對(duì)象都會(huì)繼承這兩個(gè)在對(duì)象到原始值轉(zhuǎn)換時(shí)使用的方法,在接下來(lái)解釋偏字符串、偏數(shù)值、無(wú)偏好轉(zhuǎn)換算法之前,我們必須先了解這兩個(gè)方法。
toString()
toString()
的任務(wù)是返回對(duì)象的字符串表示。
默認(rèn)情況下,toString()
方法會(huì)返回特殊值:
const obj = { x: 1, y: 2, } obj.toString(); // => '[object Object]'
但是很多類都定義了自己特有的toString()
版本。
比如,Array
類的toString()
方法會(huì)將數(shù)組的每個(gè)元素轉(zhuǎn)換為字符串,然后再使用逗號(hào)作為分隔符將它們拼接起來(lái):
const array = [1, 2, 3]; array.toString(); // => '1', '2', '3'
Function
類的toString()
方法會(huì)將用戶定義的函數(shù)轉(zhuǎn)換為 JavaScript 源代碼的字符串:
const f = function () {}; f.toString() // => 'function () {}'
Date
類定義的toString()
方法返回一個(gè)對(duì)人類友好的日期和時(shí)間字符串。
RegExp
類定義的toString()
方法會(huì)將RegExp
對(duì)象轉(zhuǎn)換為一個(gè)看起來(lái)像RegExp
字面量的字符串。
valueOf()
valueOf()
方法的設(shè)計(jì)意圖是返回對(duì)象的原始值表示。
然而大多數(shù)對(duì)象都沒(méi)有缺省的原始值表示,為此valueOf()
的默認(rèn)實(shí)現(xiàn)是返回對(duì)象本身,內(nèi)置的函數(shù)、數(shù)組等類型都是如此:
const obj = {x: 666}; const arr = [1, 2, 3]; const fn = function () {}; obj.valueOf(); // => {x: 666} arr.valueOf(); // => [1, 2, 3] fn.valueOf(); // => ? () {}
極少數(shù)對(duì)象才具有有意義的原始值表示,比如String
、Number
、Boolean
這樣的包裝類定義的valueOf()
方法會(huì)簡(jiǎn)單地返回被包裝的原始值:
const wrapperObj1 = new String(666); const wrapperObj2 = new Number(888); const wrapperObj3 = new Boolean(false); wrapperObj1.toString(); // => '666' wrapperObj2.toString(); // => '888' wrapperObj3.toString(); // => 'false'
還有Date
對(duì)象定義的valueOf()
方法返回時(shí)間戳:
const d = new Date(2022, 6, 24); d.valueOf(); // => 1658592000000
了解完toString()
和valueOf()
方法后,接下來(lái)我們看看轉(zhuǎn)換算法是如何實(shí)現(xiàn)的。
轉(zhuǎn)換算法
偏字符串算法
偏字符串算法首先嘗試toString()
方法。如果這個(gè)方法有定義且返回原始值,則使用這個(gè)原始值,即使這個(gè)值不是字符串。如果toString()
方法不存在,或者存在但返回對(duì)象,則嘗試valueOf()
方法。如果valueOf()
方法存在且返回原始值,就使用該值。否則,轉(zhuǎn)換失敗,報(bào) TypeError。
偏數(shù)值算法
偏數(shù)值算法與偏字符串算法類似,只不過(guò)是先嘗試valueOf()
方法,再嘗試toString()
方法。
無(wú)偏好算法
無(wú)偏好算法取決于被轉(zhuǎn)換的對(duì)象。如果是一個(gè)Date
對(duì)象,則使用偏字符串算法。如果是其他類型的對(duì)象,就使用偏數(shù)值算法。
以上規(guī)則適用于所有的內(nèi)置 JavaScript 類型。
練習(xí)題
文章開(kāi)頭列舉的五個(gè)問(wèn)題,下面我們逐一揭曉答案。
console.log(Boolean({}))
:對(duì)象轉(zhuǎn)換成布爾值時(shí),所有對(duì)象都轉(zhuǎn)換為true
,所以打印true
。
console.log(Number([]))
:對(duì)象轉(zhuǎn)換成數(shù)值,首先使用偏數(shù)值算法把對(duì)象轉(zhuǎn)換為一個(gè)原始值,然后再把得到的原始值轉(zhuǎn)換為數(shù)值。偏數(shù)值算法會(huì)先嘗試valueOf()
,將toString()
作為備用。Array
類繼承了默認(rèn)的valueOf()
方法,所以不會(huì)返回原始值,因此最終會(huì)調(diào)用toString()
方法??諗?shù)組會(huì)被轉(zhuǎn)換成空字符串,而空字符串轉(zhuǎn)換成數(shù)值為 0,所以打印 0。
console.log(Number([6]))
:同樣,使用偏數(shù)值算法,最終會(huì)調(diào)用toString()
方法。因?yàn)閿?shù)組中只包含一個(gè)數(shù)值,所以該數(shù)值首先會(huì)被轉(zhuǎn)換成字符串 '6',再轉(zhuǎn)換回?cái)?shù)值 6,打印結(jié)果為 6。
console.log(([] + []).length)
:兩個(gè)數(shù)組相加,首先會(huì)將數(shù)組轉(zhuǎn)換為字符串,使用偏字符串算法,空數(shù)組會(huì)轉(zhuǎn)換為空字符串,空字符串相加還是空字符串,長(zhǎng)度為 0,打印結(jié)果為 0。
console.log(({} + {}).length)
:兩個(gè)對(duì)象相加,首先會(huì)將對(duì)象轉(zhuǎn)換成字符串,使用偏字符串算法,對(duì)象轉(zhuǎn)換成字符串后是'[object Object]'
,兩個(gè)'[object Object]'
拼接后的長(zhǎng)度是 30,打印結(jié)果為 30。
到此這篇關(guān)于淺析JavaScript對(duì)象轉(zhuǎn)換成原始值的文章就介紹到這了,更多相關(guān)JS對(duì)象轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Jackson中json格式的字符串與對(duì)象的互相轉(zhuǎn)換方式
- 利用python實(shí)現(xiàn)JSON文檔與Python對(duì)象互相轉(zhuǎn)換
- Java如何將String轉(zhuǎn)換成json對(duì)象或json數(shù)組
- springboot post接口接受json時(shí),轉(zhuǎn)換為對(duì)象時(shí),屬性都為null的解決
- 復(fù)雜JSON字符串轉(zhuǎn)換為Java嵌套對(duì)象的實(shí)現(xiàn)
- 使用jackson實(shí)現(xiàn)對(duì)象json之間的相互轉(zhuǎn)換(spring boot)
- JAVA中JSONObject對(duì)象和Map對(duì)象之間的相互轉(zhuǎn)換
相關(guān)文章
JavaScript使用二分查找算法在數(shù)組中查找數(shù)據(jù)的方法
這篇文章主要介紹了JavaScript使用二分查找算法在數(shù)組中查找數(shù)據(jù)的方法,較為詳細(xì)的分析了二分查找法的原理與javascript實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-04-04Dropzone.js實(shí)現(xiàn)文件拖拽上傳功能(附源碼下載)
dropzone.js是重量輕的JavaScript庫(kù),將HTML元素設(shè)置為一個(gè)降落區(qū),并通過(guò)Ajax文件被上傳到服務(wù)器。本文給大家詳細(xì)介紹Dropzone.js實(shí)現(xiàn)文件拖拽上傳功能,需要的朋友參考下吧2016-11-11JS實(shí)現(xiàn)圖文并茂的tab選項(xiàng)卡效果示例【附demo源碼下載】
這篇文章主要介紹了JS實(shí)現(xiàn)圖文并茂的tab選項(xiàng)卡效果,涉及javascript響應(yīng)鼠標(biāo)事件動(dòng)態(tài)修改頁(yè)面元素屬性的相關(guān)操作技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2016-09-09JavaScript實(shí)現(xiàn)拖動(dòng)對(duì)話框效果的實(shí)現(xiàn)代碼
這篇文章主要介紹了JavaScript實(shí)現(xiàn)拖動(dòng)對(duì)話框效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10js實(shí)現(xiàn)回放拖拽軌跡從過(guò)程上進(jìn)行分析
今天的記錄,記錄回放拖拽痕跡,先從過(guò)程上進(jìn)行分析,需要的朋友可以參考下2014-06-06JavaScript實(shí)現(xiàn)的簡(jiǎn)單冪函數(shù)實(shí)例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的簡(jiǎn)單冪函數(shù),實(shí)例分析了javascript實(shí)現(xiàn)冪運(yùn)算的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04詳解js實(shí)時(shí)獲取并顯示當(dāng)前時(shí)間的方法
這篇文章主要介紹了js實(shí)時(shí)獲取并顯示當(dāng)前時(shí)間的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05javascript的列表切換【實(shí)現(xiàn)代碼】
下面小編就為大家?guī)?lái)一篇javascript的列表切換【實(shí)現(xiàn)代碼】。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。2016-05-05JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持
雙向數(shù)據(jù)綁定的核心方法,主要是做數(shù)據(jù)劫持操作(監(jiān)控?cái)?shù)據(jù)變化),下面這篇文章主要給大家介紹了關(guān)于JavaScript defineProperty如何實(shí)現(xiàn)屬性劫持的相關(guān)資料,需要的朋友可以參考下2021-07-07