国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript類型轉(zhuǎn)換原理

lewif / 1806人閱讀

摘要:其實(shí)這三個(gè)函數(shù)不僅僅可以當(dāng)作構(gòu)造函數(shù),它們可以直接當(dāng)作普通的函數(shù)來(lái)使用,將任何類型的參數(shù)轉(zhuǎn)化成原始類型的值其實(shí)這三個(gè)函數(shù)用于類型轉(zhuǎn)換的時(shí)候,調(diào)用的就是內(nèi)部的方法這里解釋一下的過(guò)程執(zhí)行執(zhí)行內(nèi)部函數(shù)執(zhí)行因?yàn)椴皇窃碱愋停M(jìn)入下一步。

本文修改自本人以前寫(xiě)的文章。

從類型說(shuō)起

js只有7種類型:

原始類型(primitives types)

boolean

number

包括Infinity和NaN,你可以通過(guò)typeof Infinity;來(lái)驗(yàn)證

string

null

undefined

Symbol (ECMAScript 6 新定義,暫時(shí)用不上,這篇文章不討論)

Object 類型

js內(nèi)置了很多對(duì)象供你使用,MDN文檔列舉了所有ES標(biāo)準(zhǔn)定義的內(nèi)置對(duì)象。

js的自動(dòng)裝箱

雖然string是原始類型,但為什么我們好像可以調(diào)用“string的函數(shù)”呢?

var str = "I am str";
str.toUpperCase();  // "I AM STR"

原因是js標(biāo)準(zhǔn)庫(kù)給boolean、number、string分別提供了包裝類型:Boolean、Number、String。在需要的時(shí)候,原始類型會(huì)自動(dòng)轉(zhuǎn)換成相應(yīng)的包裝對(duì)象(這個(gè)過(guò)程叫自動(dòng)裝箱)。上例的toUpperCase就是String標(biāo)準(zhǔn)對(duì)象定義的一個(gè)函數(shù)。

自動(dòng)裝箱就是臨時(shí)創(chuàng)建一個(gè)包裝對(duì)象,將原始類型的值封裝起來(lái),以便調(diào)用包裝對(duì)象的函數(shù)。但是原來(lái)那個(gè)變量的值不會(huì)有任何變化!執(zhí)行完上面例子的代碼之后,str指向的依然是那個(gè)原始值:
typeof str;  // "string"

當(dāng)然,你可以將Boolean 、Number 、String 這三個(gè)函數(shù)當(dāng)作構(gòu)造函數(shù)來(lái)使用通過(guò)手動(dòng)new包裝類來(lái)裝箱(得到包裝對(duì)象):

var str_object = new String("I am str_object");  //  手動(dòng)裝箱
str_object.toUpperCase();  //  "I AM STR_OBJECT"
typeof str_object;  //  "object"
這三個(gè)函數(shù)除了能當(dāng)作構(gòu)造函數(shù),還能作為普通函數(shù)來(lái)調(diào)用(得到對(duì)應(yīng)的原始類型值)。在文章的后面,我們會(huì)將這三個(gè)函數(shù)當(dāng)作普通的函數(shù)使用,實(shí)現(xiàn)強(qiáng)制類型轉(zhuǎn)換。
兩個(gè)與類型轉(zhuǎn)換有關(guān)的函數(shù):valueOf()和toString()

valueOf()的語(yǔ)義是,返回這個(gè)對(duì)象邏輯上對(duì)應(yīng)的原始類型的值。比如說(shuō),String包裝對(duì)象的valueOf(),應(yīng)該返回這個(gè)對(duì)象所包裝的字符串。

toString()的語(yǔ)義是,返回這個(gè)對(duì)象的字符串表示。用一個(gè)字符串來(lái)描述這個(gè)對(duì)象的內(nèi)容。

valueOf()和toString()是定義在Object.prototype上的方法,也就是說(shuō),所有的對(duì)象都會(huì)繼承到這兩個(gè)方法。但是在Object.prototype上定義的這兩個(gè)方法往往不能滿足我們的需求(Object.prototype.valueOf()僅僅返回對(duì)象本身),因此js的許多內(nèi)置對(duì)象都重寫(xiě)了這兩個(gè)函數(shù),以實(shí)現(xiàn)更適合自身的功能需要(比如說(shuō),String.prototype.valueOf就覆蓋了在Object.prototype中定義的valueOf)。當(dāng)我們自定義對(duì)象的時(shí)候,最好也重寫(xiě)這個(gè)方法。重寫(xiě)這個(gè)方法時(shí)要遵循上面所說(shuō)的語(yǔ)義。

以下是部分內(nèi)置對(duì)象調(diào)用valueOf()的行為:

對(duì)象 返回值
Array 數(shù)組本身(對(duì)象類型)。
Boolean 布爾值(原始類型)。
Date 從 UTC 1970 年 1 月 1 日午夜開(kāi)始計(jì)算,到所封裝的日期所經(jīng)過(guò)的毫秒數(shù)(原始類型)。
Function 函數(shù)本身(對(duì)象類型)。
Number 數(shù)字值(原始類型)。
Object 對(duì)象本身(對(duì)象類型)。如果自定義對(duì)象沒(méi)有重寫(xiě)valueOf方法,就會(huì)使用它。
String 字符串值(原始類型)。

由上表可見(jiàn),valueOf()雖然期望返回原始類型的值,但是實(shí)際上有一些對(duì)象在邏輯上無(wú)法找到與之對(duì)應(yīng)的原始值,因此只能返回對(duì)象本身。

toString()則不一樣,因?yàn)?strong>不管什么對(duì)象,我們總有辦法“描述”它,因此js內(nèi)置對(duì)象的toString()總能返回一個(gè)原始string類型的值。

var d = new Date();
d.toString()
// "Fri Apr 21 2017 14:54:04 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)"

我們自己在重寫(xiě)toString()的時(shí)候也應(yīng)該返回合理的string。

valueOf()和toString()經(jīng)常會(huì)在類型轉(zhuǎn)換的時(shí)候被js內(nèi)部調(diào)用,比如說(shuō)我們后文會(huì)談到的ToPrimitive。在自定義對(duì)象上合理地覆蓋valueOf()和toString(),可以控制自定義對(duì)象的類型轉(zhuǎn)換。
js內(nèi)部用于實(shí)現(xiàn)類型轉(zhuǎn)換的4個(gè)函數(shù)

這4個(gè)方法實(shí)際上是ECMAScript定義的4個(gè)抽象的操作,它們?cè)趈s內(nèi)部使用,進(jìn)行類型轉(zhuǎn)換。我們js的使用者不能直接調(diào)用這些函數(shù),但是了解這些函數(shù)有利于我們理解js類型轉(zhuǎn)換的原理。

ToPrimitive ( input [ , PreferredType ] )

ToBoolean ( argument )

ToNumber ( argument )

ToString ( argument )

請(qǐng)區(qū)分這里的ToString()和上文談到的toString(),一個(gè)是js引擎內(nèi)部使用的函數(shù),另一個(gè)是定義在對(duì)象上的函數(shù)。
ToPrimitive ( input [ , PreferredType ] )

將input轉(zhuǎn)化成一個(gè)原始類型的值。PreferredType參數(shù)要么不傳入,要么是Number 或 String。如果PreferredType參數(shù)是Number,ToPrimitive這樣執(zhí)行:

如果input本身就是原始類型,直接返回input。

調(diào)用input.valueOf(),如果結(jié)果是原始類型,則返回這個(gè)結(jié)果。

調(diào)用input.toString(),如果結(jié)果是原始類型,則返回這個(gè)結(jié)果。

拋出TypeError異常。

以下是PreferredType不為Number時(shí)的執(zhí)行順序。

如果PreferredType參數(shù)是String,則交換上面這個(gè)過(guò)程的第2和第3步的順序,其他執(zhí)行過(guò)程相同。

如果PreferredType參數(shù)沒(méi)有傳入

如果input是內(nèi)置的Date類型,PreferredType 視為String

否則PreferredType 視為 Number

可以看出,ToPrimitive依賴于valueOf和toString的實(shí)現(xiàn)。
ToBoolean ( argument )
Argument Type Result
Undefined Return false
Null Return false
Boolean Return argument
Number 僅當(dāng)argument為 +0, -0, or NaN時(shí), return false; 否則一律 return true
String 僅當(dāng)argument是空字符串(長(zhǎng)度為0)時(shí), return false; 否則一律 return true
Symbol Return true
Object Return true

表格來(lái)自ECMAScript標(biāo)準(zhǔn)。
只需要記憶0, null, undefined, NaN, ""返回false就可以了,其他一律返回true。

ToNumber ( argument )
Argument Type Result
Undefined Return NaN
Null Return +0
Boolean 如果 argument 為 true, return 1. 如果 argument 為 false, return +0
Number 直接返回argument
String 將字符串中的內(nèi)容轉(zhuǎn)化為數(shù)字(比如"23"->23),如果轉(zhuǎn)化失敗則返回NaN(比如"23a"->NaN)
Symbol 拋出 TypeError 異常
Object primValue = ToPrimitive(argument, Number),再對(duì)primValue 使用 ToNumber(primValue)

由上表可見(jiàn)ToNumber的轉(zhuǎn)化并不總是成功,有時(shí)會(huì)轉(zhuǎn)化成NaN,有時(shí)則直接拋出異常。

ToString ( argument )
Argument Type Result
Undefined Return "undefined"
Null Return "null"
Boolean 如果 argument 為 true, return "true".如果 argument 為 false, return "false"
Number 用字符串來(lái)表示這個(gè)數(shù)字
String 直接返回 argument
Symbol 拋出 TypeError 異常
Object 先primValue = ToPrimitive(argument, hint String),再對(duì)primValue使用ToString(primValue)
隱式類型轉(zhuǎn)換(自動(dòng)類型轉(zhuǎn)換)

當(dāng)js期望得到某種類型的值,而實(shí)際在那里的值是其他的類型,就會(huì)發(fā)生隱式類型轉(zhuǎn)換。系統(tǒng)內(nèi)部會(huì)自動(dòng)調(diào)用我們前面說(shuō)ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument ),嘗試轉(zhuǎn)換成期望的數(shù)據(jù)類型。

例子1:

if ( !undefined
  && !null
  && !0
  && !NaN
  && !""
) {
  console.log("true");
} // true

例子1:因?yàn)樵趇f的括號(hào)中,js期望得到boolean的值,所以對(duì)括號(hào)中每一個(gè)值都使用ToBoolean ( argument ),將它們轉(zhuǎn)化成boolean。

例子2:

3 * { valueOf: function () { return 5 } };  //15

例子2:因?yàn)樵诔颂?hào)的兩端,js期望得到number類型的值,所以對(duì)右邊的那個(gè)對(duì)象使用ToNumber ( argument ),得到結(jié)果5,再與乘號(hào)左邊的3相乘。

例子3:

> function returnObject() { return {} }
> 3 * { valueOf: function () { return {} }, toString: function () { return {} } }
// TypeError: Cannot convert object to primitive value

例子3:調(diào)用ToNumber ( argument )的過(guò)程中,調(diào)用了ToPrimitive ( input , Number ),因?yàn)樵赥oPrimitive中valueOf和toString都沒(méi)有返回原始類型,所以拋出異常。

符號(hào)"+"是一個(gè)比較棘手的一個(gè)符號(hào),因?yàn)樗瓤梢员硎尽八銛?shù)加法”,也可以表示“字符串拼接”。
簡(jiǎn)單理解版本:只要"+"兩端的任意一個(gè)操作數(shù)是字符串,那么這個(gè)"+"就表示字符串拼接,否則表示算數(shù)加法。

12+3
// 15
12+"3"
// "123"

原理理解版本:根據(jù)ECMAScript的定義,對(duì)"+"運(yùn)算的求值按照以下過(guò)程:

令lval = 符號(hào)左邊的值,rval = 符號(hào)右邊的值

令lprim = ToPrimitive(lval),rprim = ToPrimitive(rval)

如果lprim和rprim中有任意一個(gè)為string類型,將ToString(lprim)和ToString(rprim)的結(jié)果做字符串拼接

否則,將ToNumber(lprim)和ToNumber(rprim)的結(jié)果做算數(shù)加法

根據(jù)這個(gè)原理可以解釋

[]+[]
//  ""
// 提示:ToPrimitive([])返回空字符串

[] + {}
//  "[object Object]"
//  提示:ToPrimitive({})返回"[object Object]"

123 + { toString: function () { return "def" } }
//  "123def"
//  提示:ToPrimitive(加號(hào)右邊的對(duì)象)返回"def"

{} + []
//  0
// 結(jié)果不符合我們的預(yù)期:"[object Object]"
// 提示:在Chrome中,符號(hào)左邊的{}被解釋成了一個(gè)語(yǔ)句塊,而不是一個(gè)對(duì)象
// 注意在別的執(zhí)行引擎上可能會(huì)將{}解釋成對(duì)象
//  這一行等價(jià)于"+[]"
// "+anyValue"等價(jià)于Number(anyValue)

({}) + []
//  "[object Object]"
// 加上括號(hào)以后,{}被解釋成了一個(gè)對(duì)象,結(jié)果符合我們的預(yù)期了
"<"、">"的情況與"+"類似,但是處理方式與"+"有些不同。如果好奇請(qǐng)自行查閱文檔。
顯式類型轉(zhuǎn)換(強(qiáng)制類型轉(zhuǎn)換)

程序員顯式調(diào)用Boolean(value)、Number(value)、String(value)完成的類型轉(zhuǎn)換,叫做顯示類型轉(zhuǎn)換。
我們?cè)谖恼碌那懊嬲f(shuō)過(guò)new Boolean(value)、new Number(value)、new String(value)傳入各自對(duì)應(yīng)的原始類型的值,可以實(shí)現(xiàn)“裝箱”——將原始類型封裝成一個(gè)對(duì)象。其實(shí)這三個(gè)函數(shù)不僅僅可以當(dāng)作構(gòu)造函數(shù),它們可以直接當(dāng)作普通的函數(shù)來(lái)使用,將任何類型的參數(shù)轉(zhuǎn)化成原始類型的值:

Boolean("sdfsd");  //  true
Number("23");  //  23
String({a:24});  //  "[object Object]"

其實(shí)這三個(gè)函數(shù)用于類型轉(zhuǎn)換的時(shí)候,調(diào)用的就是js內(nèi)部的ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument )方法!

這里解釋一下String({a:24}); // "[object Object]"的過(guò)程:

執(zhí)行String({a:24})

執(zhí)行js內(nèi)部函數(shù)ToString ( {a:24} )

執(zhí)行primValue = ToPrimitive({a:24}, hint String)

因?yàn)閧a:24}不是原始類型,進(jìn)入下一步。

在ToPrimitive內(nèi)調(diào)用({a:24}).toString(),返回了原始值"[object Object]",因此直接返回這個(gè)字符串,ToPrimitive后面的步驟不用進(jìn)行下去了。

primValue被賦值為T(mén)oPrimitive的返回值:"[object Object]"

執(zhí)行js內(nèi)部函數(shù)ToString ( "[object Object]" ),返回"[object Object]"

返回"[object Object]"

返回"[object Object]"

返回"[object Object]"

為了防止出現(xiàn)意料之外的結(jié)果,最好在不確定的地方使用顯式類型轉(zhuǎn)換

參考文章:
ECMAScript類型轉(zhuǎn)換規(guī)范
Object to primitive conversion
What is {} + {} in JavaScript?
JavaScript quirk 1: implicit conversion of values
Object.prototype.toString()的原理 - ECMAScript
改變Object.prototype.toString.call(myClass)的輸出
比較操作符的類型轉(zhuǎn)換

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/97376.html

相關(guān)文章

  • JavaScript 類型轉(zhuǎn)換深度學(xué)習(xí)

    摘要:當(dāng)一個(gè)值為字符串,另一個(gè)值為非字符串,則后者轉(zhuǎn)為字符串。文章出自的個(gè)人博客 showImg(https://segmentfault.com/img/bVEWkS?w=3376&h=1312); JavaScript 是一門(mén)弱類型語(yǔ)言,剛接觸的時(shí)候感覺(jué)方便快捷(不需要聲明變量類型了耶!),接觸久了會(huì)發(fā)現(xiàn)它帶來(lái)的麻煩有的時(shí)候不在預(yù)期之內(nèi) 呵呵一笑,哪有這么夸張,可能有人看過(guò)這樣一段代碼 ...

    microcosm1994 評(píng)論0 收藏0
  • JavaScript是如何工作的:深入類和繼承內(nèi)部原理+Babel和 TypeScript 之間轉(zhuǎn)換

    摘要:下面是用實(shí)現(xiàn)轉(zhuǎn)成抽象語(yǔ)法樹(shù)如下還支持繼承以下是轉(zhuǎn)換結(jié)果最終的結(jié)果還是代碼,其中包含庫(kù)中的一些函數(shù)。可以使用新的易于使用的類定義,但是它仍然會(huì)創(chuàng)建構(gòu)造函數(shù)和分配原型。 這是專門(mén)探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 15 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過(guò)了前面的章節(jié),可以在這里找到它們: JavaScript 是...

    PrototypeZ 評(píng)論0 收藏0
  • JavaScript 工作原理之十五-類和繼承及 Babel 和 TypeScript 代碼轉(zhuǎn)換探秘

    摘要:使用新的易用的類定義,歸根結(jié)底也是要?jiǎng)?chuàng)建構(gòu)造函數(shù)和修改原型。首先,它把構(gòu)造函數(shù)當(dāng)成單獨(dú)的函數(shù)且包含類屬性集。該節(jié)點(diǎn)還儲(chǔ)存了指向父類的指針引用,該父類也并儲(chǔ)存了構(gòu)造函數(shù),屬性集和及父類引用,依次類推。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第...

    GeekGhc 評(píng)論0 收藏0
  • JavaScript 工作原理之十五-類和繼承及 Babel 和 TypeScript 代碼轉(zhuǎn)換探秘

    摘要:使用新的易用的類定義,歸根結(jié)底也是要?jiǎng)?chuàng)建構(gòu)造函數(shù)和修改原型。首先,它把構(gòu)造函數(shù)當(dāng)成單獨(dú)的函數(shù)且包含類屬性集。該節(jié)點(diǎn)還儲(chǔ)存了指向父類的指針引用,該父類也并儲(chǔ)存了構(gòu)造函數(shù),屬性集和及父類引用,依次類推。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第...

    BigNerdCoding 評(píng)論0 收藏0
  • [譯文] JavaScript工作原理:V8引擎內(nèi)部+5條優(yōu)化代碼的竅門(mén)

    摘要:本文將會(huì)深入分析的引擎的內(nèi)部實(shí)現(xiàn)。該引擎使用在谷歌瀏覽器內(nèi)部。同其他現(xiàn)代引擎如或所做的一樣,通過(guò)實(shí)現(xiàn)即時(shí)編譯器在執(zhí)行時(shí)將代碼編譯成機(jī)器代碼。這可使正常執(zhí)行期間只發(fā)生相當(dāng)短的暫停。 原文 How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code 幾周前我們開(kāi)始了一個(gè)系列博文旨在深入...

    dreamans 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

lewif

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<