成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解JavaScript的類型轉(zhuǎn)換

W4n9Hu1 / 2226人閱讀

摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結(jié)果。

前言
JavaScript作為一門弱類型語言,我們?cè)诿刻斓木帉懘a過程中,無時(shí)無刻不在應(yīng)用著值類型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過閱讀你不知道的JavaScript中篇,對(duì)js的值類型轉(zhuǎn)換進(jìn)行了更加深入的學(xué)習(xí),在此分享給大家參考學(xué)習(xí)。
概念

將值從一種類型轉(zhuǎn)換為另一種類型通常稱為類型轉(zhuǎn)換,主要發(fā)生在靜態(tài)語言的編譯階段;強(qiáng)制類型轉(zhuǎn)換則發(fā)生在動(dòng)態(tài)語言的運(yùn)行階段;JavaScript作為一門典型的動(dòng)態(tài)弱類型語言自然而然采用的是強(qiáng)制類型轉(zhuǎn)換(即隱式強(qiáng)制類型轉(zhuǎn)換和顯式強(qiáng)制類型轉(zhuǎn)換);在js的強(qiáng)制類型轉(zhuǎn)換總是返回標(biāo)量基本類型值,如字符串、布爾、數(shù)字,不會(huì)返回對(duì)象和函數(shù)

var a = 42;
var b = a + "";//隱式強(qiáng)制類型轉(zhuǎn)換
var c = String(a);//顯式強(qiáng)制類型轉(zhuǎn)化
前情提要

在閱讀后面的內(nèi)容之前,我們首先要明白下面幾個(gè)概念,以方便對(duì)后續(xù)內(nèi)容的理解

封裝對(duì)象 :eg:var a = new String("abc"),a被叫做封裝了基本類型的封裝對(duì)象,還原一個(gè)封裝對(duì)象的值,可以調(diào)用valueOf方法;

基本類型的幾乎所有方法并非來自本身,而是來自于封裝對(duì)象的原型對(duì)象,例如下面例子

const a = 1.2;
console.log(a.toFixed(0));//1

基本類型數(shù)字并不存在toFixed方法,只是在訪問該方法時(shí)候,js自動(dòng)封裝基本類型為對(duì)應(yīng)的封裝對(duì)象,再去訪問該封裝對(duì)象的原型上對(duì)應(yīng)的方法,等同于下面例子

const a = 1.2;
console.log(new Number(a).__proto__.toFixed());//0

ToPrimitive抽象操作:該操作主要是將對(duì)象類型轉(zhuǎn)換為基本類型,首先檢查某個(gè)對(duì)象是否有valueOf屬性,如果有則返回該對(duì)象的valueOf的值,否則調(diào)用該對(duì)象的toString屬性并返回值(如果valueOf返回的不是基本類型則調(diào)用toString方法,例如數(shù)組的valueOf返回的還是數(shù)組,所有ToPrimitive會(huì)默認(rèn)調(diào)用toString方法);

抽象值操作 ToString負(fù)責(zé)處理非字符串到字符串的強(qiáng)制類型轉(zhuǎn)換,規(guī)則如下:

1.null轉(zhuǎn)換為"null",undefined轉(zhuǎn)換為"undefined",其他基本類型都調(diào)用基本類型的包裝對(duì)象屬性toString()并返回值。

const a = 123;
const _a = new Number(123);
console.log(String(a), _a.toString());//"123" "123"
const b = true;
const _b = new Boolean(true);
console.log(String(b), _b.toString());//"true" "true"

2.數(shù)字的字符串化遵循通用規(guī)則,但是極小極大數(shù)字使用指數(shù)形式

const a = 1.07*1000*1000*1000*1000*1000*1000*1000;
console.log(String(a));//"1.07e+21"

3.對(duì)于普通對(duì)象來說,除非自行定義,否則toString()返回Object.prototype.toString()的值,其他對(duì)象有自己的toString()方法則調(diào)用自己的該方法

const b = {};
console.log(String(b));//[object object]

4.數(shù)組的默認(rèn)toString()方法進(jìn)行了重新定義,將所有單元字符串化以后再用‘,’連接起來

const a = [1, 2, 3];
console.log(String(a));//"1,2,3"

5.JSON字符串化

5-1.JSON字符串化和toString的效果基本相同,只不過序列化的結(jié)果總是字符串

5-2.JSON對(duì)于不安全的值(undefined,function(){},symbol)直接忽略,數(shù)組中則以null填充

5-3.對(duì)象循環(huán)引用直接報(bào)錯(cuò),正則表達(dá)式序列化為{}

ToNumber負(fù)責(zé)處理非數(shù)字到數(shù)字的強(qiáng)制類型轉(zhuǎn)換,規(guī)則如下:

1.true轉(zhuǎn)換為1,false轉(zhuǎn)換為0,undefined轉(zhuǎn)換為NaN,null轉(zhuǎn)換為0

console.log(Number(null));//0
console.log(Number(undefined));//NaN
console.log(Number(true));//1
console.log(Number(false));//0

2.對(duì)字符串的處理遵循數(shù)字常量的相關(guān)規(guī)定/語法,處理失敗時(shí)返回NaN

console.log(Number("123"));//123
console.log(Number("0b111"));//7
console.log(Number("0o123"));//83
console.log(Number("0x123"));//291
console.log(Number("123a"));//NaN
console.log(Number("a123"));//NaN

3.對(duì)象(包括數(shù)組)會(huì)首先按照ToPrimitive抽象操作被轉(zhuǎn)換為相應(yīng)的基本類型值,再按照前兩條規(guī)則處理;如果某個(gè)對(duì)象即不存在valueOf方法也不存在toString方法,則會(huì)產(chǎn)生TypeError錯(cuò)誤(例如Object.create(null)不存在以上兩種方法)

const arr = [1, 2, 3];
console.log(Number(arr));//NaN
console.log(Number(arr.toString()));//NaN


const num = new Number(123);
console.log(Number(num));//123
console.log(Number(num.valueOf()));//123

const bool = new Boolean(true);
console.log(bool.valueOf());//true
console.log(Number(bool));//1
console.log(Number(bool.valueOf()));//1

const obj1 = {
  toString:()=>"21"
}

const obj2 = {
  valueOf:()=>"42",
  toString:()=>"21"
}

const obj3 = {
  a:1
}
console.log(Number(obj1));//21
console.log(Number(obj2));//42
console.log(obj3.toString());//[object Object]
console.log(Number(obj3));//NaN


const obj = Object.create(null);
console.log(Number(obj));//TypeError

上述obj1,obj2分別調(diào)用toString和valueOf方法,obj3調(diào)用原型上的toString()方法

ToBoolean負(fù)責(zé)處理非布爾值到布爾值的強(qiáng)制類型轉(zhuǎn)換,規(guī)則如下:

可以被轉(zhuǎn)換為false的值(undefined,null,false, +0、-0和NaN,"")

除條件1的其他都被轉(zhuǎn)換為true(切記:封裝對(duì)象均被轉(zhuǎn)為true)

顯式強(qiáng)制類型轉(zhuǎn)換 字符串和數(shù)字之間的顯式轉(zhuǎn)換

通過window下面的內(nèi)建函數(shù)String()和Number()來實(shí)現(xiàn)(遵循上述抽象值操作)

toString()的顯式轉(zhuǎn)換過程為先隱式的將基本類型轉(zhuǎn)為封裝對(duì)象,再對(duì)該對(duì)象調(diào)用toString方法

一元運(yùn)算符+和-來轉(zhuǎn)換,例如+a顯式的將c轉(zhuǎn)換為數(shù)字

位運(yùn)算NOT的顯式轉(zhuǎn)換

第一步:位運(yùn)算NOT將非數(shù)字和數(shù)字轉(zhuǎn)換為32位數(shù)字

第二步:將該數(shù)字求負(fù)值并減1

indexOf優(yōu)雅寫法(返回-1的這種現(xiàn)象稱為抽象滲漏,即代碼暴露了底層的實(shí)現(xiàn)細(xì)節(jié))

截除數(shù)字值得小數(shù)部分比Math.floor()更加靠譜(Math.floor對(duì)負(fù)數(shù)的截取和~不同)

const a = true;
console.log(~a === -Number(a)-1)//true

//indexOf優(yōu)雅寫法
const b = "abc";
if(~b.indexOf("d")){
  console.log("存在d")
}else{
  console.log("不存在d")
}

//數(shù)字的小數(shù)部分截除
const d = 3.14;
const e = -3.14;
console.log(Math.floor(d), ~~d);//3 3
console.log(Math.floor(e), ~~e);//-4 -3
顯式解析數(shù)字字符串

解析字符串中的數(shù)字和強(qiáng)制將字符串轉(zhuǎn)換為數(shù)字返回的結(jié)果都是數(shù)字;但是解析允許字符串中含有非數(shù)字,解析按從左到右的順序,如果遇到非數(shù)字就停止解析;而轉(zhuǎn)換不允許出現(xiàn)非數(shù)字字符,否則會(huì)失敗并返回NaN。

parseInt()和parseFloat分別用來解析整數(shù)和浮點(diǎn)數(shù),傳入的值必須是字符串,如果是非字符串會(huì)被隱式轉(zhuǎn)換為字符串再解析

注意點(diǎn):es5之前parseInt()遇到0開頭的字符串?dāng)?shù)字(比如時(shí)間hour="09")會(huì)被按照八進(jìn)制處理,需要在第二個(gè)參數(shù)傳入10解決,es5之后0開頭的能能字符串化為八進(jìn)制的按八進(jìn)制解析不能的按10進(jìn)制解析;

//現(xiàn)將a轉(zhuǎn)為字符串"1,2,3"
const a = [1, 2, 3];
console.log(parseInt(a));//1
console.log(parseFloat(a));//1

//現(xiàn)將true轉(zhuǎn)為字符串"true"
console.log(parseInt(true));//NaN
console.log(parseFloat(true));//NaN

//現(xiàn)將3.14轉(zhuǎn)為字符串"3.14"
console.log(parseInt(3.14));//3
console.log(parseFloat(3.14));//3.14

console.log(String(new Date()));//"Wed Jun 12 2019 21:23:59 GMT+0800"
console.log(parseInt(new Date()));//NaN
console.log(parseFloat(new Date()));//NaN

//關(guān)于es6之前八進(jìn)制寫法的解析
console.log(parseInt(09));//9
console.log(parseFloat(09));//9
console.log(parseInt(010));//8
console.log(parseFloat(010));//8

parseInt()的一些奇怪現(xiàn)象

parseInt(1/0, 19);//18
//其實(shí)相當(dāng)于parseInt(Infinity, 19);其中Infinity的I在十九進(jìn)制數(shù)中為18

parseInt(0.000008);//0
//字符串化為0.00008后進(jìn)行解析

parseInt(0.0000008);//8
//字符化為8e-7后進(jìn)行解析(詳見抽象ToNumber)

parseInt(0x10);//16
String(0x10);//16
parseInt(0b10);//2
String(0b10);//2
parseInt(0o10);//8
String(0o10);//8
parseInt(012);//10
String(012);//10
//其實(shí)現(xiàn)在es6規(guī)定了二進(jìn)制、八進(jìn)制和十六進(jìn)制的表示法
//以上三個(gè)字符串均先被String()化為字符串再進(jìn)行解析
顯式轉(zhuǎn)換為布爾值

通過全局方法Boolean()強(qiáng)制轉(zhuǎn)換,遵循抽象值操作中的ToBolean

!!進(jìn)行強(qiáng)制轉(zhuǎn)換,遵循抽象值操作中的ToBolean

隱式強(qiáng)制類型轉(zhuǎn)換 隱式強(qiáng)制類型轉(zhuǎn)換為字符串

一元運(yùn)算符加號(hào)(+)首先把非基本類型通過ToPrimitive抽象操作轉(zhuǎn)換為基本類型,如果加號(hào)中的兩項(xiàng)有一項(xiàng)是字符串,另一項(xiàng)則進(jìn)行ToString操作,進(jìn)行字符串拼接,如果是布爾值加數(shù)字,則對(duì)布爾進(jìn)行ToNumber操作再求和

const a = 1;
console.log(a + true);//2
//等同于
console.log(a + Number(true));//2

console.log([1, 2] + [1, 2]); //1,21,2
//等同于
console.log([1, 2].toString() + [1, 2].toString()); //1,21,2


console.log({} + []);//[object Object]
console.log([] + {});//[object Object]
console.log({}.toString());//[object Object]
console.log([].toString());//""

隱式強(qiáng)制類型轉(zhuǎn)換為數(shù)字,通過一元運(yùn)算符-、/、*轉(zhuǎn)換,遵循ToNumber的抽象值操作規(guī)則

console.log("3.14" - "0");//3.14
console.log([2] - [1]);//1
//等同于
console.log([2].toString() - [1].toString());//1
隱式強(qiáng)制類型轉(zhuǎn)換為布爾值

以下均遵循ToBolean抽象值操作

if(..)語句中的條件判斷表達(dá)式

for(..;..;..)語句的第二個(gè)條件判斷表達(dá)式

while(..)和do..while(..)的條件判斷表達(dá)式

?:中的條件判斷表達(dá)式

邏輯運(yùn)算符||和&&左邊的操作數(shù)(a||b等同于a?a:b,a&&b等同于a?b:a)

符號(hào)的強(qiáng)制類型轉(zhuǎn)換

Symbol不能被強(qiáng)制轉(zhuǎn)換為數(shù)字(顯式和隱式都會(huì)產(chǎn)生錯(cuò)誤),但可以被強(qiáng)制轉(zhuǎn)換為布爾值(顯式和隱式結(jié)果都為true)

寬松相等和嚴(yán)格相等
==允許在相等的比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換,===則不能允許,并不是==檢查值是否相等,===檢查值和類型是否相等
嚴(yán)格相等的兩種特殊情況

NaN不等于NaN;

+0等于-0;

寬松相等之間的隱式轉(zhuǎn)換

1.字符串和數(shù)字之間的相等比較

(1) 如果 Type(x) 是數(shù)字,Type(y) 是字符串,則返回 x == ToNumber(y) 的結(jié)果。

(2) 如果 Type(x) 是字符串,Type(y) 是數(shù)字,則返回 ToNumber(x) == y 的結(jié)果。

const [a, b] = ["42", 42];
console.log(a == b);//true
//等同于
console.log(Number(a) === b);//true

console.log(b == a);//true
//等同于
console.log(Number(a) === b);//true

2.其他類型和布爾類型之間的比較

(1) 如果 Type(x) 是布爾類型,則返回 ToNumber(x) == y 的結(jié)果。

(2) 如果 Type(y) 是布爾類型,則返回 x == ToNumber(y) 的結(jié)果。

const [a, b] = [true, 1];
console.log(a == b);//true
//等同于
console.log(Number(a) === b);//true

console.log(b == a);//true
//等同于
console.log(b === Number(a));//true

const [c, d] = [false, 0];
console.log(c == d);//true
//等同于
console.log(Number(c) === d);//true

console.log(d == c);//true
//等同于
console.log(d === Number(c));//true

console.log("true" == true);//false
//等同于
console.log("true" === 1);//false

3.null和undefined之間的相等比較,規(guī)范規(guī)定null和undefined寬松相等

console.log(null == undefined);//true

4.對(duì)象和非對(duì)象之間(包括數(shù)字、字符串;其中布爾遵循其他類型和布爾類型之間的比較)的相等比較

如果Type(x)是字符串或者數(shù)字,Type(y)是對(duì)象,則返回x == ToPromitive(y)的結(jié)果;

如果Type(x)是對(duì)象,Type(y)是字符串或者數(shù)字,則返回ToPromitive(x) == y的結(jié)果;

const [x, y] = [["42"], 42];
console.log(x == y);//true
//等同于
console.log(x.toString() == y);//true

const x1 = "abc";
const y1 = new String(x1);
console.log(x1 == y1);//true
//等同于
console.log(x1 == y1.valueOf());//true

5.一些特殊情況

const [x, y, z] = [undefined, null, NaN];
console.log(x == Object(x) );//false
console.log(y == Object(y) );//false
//等同于
console.log(x == Object() );//false
console.log(y == Object() );//false

console.log(z == Object(z) );//false
//等同于
console.log(z == new Number(z) );//false

//由于Objec(undefined)和Object(null)沒有對(duì)應(yīng)的封裝對(duì)象,所以不能夠被封裝,
//Objec(undefined)和Object(null)均返回常規(guī)對(duì)象,等同于Object()
//Object(NaN)等同于new Number(NaN), NaN==NaN返回false

6.假值的相等比較

null == "0";//false
null == false;//false
null == "";//false
null == 0;//false

undefined == "0";//false
undefined == false;//false
undefined == "";//false
undefined == 0;//false

null == undefined;//false
//null只會(huì)與undefined寬松相等


"0" == false;//true ---特殊
"0" == NaN;//false
"0" == 0;//true
"0" == "";//false

false == NaN;//false
false == 0;//true
false == "";//true ---特殊
false == [];//true ---特殊
false == {};//false

"" == NaN;//false
"" == 0;//true ---特殊
"" == [];//true
"" == {};//false

0 == NaN;//false
0 == [];//true ---特殊
0 == {};//false
0 == "
";//true ---特殊

7.抽象關(guān)系比較>、<、≥、≤

如果雙方都是字符串,則按照字母順序進(jìn)行比較

如果雙方是其他情況首先調(diào)用ToPrimitive轉(zhuǎn)換為基本類型

如果轉(zhuǎn)換的結(jié)果出現(xiàn)非字符串,則根據(jù)ToNumber規(guī)則強(qiáng)制轉(zhuǎn)換為數(shù)字進(jìn)行比較

const a = [42];
const b = ["43"];

console.log(a < b);//true
//ToPrimite轉(zhuǎn)換
console.log(a.toString() < b.toString());
//按照字母順序判斷
console.log("42" < "43");//true

const a1 = ["42"];
const a2 = ["043"];
console.log(a1 > a2);//true

關(guān)于對(duì)象關(guān)系比較的奇怪現(xiàn)象

var a = { b: 42 };
var b = { b: 43 };
a < b;  // false
a == b; // false
a > b;  // false
a <= b; // true
a >= b; // true

按理兩邊對(duì)象都會(huì)進(jìn)行ToPrimitive抽象值操作,轉(zhuǎn)換為[object object]應(yīng)該相等,但是結(jié)果卻并非如此,具體原理參考ECMAScript5規(guī)范11.8節(jié)

8.原理鞏固

如何讓a==2&&a==3?

const a = new Number("something");
let i = 2;
Number.prototype.valueOf = ()=>i++;
console.log(a == 2 && a == 3);//true

[] == ![]為何為true?

![]首先轉(zhuǎn)換為false, [] == false符合上面的假值相等

"" == [null]為何為true?

[null]進(jìn)行ToPrimitive強(qiáng)制類型轉(zhuǎn)換為""

9.安全運(yùn)用隱式強(qiáng)制類型轉(zhuǎn)化

如果兩邊的值中有true或者false,千萬不要使用==

如果兩邊的值中有[]、""或者0,盡量不要使用==

最安全的方式可以通過typeof判斷

最后慣例,歡迎大家star我們的人人貸大前端團(tuán)隊(duì)博客以及個(gè)人github,所有的文章還會(huì)同步更新到知乎專欄 和 掘金賬號(hào),我們每周都會(huì)分享幾篇高質(zhì)量的大前端技術(shù)文章。如果你喜歡這篇文章,希望能動(dòng)動(dòng)小手給個(gè)贊。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/54109.html

相關(guān)文章

  • 深入理解JavaScript類型轉(zhuǎn)換

    摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們?cè)诿刻斓木帉懘a過程中,無時(shí)無刻不在應(yīng)用著值類型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過閱讀你...

    niuxiaowei111 評(píng)論0 收藏0
  • 深入理解JavaScript類型轉(zhuǎn)換

    摘要:等同于等同于其他類型和布爾類型之間的比較如果是布爾類型,則返回的結(jié)果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作為一門弱類型語言,我們?cè)诿刻斓木帉懘a過程中,無時(shí)無刻不在應(yīng)用著值類型轉(zhuǎn)換,但是很多時(shí)候我們只是在單純的寫,并不曾停下腳步去探尋過值類型轉(zhuǎn)換的內(nèi)部轉(zhuǎn)換規(guī)則,最近通過閱讀你...

    shuibo 評(píng)論0 收藏0
  • 精讀《你不知道javascript(中卷)》

    摘要:強(qiáng)制類型轉(zhuǎn)換本章介紹了的數(shù)據(jù)類型之間的轉(zhuǎn)換即強(qiáng)制類型轉(zhuǎn)換包括顯式和隱式。強(qiáng)制類型轉(zhuǎn)換常常為人詬病但實(shí)際上很多時(shí)候它們是非常有用的。隱式強(qiáng)制類型轉(zhuǎn)換則沒有那么明顯是其他操作的副作用。在處理強(qiáng)制類型轉(zhuǎn)換的時(shí)候要十分小心尤其是隱式強(qiáng)制類型轉(zhuǎn)換。 前言 《你不知道的 javascript》是一個(gè)前端學(xué)習(xí)必讀的系列,讓不求甚解的JavaScript開發(fā)者迎難而上,深入語言內(nèi)部,弄清楚JavaSc...

    李世贊 評(píng)論0 收藏0
  • 從 ++[[]][+[]]+[+[]]==10? 深入淺出弱類型 JS 隱式轉(zhuǎn)換

    摘要:與此相對(duì),強(qiáng)類型語言的類型之間不一定有隱式轉(zhuǎn)換。三為什么是弱類型弱類型相對(duì)于強(qiáng)類型來說類型檢查更不嚴(yán)格,比如說允許變量類型的隱式轉(zhuǎn)換,允許強(qiáng)制類型轉(zhuǎn)換等等。在中,加性運(yùn)算符有大量的特殊行為。 從++[[]][+[]]+[+[]]==10?深入淺出弱類型JS的隱式轉(zhuǎn)換 本文純屬原創(chuàng)? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉(zhuǎn)載! 原文收錄在【我的GitHub博客】,覺得本文寫的不算爛的...

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

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

0條評(píng)論

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