成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JavaScript 強(qiáng)制類型轉(zhuǎn)換

OnlyLing / 880人閱讀

摘要:強(qiáng)制類型轉(zhuǎn)換作為程序員,你一定獲取過當(dāng)前系統(tǒng)的時(shí)間戳。比如對(duì)于變量而言,此次強(qiáng)制類型轉(zhuǎn)換是隱式的。然而則是非常典型的顯式強(qiáng)制類型轉(zhuǎn)換。隱式強(qiáng)制類型轉(zhuǎn)換大部分被詬病的強(qiáng)制類型轉(zhuǎn)換都是隱式強(qiáng)制類型轉(zhuǎn)換。

JavaScript 強(qiáng)制類型轉(zhuǎn)換

作為 JavaScript 程序員,你一定獲取過當(dāng)前系統(tǒng)的時(shí)間戳。在 ES5 引入 Date.now() 靜態(tài)方法之前,下面這段代碼你一定不會(huì)陌生:

var timestamp = +new Date(); // timestamp 就是當(dāng)前的系統(tǒng)時(shí)間戳,單位是 ms

你肯定聽說過 JavaScript 的強(qiáng)制類型轉(zhuǎn)換,你能指出這段代碼里哪里用到了強(qiáng)制類型轉(zhuǎn)換嗎?

幾乎所有 JavaScript 程序員都接觸過強(qiáng)制類型轉(zhuǎn)換 —— 不論是有意的還是無意的。強(qiáng)制類型轉(zhuǎn)換導(dǎo)致了很多隱蔽的 BUG,但是強(qiáng)制類型轉(zhuǎn)換同時(shí)也是一種非常有用的技術(shù),我們不應(yīng)該因噎廢食。

在本文中我們來詳細(xì)探討一下 JavaScript 的強(qiáng)制類型轉(zhuǎn)換,以便我們可以在避免踩坑的情況下最大化利用強(qiáng)制類型轉(zhuǎn)換的便捷。

類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換

類型轉(zhuǎn)換發(fā)生在靜態(tài)類型語言的編譯階段,而強(qiáng)制類型轉(zhuǎn)換發(fā)生在動(dòng)態(tài)類型語言的運(yùn)行時(shí)(runtime),因此在 JavaScript 中只有強(qiáng)制類型轉(zhuǎn)換。

強(qiáng)制類型轉(zhuǎn)換一般還可分為 隱式強(qiáng)制類型轉(zhuǎn)換(implicit coercion和 _顯式強(qiáng)制類型轉(zhuǎn)換(explicit coercion)_。

從代碼中可以看出轉(zhuǎn)換操作是隱式的還是顯式的,顯式強(qiáng)制類型轉(zhuǎn)換很容易就能看出來,而隱式強(qiáng)制類型轉(zhuǎn)換可能就沒有這么明顯了。

比如:

var a = 21;

var b = a + "";

var c = String(a);

對(duì)于變量 b 而言,此次強(qiáng)制類型轉(zhuǎn)換是隱式的。+ 操作符在其中一個(gè)操作數(shù)是字符串時(shí)進(jìn)行的是字符串拼接操作,因此數(shù)字 21 會(huì)被轉(zhuǎn)換為相應(yīng)的字符串 "21"

然而 String(21) 則是非常典型的顯式強(qiáng)制類型轉(zhuǎn)換。

這兩種強(qiáng)制轉(zhuǎn)換類型的操作都是將數(shù)字轉(zhuǎn)換為字符串。

不過“顯式”還是“隱式”都是相對(duì)而言的。比如如果你知道 a + "" 是怎么回事,那么對(duì)你來說這可能就是“顯式”的。反之,如果你不知道 String(a) 可以用來字符串強(qiáng)制類型轉(zhuǎn)換,那么它對(duì)你來說可能就是“隱式”的。

抽象值操作

在介紹強(qiáng)制類型轉(zhuǎn)換之前,我們需要先了解一下字符串、數(shù)字和布爾值之間類型轉(zhuǎn)換的基本規(guī)則。在 ES5 規(guī)范中定義了一些“抽象操作”和轉(zhuǎn)換規(guī)則,在這我們介紹一下 ToPrimitive、ToString、ToNumberToBoolean。注意,這些操作僅供引擎內(nèi)部使用,和平時(shí) JavaScript 代碼中的 .toString() 等操作不一樣。

ToPrimitive

你可以將 ToPrimitive 操作看作是一個(gè)函數(shù),它接受一個(gè) input 參數(shù)和一個(gè)可選的 PreferredType 參數(shù)。ToPrimitive 抽象操作會(huì)將 input 參數(shù)轉(zhuǎn)換成一個(gè)原始值。如果一個(gè)對(duì)象可以轉(zhuǎn)換成不止一種原始值,可以使用 PreferredType 指定抽象操作的返回類型。

根據(jù)不同的輸入類型,ToPrimitive 的轉(zhuǎn)換操作如下:

輸入類型 操作 / 返回值
Undefined 自身(無轉(zhuǎn)換操作)
Null 自身(無轉(zhuǎn)換操作)
Boolean 自身(無轉(zhuǎn)換操作)
Number 自身(無轉(zhuǎn)換操作)
String 自身(無轉(zhuǎn)換操作)
Object 返回 Objectdefault value。Objectdefault value 通過在該對(duì)象上傳遞 PreferredType 參數(shù)給內(nèi)部操作 [[DefaultValue]](hint) 獲得。[[DefaultValue]](hint) 的實(shí)現(xiàn)請(qǐng)往下看。
[[DefaultValue]](hint) 內(nèi)部操作

在對(duì)象 O 上調(diào)用內(nèi)部操作 [[DefaultValue]] 時(shí),根據(jù) hint 的不同,其執(zhí)行的操作也不同,簡(jiǎn)化版(具體可參考 ES5 規(guī)范 8.12.8 節(jié))如下:

如果 hintString;

如果 OtoString 屬性是函數(shù);

O 設(shè)置為 this 值并調(diào)用 toString 方法,將返回值賦值給 val;

如果 val 是原始值類型則返回;

如果 OvalueOf 屬性是函數(shù);

O 設(shè)置為 this 值并調(diào)用 valueOf 方法,將返回值賦值給 val;

如果 val 是原始值類型則返回;

拋出 TypeError 錯(cuò)誤。

如果 hintNumber

如果 OvalueOf 屬性是函數(shù);

O 設(shè)置為 this 值并調(diào)用 valueOf 方法,將返回值賦值給 val

如果 val 是原始值類型則返回;

如果 OtoString 屬性是函數(shù);

O 設(shè)置為 this 值并調(diào)用 toString 方法,將返回值賦值給 val;

如果 val 是原始值類型則返回;

拋出 TypeError 錯(cuò)誤。

如果 hint 參數(shù)為空;

如果 ODate 對(duì)象,則和 hintString 時(shí)一致;

否則和 hintNumber 時(shí)一致。

ToString

原始值的字符串化的規(guī)則如下:

null 轉(zhuǎn)化為 "null";

undefined 轉(zhuǎn)化為 "undefined";

true 轉(zhuǎn)化為 "true"

false 轉(zhuǎn)化為 "false";

數(shù)字的字符串化遵循通用規(guī)則,如 21 轉(zhuǎn)化為 "21",極大或者極小的數(shù)字使用指數(shù)形式,如:

var num = 3.912 * Math.pow(10, 50);

num.toString(); // "3.912e50"

對(duì)于普通對(duì)象,如果對(duì)象有自定義的 toString() 方法,字符串化時(shí)就會(huì)調(diào)用該自定義方法并使用其返回值,否則返回的是內(nèi)部屬性 [[Class]] 的值,比如 "object [Object]"。需要注意的是,數(shù)組默認(rèn)的 toString() 方法經(jīng)過了重新定義,其會(huì)將所有元素字符串化之后再用 "," 連接起來,如:

var arr = [1, 2, 3];

arr.toString(); // "1,2,3"

ToNumber

在 ES5 規(guī)范中定義的 ToNumber 操作可以將非數(shù)字值轉(zhuǎn)換為數(shù)字。其規(guī)則如下:

true 轉(zhuǎn)換為 1;

false 轉(zhuǎn)換為 0;

undefined 轉(zhuǎn)換為 NaN;

null 轉(zhuǎn)換為 0

針對(duì)字符串的轉(zhuǎn)換基本遵循數(shù)字常量的相關(guān)規(guī)則。處理失敗則返回 NaN

對(duì)象會(huì)先被轉(zhuǎn)換為原始值,如果返回的是非數(shù)字的原始值,則再遵循上述規(guī)則將其強(qiáng)制轉(zhuǎn)換為數(shù)字。

在將某個(gè)值轉(zhuǎn)換為原始值的時(shí)候,會(huì)首先執(zhí)行抽象操作 ToPrimitive,如果結(jié)果是數(shù)字則直接返回,如果是字符串再根據(jù)相應(yīng)規(guī)則轉(zhuǎn)換為數(shù)字。

參照上述規(guī)則,現(xiàn)在我們可以一步一步來解釋本文開頭的那行代碼了。

var timestamp = +new Date(); // timestamp 就是當(dāng)前的系統(tǒng)時(shí)間戳,單位是 ms

其執(zhí)行步驟如下:

new 操作符比 + 操作符優(yōu)先級(jí)更高,因此先執(zhí)行 new Date() 操作,生成一個(gè)新的 Date 實(shí)例;

一元操作符 + 在其操作數(shù)為非數(shù)字時(shí),會(huì)對(duì)其進(jìn)行隱式強(qiáng)制類型轉(zhuǎn)換數(shù)字

hintNumber;

Date 實(shí)例的 valueOf 屬性指向的是 Date.prototype.valueOf,是一個(gè)函數(shù);

this 指向 Date 實(shí)例并調(diào)用 valueOf 函數(shù),獲得返回值;

返回值是一個(gè)數(shù)字,直接將其返回;

隱式強(qiáng)制類型轉(zhuǎn)換獲得的值賦值給 timestamp 變量。

有了以上知識(shí),我們就可以實(shí)現(xiàn)一些比較好玩的東西了,比如將數(shù)字和對(duì)象相加:

var a = {
  valueOf: function() {
    return 18;
  }
};

var b = 20;

+a; // 18
Number(a); // 18
a + b; // 38
a - b; // -2

順帶提一下,從 ES5 開始,使用 Object.create(null) 創(chuàng)建的對(duì)象,其 [[Prototype]] 屬性為 null 因此沒有 valueOf()toString() 方法,因此無法進(jìn)行強(qiáng)制類型轉(zhuǎn)換。請(qǐng)看如下示例:

var a = {};
var b = Object.create(null);

+a; // NaN
+b; // Uncaught TypeError: Cannot convert object to primitive value
a + ""; // "[object Object]"
b + ""; // Uncaught TypeError: Cannot convert object to primitive value
ToBoolean

JavaScript 中有兩個(gè)關(guān)鍵字 truefalse,分別表示布爾類型的真和假。我們經(jīng)常會(huì)在 if 語句中將 0 作為假值條件,1 作為真值條件,這也利用了強(qiáng)制類型轉(zhuǎn)換。我們可以將 true 強(qiáng)制類型轉(zhuǎn)換為 1,false 強(qiáng)制類型轉(zhuǎn)換為 0,反之亦然。然而 true1 并不是一回事,false0 也一樣。

假值

在 JavaScript 中值可以分為兩類:

可以被強(qiáng)制類型轉(zhuǎn)換為 false 的值

其他(被強(qiáng)制類型轉(zhuǎn)換為 true 的值)

在 ES5 規(guī)范中下列值被定義為假值:

undefined

null

false

+0、-0NaN

""

假值的布爾強(qiáng)制類型轉(zhuǎn)換結(jié)果為 false。

在假值列表以外的值都是真值。

?? 例外

規(guī)則難免有例外。剛說了除了假值列表以外的所有其他值都是真值,然而你可以在現(xiàn)代瀏覽器的控制臺(tái)中執(zhí)行下面幾行代碼試試:

Boolean(document.all);
typeof document.all;

得到的結(jié)果應(yīng)該是 false"undefined"。然而如果你直接執(zhí)行 document.all 得到的是一個(gè)類數(shù)組對(duì)象,包含了頁(yè)面中所有的元素。document.all 實(shí)際上不能算是 JavaScript 語言的范疇,這是瀏覽器在特定條件下創(chuàng)建一些外來(exotic)值,這些就是“假值對(duì)象”。

假值對(duì)象看起來和普通對(duì)象并無二致(都有屬性,document.all 甚至可以展為數(shù)組),但是其強(qiáng)制類型轉(zhuǎn)換的結(jié)果卻是 false

在 ES5 規(guī)范中,document.all 是唯一一個(gè)例外,其原因主要是為了兼容性。因?yàn)槔洗a可能會(huì)這么判斷是否是 IE:

if (document.all) {
  // Internet Explorer
}

在老版本的 IE 中,document.all 是一個(gè)對(duì)象,其強(qiáng)制類型轉(zhuǎn)換結(jié)果為 true,而在現(xiàn)代瀏覽器中,其強(qiáng)制轉(zhuǎn)換結(jié)果為 false

真值

除了假值以外都是真值。

比如:

var a = "false";
var b = "0";
var c = """";

var d = Boolean(a && b && c);

d; // ?

dtrue 還是 false 呢?

答案是 true。這些值都是真值,相信不需要過多分析。

同樣,以下幾個(gè)值一樣都是真值:

var a = [];
var b = {};
var c = function() {};
顯式強(qiáng)制類型轉(zhuǎn)換

顯式強(qiáng)制類型轉(zhuǎn)換非常常見,也不會(huì)有什么坑,JavaScript 中的顯式類型轉(zhuǎn)換和靜態(tài)語言中的很相似。

字符串和數(shù)字之間的顯式轉(zhuǎn)換

字符串和數(shù)字之間的相互轉(zhuǎn)換靠 String()Number() 這兩個(gè)內(nèi)建函數(shù)實(shí)現(xiàn)。注意在調(diào)用時(shí)沒有 new 關(guān)鍵字,只是普通函數(shù)調(diào)用,不會(huì)創(chuàng)建一個(gè)新的封建對(duì)象。

var a = 21;
var b = "2.71828";

var c = String(a);
var d = Number(b);

c; // "21"
d; // 2.71828

除了直接調(diào)用 String() 或者 Number() 方法之外,還可以通過別的方式顯式地進(jìn)行數(shù)字和字符串之間的相互轉(zhuǎn)換:

var a = 21;
var b = "2.71828";

var c = a.toString();
var d = +b;

c; // "21"
d; // 2.71828

雖然 a.toString() 看起來很像顯式的,然而其中涉及了隱式轉(zhuǎn)換,因?yàn)?21 這樣的原始值是沒有方法的,JavaScript 自動(dòng)創(chuàng)建了一個(gè)封裝對(duì)象,并調(diào)用了其 toString() 方法。

+b 中的 + 是一元運(yùn)算符,+ 運(yùn)算符會(huì)將其操作數(shù)轉(zhuǎn)換為數(shù)字。而 +b 是顯式還是隱式就取決于開發(fā)者自身了,本文之前也提到過,顯式還是隱式都是相對(duì)的。

顯式轉(zhuǎn)換為布爾值

和字符串與數(shù)字之間的相互轉(zhuǎn)換一樣,Boolean() 可以將參數(shù)顯示強(qiáng)制轉(zhuǎn)換為布爾值:

var a = "";
var b = 0;
var c = null;
var d = undefined;

var e = "0";
var f = [];
var g = {};

Boolean(a); // false
Boolean(b); // false
Boolean(c); // false
Boolean(d); // false

Boolean(e); // true
Boolean(f); // true
Boolean(g); // true

不過我們很少會(huì)在代碼中直接用 Boolean() 函數(shù),更常見的是用 !! 來強(qiáng)制轉(zhuǎn)換為布爾值,因?yàn)榈谝粋€(gè) ! 會(huì)將操作數(shù)強(qiáng)制轉(zhuǎn)換為布爾值,并反轉(zhuǎn)(真值反轉(zhuǎn)為假值,假值反轉(zhuǎn)為真值),而第二個(gè) ! 會(huì)將結(jié)果反轉(zhuǎn)回原值:

var a = "";
var b = 0;
var c = null;
var d = undefined;

var e = "0";
var f = [];
var g = {};

!!a; // false
!!b; // false
!!c; // false
!!d; // false

!!e; // true
!!f; // true
!!g; // true

不過更常見的情況是類似 if(...) {} 這樣的代碼,在這個(gè)上下文中,如果我們沒有使用 Boolean() 或者 !! 轉(zhuǎn)換,就會(huì)自動(dòng)隱式地進(jìn)行 ToBoolean 轉(zhuǎn)換。

三元運(yùn)算符也是一個(gè)很常見的布爾隱式強(qiáng)制類型轉(zhuǎn)換的例子:

var a = 21;
var b = "hello";
var c = false;

var d = a ? b : c;

d; // "hello"

在執(zhí)行三元運(yùn)算的時(shí)候,先對(duì) a 進(jìn)行布爾強(qiáng)制類型轉(zhuǎn)換,然后根據(jù)結(jié)果返回 : 前后的值。

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

大部分被詬病的強(qiáng)制類型轉(zhuǎn)換都是隱式強(qiáng)制類型轉(zhuǎn)換。但是隱式強(qiáng)制類型轉(zhuǎn)換真的一無是處嗎?并不一定,引擎在一定程度上簡(jiǎn)化了強(qiáng)制類型轉(zhuǎn)換的步驟,這對(duì)于有些情況來說并不是好事,而對(duì)于另一些情況來說可能并不一定是壞事。

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

在上一節(jié)我們已經(jīng)介紹了字符串和數(shù)字之間的顯式強(qiáng)制類型轉(zhuǎn)換,在這一節(jié)我們來說說他們兩者之間的隱式強(qiáng)制類型轉(zhuǎn)換。

+ 運(yùn)算符既可以用作數(shù)字之間的相加也可以通過重載用于字符串拼接。我們可能覺得如果 + 運(yùn)算符兩邊的操作數(shù)有一個(gè)或以上是字符串就會(huì)進(jìn)行字符串拼接。這種想法并不完全錯(cuò)誤,但也不是完全正確的。比如以下代碼可以驗(yàn)證這句話是正確的:

var a = 21;
var b = 4;

var c = "21";
var d = "4";

a + b; // 25
c + d; // "214"

但是如果 + 運(yùn)算符兩邊的操作數(shù)不是字符串呢?

var arr0 = [1, 2];
var arr1 = [3, 4];

arr0 + arr1; // ???

上面這條命令的執(zhí)行結(jié)果是 "1,23,4"。ab 都不是字符串,為什么 JavaScript 會(huì)把 ab 都轉(zhuǎn)換為字符串再進(jìn)行拼接?

根據(jù) ES5 規(guī)范 11.6.1 節(jié),如果 + 兩邊的操作數(shù)中,有一個(gè)操作數(shù)是字符串或者可以通過以下步驟轉(zhuǎn)換為字符串,+ 運(yùn)算符將進(jìn)行字符串拼接操作:

如果一個(gè)操作數(shù)為對(duì)象,則對(duì)其調(diào)用 ToPrimitive 抽象操作;

ToPrimitive 抽象操作會(huì)調(diào)用 [[DefaultValue]](hint),其中 hintNumber

這個(gè)操作和上面所述的 ToNumber 操作一致,不再重復(fù)。

在這個(gè)操作中,JavaScript 引擎對(duì)其進(jìn)行 ToPrimitive 抽象操作的時(shí)候,先執(zhí)行 valueOf() 方法,但是由于其 valueOf() 方法返回的是數(shù)組,無法得到原始值,轉(zhuǎn)而調(diào)用 toString() 方法,toString() 方法返回了以 , 拼接的所有元素的字符串,即 1,23,4+ 運(yùn)算符再進(jìn)行字符串拼接,得到結(jié)果 1,23,4

簡(jiǎn)單來說,只要 + 的操作數(shù)中有一個(gè)是字符串,或者可以通過上述步驟得到字符串,就進(jìn)行字符串拼接操作;其余情況執(zhí)行數(shù)字加法。

所以以下這段代碼可謂隨處可見:

var a = 21;

a + ""; // "21"

利用隱式強(qiáng)制類型轉(zhuǎn)換將非字符串轉(zhuǎn)換為字符串,這樣轉(zhuǎn)換非常方便。不過通過 a + "" 和直接調(diào)用 String(a) 之間并不是完全一樣,有些細(xì)微的差別需要注意一下。a + "" 會(huì)對(duì) a 調(diào)用 valueOf() 方法,然后再通過上述的 ToString 抽象操作轉(zhuǎn)換為字符串。而 String(a) 則會(huì)直接調(diào)用 toString()。

雖然返回值都是字符串,然而如果 a 是對(duì)象的話,結(jié)果可能出乎意料!

比如:

var a = {
  valueOf: function() {
    return "21";
  },
  toString: function() {
    return "6";
  }
};

a + ""; // "42"
String(a); // "6"

不過大部分情況下也不會(huì)寫這么奇怪的代碼,如果你真的要擴(kuò)展 valueOf() 或者 toString() 方法的話,請(qǐng)留意一下,因?yàn)槟憧赡軣o意間影響了強(qiáng)制類型轉(zhuǎn)換的結(jié)果。

那么從字符串轉(zhuǎn)換為數(shù)字呢?請(qǐng)看下面的例子:

var a = "2.718";
var b = a - 0;

b; // 2.718

由于 - 操作符不像 + 操作符有重載,- 只能進(jìn)行數(shù)字減法操作,因此如果操作數(shù)不是數(shù)字的話會(huì)被強(qiáng)制轉(zhuǎn)換為數(shù)字。當(dāng)然,a * 1a / 1 也可以,因?yàn)檫@兩個(gè)運(yùn)算符也只能用于數(shù)字。

- 用于對(duì)象會(huì)怎么樣呢?比如:

var a = [3];
var b = [1];

a - b; // 2

- 只能執(zhí)行數(shù)字減法,因此會(huì)對(duì)操作數(shù)進(jìn)行強(qiáng)制類型轉(zhuǎn)換為數(shù)字,根據(jù)前面所述的步驟,數(shù)組會(huì)調(diào)用其 toString() 方法獲得字符串,然后再轉(zhuǎn)換為數(shù)字。

布爾值到數(shù)字的隱式強(qiáng)制類型轉(zhuǎn)換

假設(shè)現(xiàn)在你要實(shí)現(xiàn)這么一個(gè)函數(shù),在它的三個(gè)參數(shù)中,如果有且只有一個(gè)參數(shù)為真值則返回 true,否則返回 false,你該怎么寫?

簡(jiǎn)單一點(diǎn)的寫法:

function onlyOne(x, y, z) {
  return !!((x && !y && !z) || (!x && y && !z) || (!x && !y && z));
}

onlyOne(true, false, false); // true
onlyOne(true, true, false); // false
onlyOne(false, false, true); // true

三個(gè)參數(shù)的時(shí)候代碼好像也不是很復(fù)雜,那如果是 20 個(gè)呢?這么寫肯定過于繁瑣了。我們可以用強(qiáng)制類型轉(zhuǎn)換來簡(jiǎn)化代碼:

function onlyOne(...args) {
  return (
    args.reduce(
      (accumulator, currentValue) => accumulator + !!currentValue,
      0
    ) === 1
  );
}

onlyOne(true, false, false, false); // true
onlyOne(true, true, false, false); // false
onlyOne(false, false, false, true); // true

在上面這個(gè)改良版的函數(shù)中,我們使用了數(shù)組的 reduce() 方法來計(jì)算所有參數(shù)中真值的數(shù)量,先使用隱式強(qiáng)制類型轉(zhuǎn)換把參數(shù)轉(zhuǎn)換成 true 或者 false,再通過 + 運(yùn)算符將 true 或者 false 隱式強(qiáng)制類型轉(zhuǎn)換成 1 或者 0,最后的結(jié)果就是參數(shù)中真值的個(gè)數(shù)。

通過這種改良版的代碼,我們可以很簡(jiǎn)單的寫出 onlyTwo()、onlyThree() 的函數(shù),只需要改一個(gè)數(shù)字就好了。這無疑是一個(gè)很大的提升。

隱式強(qiáng)制類型轉(zhuǎn)換為布爾值

在以下情況中會(huì)發(fā)生隱式強(qiáng)制類型轉(zhuǎn)換:

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

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

while (..)do..while(..) 循環(huán)中的條件判斷表達(dá)式;

.. ? .. : .. 三元表達(dá)式中的條件判斷表達(dá)式,也就是第一個(gè);

邏輯或 || 和邏輯與 && 左邊的操作數(shù),作為條件判斷表達(dá)式。

在這些情況下,非布爾值會(huì)通過上述的 ToBoolean 抽象操作被隱式強(qiáng)制類型轉(zhuǎn)換為布爾值。

||&&

JavaScript 中的邏輯或和邏輯與運(yùn)算符和其他語言中的不太一樣。在別的語言中,其返回值類型是布爾值,然而在 JavaScript 中返回值是兩個(gè)操作數(shù)之一。因此在 JavaScript 中,||&& 被稱作選擇器運(yùn)算符可能更合適。

根據(jù) ES5 規(guī)范 11.11 節(jié):

||&& 運(yùn)算符的返回值不一定是布爾值,而是兩個(gè)操作數(shù)中的其中一個(gè)。

比如:

var a = 21;
var b = "xyz";
var c = null;

a || b; // 21
a && b; // "xyz"

c || b; // "xyz"
c && b; // null

如果 || 或者 && 左邊的操作數(shù)不是布爾值類型的話,則會(huì)對(duì)左邊的操作數(shù)進(jìn)行 ToBoolean 操作,根據(jù)結(jié)果返回運(yùn)算符左邊或者右邊的操作數(shù)。

對(duì)于 || 來說,左邊操作數(shù)的強(qiáng)制類型轉(zhuǎn)換結(jié)果如果為 true 則返回運(yùn)算符左邊的操作數(shù),如果是 false 則返回運(yùn)算符右邊的操作數(shù)。

對(duì)于 && 來說則剛好相反,左邊的操作數(shù)強(qiáng)制類型轉(zhuǎn)換結(jié)果如果為 true 則返回運(yùn)算符右邊的操作數(shù),如果是 false 則返回運(yùn)算符左邊的操作數(shù)。

||&& 返回的是兩個(gè)操作數(shù)之一,而非布爾值。

在 ES6 的函數(shù)默認(rèn)參數(shù)出現(xiàn)之前,我們經(jīng)常會(huì)看到這樣的代碼:

function foo(x, y) {
  x = x || "x";
  y = y || "y";

  console.log(x + " " + y);
}

foo(); // "x y"
foo("hello"); // "hello y"

看起來和我們預(yù)想的一致。但是,如果是這樣調(diào)用呢?

foo("hello world", ""); // ???

上面的執(zhí)行結(jié)果是 hello world y,為什么?

在執(zhí)行到 y = y || "y" 的時(shí)候,JavaScript 對(duì)運(yùn)算符左邊的操作數(shù)進(jìn)行了布爾隱式強(qiáng)制類型轉(zhuǎn)換,其結(jié)果為 false,因此運(yùn)算結(jié)果為運(yùn)算符右邊的操作數(shù),即 "y",因此最后打印出來到日志是 "hello world y" 而非我們預(yù)想的 hello world。

所以這種方式需要確保傳入的參數(shù)不能有假值,否則就可能和我們預(yù)想的不一致。如果參數(shù)中可能存在假值,則應(yīng)該有更加明確的判斷。

如果你看過壓縮工具處理后的代碼的話,你可能經(jīng)常會(huì)看到這樣的代碼:

function foo() {
  // 一些代碼
}

var a = 21;

a && foo(); // a 為假值時(shí)不會(huì)執(zhí)行 foo()

這時(shí)候 && 就被稱為守護(hù)運(yùn)算符(guard operator),即 && 左邊的條件判斷表達(dá)式結(jié)果如果不是 true 則會(huì)自動(dòng)終止,不會(huì)判斷操作符右邊的表達(dá)式。

所以在 if 或者 for 語句中我們使用 ||&& 的時(shí)候,if 或者 for 語句會(huì)先對(duì) ||&& 操作符返回的值進(jìn)行布爾隱式強(qiáng)制類型轉(zhuǎn)換,再根據(jù)轉(zhuǎn)換結(jié)果來判斷。

比如:

var a = 21;
var b = null;
var c = "hello";

if (a && (b || c)) {
  console.log("hi");
}

在這段代碼中,a && (b || c) 的結(jié)果實(shí)際是 "hello" 而非 true,然后 if 再通過隱式類型轉(zhuǎn)換為 true 才執(zhí)行 console.log("hi")。

Symbol 的強(qiáng)制類型轉(zhuǎn)換

ES6 中引入了新的基本數(shù)據(jù)類型 —— Symbol。然而它的強(qiáng)制類型轉(zhuǎn)換有些不一樣,它支持顯式強(qiáng)制類型轉(zhuǎn)換,但是不支持隱式強(qiáng)制類型轉(zhuǎn)換。

比如:

var s = Symbol("hi");

String(s); // "Symbol(hi)"
s + ""; // Uncaught TypeError: Cannot convert a Symbol value to a string

而且 Symbol 不能強(qiáng)制轉(zhuǎn)換為數(shù)字,比如:

var s = Symbol("hi");

s - 0; // Uncaught TypeError: Cannot convert a Symbol value to a number

Symbol 的布爾強(qiáng)制類型轉(zhuǎn)換都是 true。

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

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

相關(guān)文章

  • JavaScript基礎(chǔ)---強(qiáng)制類型轉(zhuǎn)換

    摘要:如果有并且返回基本類型值,再使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換。四寬松相等和嚴(yán)格相等允許在相等比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換,而不允許。這時(shí)最好用來避免不經(jīng)意的強(qiáng)制類型轉(zhuǎn)換。這兩個(gè)原則可以讓我們避開幾乎所有強(qiáng)制類型轉(zhuǎn)換的坑。 一、類型轉(zhuǎn)換規(guī)則 1.ToString 對(duì)于普通對(duì)象來說,除非自行定義toString方法,否則就會(huì)調(diào)用Object.prototype.toString()方法,如果對(duì)象有自己的...

    lufficc 評(píng)論0 收藏0
  • JavaScript數(shù)據(jù)類型及(隱式)類型轉(zhuǎn)換詳解

    摘要:顯示的調(diào)用轉(zhuǎn)換過程稱為顯式強(qiáng)制類型轉(zhuǎn)換,隱式的情況稱為隱式強(qiáng)制類型轉(zhuǎn)換。隱式強(qiáng)制類型轉(zhuǎn)換讓代碼變得晦澀難懂而又便捷而奇妙。事實(shí)上,允許在比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換,而不允許。如果有并且返回基本類型值,就使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換。 JavaScript是一種非常靈活的現(xiàn)代編程語言,靈活到使用者極其容易被忽視的它那廣闊的世界以及它帶給我們的無限遐想空間。本文將對(duì)JavaScript最最基礎(chǔ)也最...

    hiyayiji 評(píng)論0 收藏0
  • javascript中讓人懵逼的類型轉(zhuǎn)換

    摘要:核心點(diǎn)中的強(qiáng)制類型轉(zhuǎn)換總是返回標(biāo)量基本類型值。數(shù)字化對(duì)象在強(qiáng)制轉(zhuǎn)換為數(shù)字的時(shí)候,會(huì)優(yōu)先調(diào)用方法,如果返回基本類型的值,則直接使用該返回值如果返回值不是基本類型,則會(huì)繼續(xù)調(diào)用方法,如果返回基本類型的值,則直接使用該返回值,否則報(bào)錯(cuò)。 最近在讀《你不知道的javascript》系列圖書,收獲蠻大,感慨也挺多的。是的,關(guān)于javascript,你不是不知道,而是真的不知道。?就比如類型轉(zhuǎn)換,...

    didikee 評(píng)論0 收藏0
  • JavaScript 封裝對(duì)象與強(qiáng)制類型轉(zhuǎn)換

    摘要:拆封想要等到封裝對(duì)象中基本類型值,我們可以使用方法獲取。值類型轉(zhuǎn)換上面兩種方式,第一種我們稱為顯示強(qiáng)制類型轉(zhuǎn)換第二種稱之為隱式強(qiáng)制類型轉(zhuǎn)換。介紹強(qiáng)制與隱式類型轉(zhuǎn)換時(shí),我們需要掌握對(duì)字符串?dāng)?shù)字和布爾類型的轉(zhuǎn)換規(guī)則。 前面兩章介紹了幾大數(shù)據(jù)類型以及值類型,接下來的這個(gè)知識(shí)點(diǎn),我覺得它對(duì)于javascript程序員來說是很重要的, 認(rèn)識(shí)封裝對(duì)象 在開始之前,我們先看一個(gè)例子,以便之后更輕松的...

    Lin_YT 評(píng)論0 收藏0
  • JavaScript中的強(qiáng)制類型轉(zhuǎn)換

    摘要:第三章強(qiáng)制類型轉(zhuǎn)換強(qiáng)制類型轉(zhuǎn)換將其他數(shù)據(jù)類型轉(zhuǎn)換成類型將其他數(shù)據(jù)類型轉(zhuǎn)換為強(qiáng)制類型轉(zhuǎn)換指將一個(gè)數(shù)據(jù)類型強(qiáng)制轉(zhuǎn)換為其他數(shù)據(jù)類型類型轉(zhuǎn)換主要是指將其他數(shù)據(jù)類型轉(zhuǎn)換為將其他數(shù)據(jù)類型轉(zhuǎn)換為方式一調(diào)用被轉(zhuǎn)換數(shù)據(jù)的方法該方法不會(huì)影響到原變量但是注 ??????????????????????????????第三章強(qiáng)制類型轉(zhuǎn)換 ???????Cast type:強(qiáng)制類型轉(zhuǎn)換 ??????將其他數(shù)據(jù)類...

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

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

0條評(píng)論

閱讀需要支付1元查看
<