中卷(1.4)

強制類型轉換

值類型轉換

將值從一種類型轉換為另一種類型通常稱為類型轉換(type casting),這是顯示的情況;隱式的情況稱為強制類型轉換(coercion)。
也可以這樣來區分:類型轉換發生在靜態類型語言的編譯階段,而強制類型轉換則發生在動態類型語言的運行時。
然而在 js 中通常將他們統稱為強制類型轉換,我個人則傾向于用“隱式強制類型轉換”和“顯示強制類型轉換”來區分。
二者的區別顯而易見:我們能夠從代碼中看出那些地方是顯示強制類型轉換,而隱式強制類型轉換則不那么明顯,通常式某些操作產生的副作用。
例如:

var a = 42;
var b = a + ""; // 隱式強制類型轉換
var c = String( a ); // 顯示強制類型轉換

抽象值操作

1.ToString

該抽象操作負責處理非字符串到字符串的強制類型轉換。
基本類型值的字符串化規則為:null 轉換為 "null",undefined 轉換為 "undefined",true 轉換為 "true"。數字的字符串化則遵循通用規則,不過之前講過的 那些極小和極大的數字使用指數形式。
對普通對象來說,除非自己定義,否則 toString() (Object.prototype.toString()) 返回內部屬性 [[Class]] 的值,如 "[object Object]"。
然而前面我們介紹過,如果對象有自己的 toString() 方法,字符串化時就會調用該方法并使用其返回值。
數組的默認 toString() 方法經過了重新定義:

var a = [1,2,3];
a.toString(); // "1,2,3"

JSON 字符串化
工具函數 JSON.stringify(..) 在將 JSON 對象序列化時也用到了 ToString。
請注意,JSON 字符串化并非嚴格意義上的強制類型轉換,因為其中也設計了 ToString 的相關規則。
對于大多數簡單值來說, JSON 字符串化和 toString() 的效果基本相同,只不過序列化的結果總是字符串:

JSON.stringify( 42 ); // "42"
JSON.stringify( "42" ); // ""42""(含有雙引號的字符串)
JSON.stringify( null ); // "null"
JSON.stringify( true ); // "true"

所有安全的 JSON 值都可以使用 JSON.stringify(..) 字符串化。安全的 JSON 值始值能夠呈現為有效 JSON 格式的值。
為了簡單起見,我們來看看什么是不安全的 JSON 值。undefined、function、symbol 和包含循環引用的對象都不符合 JSON 的結構標準,其他支持 JSON 的語言都無法處理它們。
JSON.stringify(..) 在對象中遇到 undefined、function 和 symbol 時會自動將其忽略,在數組中則會返回 null,以保證單元位置不變。
例如:

JSON.stringify( undefined ); // undefined
JSON.stringify( function(){} ); // undefined

JSON.stringify(
  [1, undefined, function(){},4]
); // "[1,null,null,4]"
JSON.stringify(
  { a:2, b:function(){} }
); // "{"a":2}"

對包含循環引用的對象執行 JSON.stringify(..) 會出錯。

如果對象定義了 toJSON() 方法,JSON 字符串化時會首先調用該方法,然后用它的返回值來進行序列化。
如果要對含有非法的 JSON 值得對象做字符串化,或者對象中的某些值無法被序列化時,就需要定義 toJSON() 方法來返回一個安全的 JSON 值。
例如:

var o = {};

var a = {
  b: 42,
  c: o,
  d: function(){}
};

// 在a中創建一個循環引用
o.e = a;

// 循環引用在這里會產生錯誤
JSON.stringify( a );

// 自定義的 JSON 序列化
a.toJSON = function(){
  return { b: this.b };
};

JSON.stringify( a ); // "{"b":42}"

很多人誤以為 toJSON 返回的是 JSON 字符串化后的值,其實不然,除非我們確實想要對字符串進行字符串化(通常不會!)。toJSON() 返回的值應該是一個適當的值,可以是任何類型,然后再由 JSON.stringify(..) 對其進行字符串化。
也就是說,toJSON() 應該“返回一個能夠被字符串化的安全的 JSON 值”,而不是“返回一個 JSON 字符串”。
例如:

var a = {
  val: [1,2,3],
  
  // 可能是我們想要的結果!
  toJSON: function(){
    return this.val.slice( 1 );
  }
};

var b = {
  val: [1,2,3],
  
  // 可能不是我們想要的結果!
  toJSON: function(){
    return "[" +  
      this.val.slice( 1 ).join() +
    "]";
  }
};

JSON.stringify( a ); // "[2,3]"
JSON.stringify( b ); // ""[2,3]""

現在介紹幾個不太為人所知但卻非常有用的功能。
我們可以向 JSON.stringify(..) 傳遞一個可選參數 replacer,它可以是數組或者函數,用來指定對象序列化過程中哪些屬性應該被處理,哪些應該被排除,和 toJSON() 很像。
如果 replacer 是一個數組,那么它必須是一個字符串數組,其中包含序列化要處理的對象的屬性名稱,除此以外的其他屬性則被忽略。
如果 replacer 是一個函數,它會對對象本身調用一次,然后對對象中的每個屬性各調用一次,每次傳遞兩個參數,鍵和值。如果要忽略某個鍵就返回 undefined,否則返回指定的值。

var a = {
  b: 42,
  c: "42",
  d: [1,2,3]
}

JSON.stringify( a, ["b","c"]); // "{"b":42,"c":"42"}"

JSON.stringify( a, function(k,v){
  if (k !== "c") return v;
})
// "{"b":42,"d":[1,2,3]}"

JSON.stringify 還有一個可選參數 space,用來指定輸出的縮進格式。

var a = {
  b: 42,
  c: "42",
  d: [1,2,3]
};

JSON.stringify( a, null, 3 );
//"{
//   "b": 42,   
//   "c": "42",
//   "d": [
//      1,
//      2,
//      3
//   ]
//}"

JSON.stringify( a, null, "-----");
//"{
//-----"b": 42,
//-----"c": "42",
//-----"d": [
//----------1,
//----------2,
//----------3
//-----]
//}"

請記住,JSON.stringify(..) 并不是強制類型轉換。在這里介紹是因為它涉及 ToString 強制類型轉換,具體表現在以下兩點。
1.字符串、數字、布爾值和 null 的 JSON.stringify(..) 規則與 ToString 基本相同。
2.如果傳遞給 JSON.stringify(..) 的對象中定義了 toJSON() 方法,那么該方法會在字符串化前調用,以便將對象轉換為安全的值

2.ToNumber

其中 true 轉換為 1, false 轉換為 0。undefined 轉換為 NaN,null 轉換為 0。
ToNumber 對字符串的處理基本遵循數字常量的相關規則 / 語法。處理失敗時返回 NaN。
對象(包括數組)會首先被轉換為相應的基本類型值,如果返回的是非數字的基本類型值,則再遵循以上規則將其強制轉換為數字。
為了將值轉換為相應的基本類型值,抽象操作 ToPrimitive 會首先檢查該值是否有 valueOf() 方法。如果有并且返回基本類型值,就使用該值進行強制類型轉換。如果沒有就使用 toString() 的返回值來進行強制類型轉換。
如果 valueOf() 和 toString() 均不返回基本類型值,會產生 TypeError 錯誤。
從 ES5 開始,使用 Object.create(null) 創建的對象 [[Prototype]] 屬性為 null,并且沒有 valueOf() 和 toString() 方法,因此無法進行強制類型轉換。

我們稍后會詳細介紹數字的強制類型轉換,下面的示例代碼中我們假定 Number(..) 已經實現了此功能。

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

var b = {
  toString: function(){
    return "42";
  }
};

var c = [4,2]
c.toString = function(){
  return this.join(""); // "42"
}

Number( a ); // 42
Number( b ); // 42
Number( c ); // 42
Number( "" ); // 0
Number( [] ); // 0
Number( ["abc"] ); //NaN 
3.ToBoolean

首先也是最重要的一點是,js 中有兩個關鍵詞 true 和 false,分別代表布爾類型中的真和假。我們常誤以為值 1 和 0 分別等同于 true 和 false。在有些語言中可能是這樣,但在 js 中布爾值和數字是不一樣的。雖然我們可以將 1 強制類型轉換為 true,將 0 強制類型轉換為 false,反之亦然,但它們并不是一回事。

  • 假值(falsy value)
    js 中的值可以分為以下兩類:
    1)可以被強制類型轉換為 false 的值
    2)其他(被強制類型轉換為 true 的值)
    js 規范具體定義了一小撮可以被強制類型轉換為 false 的值
    以下是這些假值:
    undefined、null、false、+0、-0、NaN 和 ""
    假值的布爾強制類型轉換結果為 false。
    從邏輯上說,價值列表以外的都應該是真值(truthy)。但 js 規范對次并沒有明確定義,只是給出了一些示例,例如規定所有的對象都是真值。
  • 假值對象(falsy object)
    這個標題似乎有點自相矛盾。前面講過規范規定所有的對象都是真值,怎么還有價值對象呢?
    有些人可能會以為假值對象就是包裝了假值的封裝對象,其實不然!
    例如:
var a = new Boolean( false );
var b = new Number( 0 );
var c = new String( "" ); 

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

d 為 true,說明 a、b、c 都為 true。
請注意,這里 Boolean(..) 對 a && b && c 進行了封裝,有人可能問為什么。我們暫且記下,稍后會做說明。你可以試試不用 Boolean(..) 的話 d = a && b && c 會產生什么結果。
如果價值對象并非封裝了假值的對象,那它究竟是什么?
值得注意的是,雖然 js 代碼會出現假值對象,但它實際上并不屬于 js 語言的范疇。
瀏覽器在某些特定情況下,在常規 js 語法基礎上自己創建了一些外來值,這些就是“假值對象”。
假值對象看起來和普通對象并無二致(都有屬性,等等),但將它們強制類型轉換為布爾值時結果為 false。
最常見的例子是 document.all,它是一個類數組對象,包含了頁面上的所有元素,由 DOM 提供給 js 程序使用。
那為什么它是假值呢?因為我們經常通過將 document.all 強制類型轉換為布爾值來··判斷瀏覽器是否是老版本的 IE。

if(document.all) { /* it's old version IE */ }
  • 真值(truthy value)
    真值就是假值列表之外的值。例如:
var a = "false";
var b = "0";
var c = "''";

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

再如:

var a = [];
var b = {};
var c = function(){};

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

顯示強制類型轉換

顯示強制類型轉換是那些顯而易見的類型轉換,很多類型轉換都屬于此列。
對顯示強制類型轉換幾乎不存在非議,它類似于靜態語言中的類型轉換,已被廣泛接受,不會有什么坑。我們后面再討論這個話題。

字符串和數字之間的顯示轉換

我們從最常見的字符串和數字之間的強制類型轉換開始
字符串和數字之間的轉換是通過 String(..) 和 Number(..) 兩個內建函數(原生構造函數)來實現的,請注意它們前面沒有 new 關鍵字,并不創建封裝對象。
下面是兩者之間的顯示強制類型轉換:

var a = 42;
var b = String( a );

var c = "3.14";
var d = Number( c );

b; // "42"
d; // 3.14

除了 String(..) 和 Number(..) 以外,還有其他方法可以實現字符串和數字之間的顯示轉換:

var a = 42;
var b = a.toString();

var c = "3.14";
var d = +c;

b; // "42"
d; // 3.14 

一元運算符 +c 可以將 c 轉換為數字,而非數字的加法運算。
不過有時也容易產生誤會。例如:

var c = "3.14";
var d = 5+ +c;

d; // 8.14

一元運算符 - 和 + 一樣,并且它還會反轉數字的符號位。由于 -- 會被當作遞減運算符來處理,所以我們不能使用 -- 來撤銷反轉,而應該像 - -"3.14" 這樣,在中間加一個空格,才能得到正確結果 3.14。

1.日期顯示轉換為數字
一元運算符 + 的另一個常見的用途是將日期對象強制類型轉換為數字,返回的結果為 Unix 時間戳,以毫秒為單位:

var d = new Date( "Mon, 18 Aug 2014 08:53:06 CDT" );
+d; // 1408369986000

我們常用下面的方法獲得當前的時間戳:

var timestamp = +new Date();

js 有一處奇特的語法,即構造函數沒有參數時可以不用帶()。
于是我們可能會碰到 var timestamp = +new Date; 這樣的寫法。

不過最好還是使用 ES5 中新加入的靜態方法 Date.now()。我們不建議對日期類型使用強制類型轉換。

2.奇特的 ~ 運算符
一個常被人忽視的地方是 ~ 運算符(即字位操作“非”)相關的強制類型轉換。
字位操作符只適用于32位整數,運算符會強制操作數使用32位格式。這是通過抽象操作 ToInt32 來實現的。
ToInt32 首先執行 ToNumber 強制類型轉換,比如 "123" 會先轉換為123,然后再執行 ToInt32。
雖然嚴格說來并非強制類型轉換(因為返回值類型并沒有發生變化),但字位運算符(如 | 和 ~)和某些特殊數字一起使用時會產生類似強制類型轉換的效果,返回另外一個數字。
例如 | 運算符(字位操作“或”)的空操作 0 | x,它僅執行 ToInt32 轉換:

0 | -0; //0
0 | NaN; // 0
0 | Infinity; // 0
0 | -Infinity; // 0

以上這些特殊數字無法以32位呈現(因為它們來自 64 位 IEEE 754 標準),因此返回 0。
再回到 ~。它首先將值強制類型轉換為32位數字,然后執行字位操作“非”(對每一個字位進行反轉)。
對 ~ 還可以有另外一種詮釋,源自早期的計算機科學和離散數學:~ 返回 2 的補碼。這樣一來問題就清楚多了!
~x 大致等同于 -(x+1)。
很奇怪,但相對更容易說明問題。

~42; // -(42+1) ==> -43

另外,在 -(x+1) 中唯一能都得到 0(或者嚴格說是 -0)的 x 值是 -1。也就是說如果 x 為-1時, ~ 和一些數字值在一起會返回假值0,其他情況則返回真值。
這個特點很有用處,因為 -1 是一個“哨位值”,即被賦予了特殊含義的值,在 C 語言中我們用 -1 來表示函數執行失敗,用大于等于 0 的值表示函數執行成功。
js 中字符串的 indexOf(..) 方法也遵循這一慣例,該方法在字符串中搜索指定的子字符串,如果找到就返回子字符串的位置(從0開始),否則返回 -1。
indexOf(..) 不僅能夠得到子字符串的位置,還可以用來檢查字符串中是否包含指定的子字符串,相當于一個條件判斷。
例如:

var a = "Hello World";

if (a.indexOf( "lo" ) >= 0){ // true
  // 找到匹配!
}
if (a.indexOf("lo") != -1){ // true
  // 找到匹配!
}
if (a.indexOf("lo") < 0){ // true
  // 沒有找到匹配!
}
if (a.indexOf("lo") == -1){ // true
  // 沒有找到匹配!
}

大于等于 0 和 ==-1 這樣的寫法不是很好,成為“抽象滲漏”,意思是在代碼中暴露了底層的實現細節,這里是指用 -1 作為失敗時的返回值,這些細節應該被屏蔽掉。

現在我們終于明白 ~ 的用處了!~ 和 indexOf() 一起可以將結果強制類型轉換為 真 / 假值:

var a = "Hello World";

~a.indexOf( "lo" ); // -4 <--真值!

if(~a.indexOf( "lo" )){ // true
  // 找到匹配!
}

~a.indexOf( "ol" ); // 0 <--假值!
!~a.indexOf( "ol" ); // true
if(!~a.indexOf( "ol" )){ // true
  // 沒有找到匹配!
}

由 -(x+1) 推斷 ~-1 的結果應該是 -0,然而實際上結果是0,因為它是字位操作而非數字運算。

3.字位截除
一些開發人員使用 ~~ 來截除數字值得小數部分,以為這和 Math.floor(..) 的效果一樣,實際上并非如此。
~~ 中的第一個 ~ 執行 ToInt32 并反轉字位,然后第二個 ~ 再進行一次字位反轉,即將所有的字位反轉回原值,最后得到的仍然是 ToInt32 的結果。
~~ 和 !! 很相似
對 ~~ 我們要多加注意。首先它只適用于 32 位數字,更重要的是它對負數的處理與 Math.floor(..) 不同。

Math.floor( -49.6 ); // -50
~~-49.6; // -49

~~x 能將值截除為一個32位整數,x | 0 也可以,而且看起來還更簡潔。
出于對運算優先級的考慮,我們更傾向于使用 ~~x:

~~1E20 / 10; // 166199296

1E20 | 0 / 10; // 1661992960
(1E20 | 0 )/ 10; // 166199296

顯示解析數字字符串

例如:

var a = "42";
var b = "42px";

Number( a ); // 42
parseInt( a ); // 42

Number( b ); // NaN
parseInt( b ); // 42

解析允許字符串中含有非數字字符,解析從左到右進行,如果遇到非數字字符就停止解析。而轉換不允許出現數字字符,否則會失敗并返回 NaN。
解析字符串中的浮點數可以使用 parseFloat(..) 函數。
不要忘了 parseInt(..) 針對的是字符串值。向 parseInt(..) 傳遞數字和其他類型的參數是沒有用的,比如 true、function(){...} 和 [1,2,3]。
非字符串參數會首先被強制類型轉換位字符串,依賴這樣的隱式強制類型轉換并非上策,應該避免向 parseInt(..) 傳遞非字符串參數。
從 ES5 開始 parseInt(..) 默認轉換位十進制數,除非另外指定。如果你的代碼需要在 ES5 之前的環境運行,請記得將第二個參數設置為 10。

parseInt 解析非字符串

例如:

parseInt( 1/0, 19 ); // 18

parseInt( 1/0, 19 ) 實際上是 parseInt("Infinity", 19)。第一個字符是 "I",以 19 為基數時值為 18。第二個字符 "n" 不是一個有效的數字字符,解析到此為止。

此外還有一些看起來很奇怪但實際上能解釋得通的例子:

parseInt( 0.000008 ); // 0 ("0" 來自于 "0.000008")
parseInt( 0.0000008 ); // 8 ("8" 來自于 "8e-7")
parseInt( false, 16 ); // 250 ("fa" 來自于 "false")
parseInt( parseInt, 16); // 15 ("f" 來自于 "function..")

parseInt( "0x10" ); // 16
parseInt( "103", 2 ); // 2

其實 parseInt(..) 函數是十分靠譜的,只要使用得當就不會有問題。因為使用不等而導致一些莫名奇妙的結果,并不能歸咎與 js 本身。

顯示轉換位布爾值

與前面的 String(..) 和 Number(..) 一樣, Boolean(..)(不帶 new)是顯示的 ToBoolean 強制類型轉換:

var a = "0";
var b = [];
var c = {};

var d = "";
var e = 0;
var f = null;
var g;

Boolean( a ); // true
Boolean( b ); // true
Boolean( c ); // true

Boolean( d ); // false
Boolean( e ); // false
Boolean( f ); // false
Boolean( g ); // false

和前面講的 + 類似,一元運算符 ! 顯示地將值強制類型轉換為布爾值。但是它同時還將真值反轉為假值(或者將假值反轉為真值)。所以顯示強制類型轉換為布爾值最常用的方法是 !!,因為第二個 ! 會將結果反轉為原值:

var a = "0";
var b = [];
var c = {};

var d = "";
var e = 0;
var f = null;
var g;

!!a; // true
!!b; // true
!!c; // true

!!d; // false
!!e; // false
!!f; // false
!!g; // false

顯示 ToBoolean 的另外一個用處,是在 JSON 序列化過程中將其值強制類型轉換為 true 或 false:

var a = [
  1,
  function(){ /*..*/ },
  2,
  function(){ /*..*/ }
];

JSON.stringify( a ); // "[1,null,2,null]"

JSON.stringify( a, function(key,val){
  if (typeof val == "function"){
    // 函數的 ToBoolean 強制類型轉換
    return !!val;
  }
  else{
    return val;
  }
} );
// "[1,true,2,true]"

隱式強制類型轉換

隱式強制類型轉換指的是那些隱蔽的強制類型轉換,副作用也不是很明顯。
顯式強制類型轉換旨在讓代碼更加清晰可讀,而隱式強制類型轉換看起來就像是它的對立面,會讓代碼變得晦澀難懂。
對強制類型轉換的詬病大多是針對隱式強制類型轉換。
但是隱式強制類型轉換的作用是減少冗余,讓代碼更簡潔。

字符串和數字之間的隱式強制類型轉換

通過重載,+ 運算符即能用于數字加法,也能用于字符串拼接。js 怎樣來判斷我們要的是哪個操作?例如:

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執行單位為行(line),也就是一...
    悟名先生閱讀 4,188評論 0 13
  • 值類型轉換將值從一種類型轉換為另一種類型通常稱為類型轉換,這是顯示的情況;隱式的情況稱為強制類型轉換。JavaSc...
    xpwei閱讀 3,578評論 0 5
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,807評論 18 139
  • 特別說明,為便于查閱,文章轉自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 533評論 0 0
  • 這幾天一直在糾結一個小說的情節,我不知道該用什么樣的方式表達出來。于是寫了刪,刪了改,卻還是沒能使自己滿意。想著這...
    阿驢閱讀 1,633評論 0 1