最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

YDKJS 第四次讀書會 筆記(下)

XAMPP下载 admin 578浏览 0评论
 ToBoolean
常見的誤解
true 就是 1 ,false 就是 0,可是在 JS 中,number 就是 number,boolean 就是 boolean,你可以將兩者強制轉型,但那並不相同。

Falsy 值
JavaScript 所有值可以被分為兩類:

被強制轉型為布林會變為 false 的值。
其他所有值。
ToBoolean定義了一個抽象運算,說明強制轉型為布林會發生什麼事。

假值:
undefined
null
false
+0 / -0 / NaN
“”
JavaScript 沒有明確定義 truthy 的清單,語言規格暗示:沒有明確位於 falsy 清單的任何值都是 truthy。

Falsy 物件
document.all是一個類陣列,以前被 JS程式所使用,但因為早就被遺棄了,而因為許多網站仍需要仰賴此功能無法移除,就將此改為 falsy 物件。

除此之都是 Truthy ,連包含 false 的物件包裹器都是 Truthy。

Truthy 值
沒有明確位於 falsy 清單的任何值都是 truthy。

var a = “false”;
var b = “0”;
var c = “””;

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

d;
因為這些變數內含 false 值,但變數本身就是 Truthy。

明確地強制轉型
可以明確看得出來的型別轉換。

明確地:Strings <——> Numbers
為了在 string 和 number 之間進行強制轉型,我們使用內建的String( … ) 和 Number( … ) 函式,要注意的是不使用 new 關鍵字,而我們要做的是在兩個型別做明確的強制轉型。換句話說,如果使用 new 關鍵字就是在建立物件包裹器。

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

var c = “3.14”;
var d = Number( c );

b; // “42”
d; // 3.14
無論是 String( … ) 還是 Number( … ),他們會把值強制轉型成基本型別值,詳細參考前面說的 ToNumber 和 ToString。

除了String( … ) 或 Number( … )這兩個方法,還有其他方法可以在這兩個型別中做明確地轉換:

var a = 42;
var b = a.toString();
//表面上這看起來就是要轉成字串型別,
//但 toString 不能在基本型別值上被呼叫,所以他會被隱含的被封裝成物件包裹器。

var c = “3.14”;
var d = +c;
// 這邊展示加號運算子的形式,
// 他不會做直接的加法運算或是字串連接
// 而是 + 把 c 強制轉型成數字
//
// 如果你沒有用過這些方法的話,你可能認為這些是副作用。

b; // “42”
d; // 3.14
如果你喜歡+c模式的話,還是會有地方讓你困擾,像是:

var c = “3.14”;
var d = 5+ +c;

d; // 8.14
-運算子也會做強制轉型,但它同時也會反轉數字的正負號,但你也不能做–,這樣會變成遞減運算子,所以你應該在他們之間放上空格- -,結果就會像- -“3.14″這樣,這樣就會做強制轉型。

所以如果與其他運算子緊密相鄰的話,你應該要避免用單元運算子來進行強制轉型。

日期轉為數字
單元 + 運算子另一個常見的用途是把 Date 物件強制轉型成數字:

var d = new Date( “Mon, 18 Aug 2014 08:53:06 CDT” );

+d; // 1408369986000
或是取得當下的時戳值:

var timestamp = +new Date();
var timestamp = +new Date;
//沒有參數的狀況下,小括號可加可不加
//但為了增加可讀性,請務必加小括號。
不過如果有不用強制轉型的方法應該優先使用,因為會更明確:

var timestamp = Date.now();
建議:不要用與日期有關的強制轉型,要產生現在時間戳值。
如果要取得非現在時間的時戳值,可用new Date( .. ).getTime()。

~ (NOT)的奇幻旅程
很多人想避免用~ 運算子,但我們還是需要深入了解。

在前面有說 JS 的位元運算子只對 32 位元的作業有定義,所以我們的運算元必須要符合 32 位元值的表示法。這進行的規則是由 ToInt32 抽象運算來控制。

ToInt32 會先進行 ToNumber 的強制轉型,再套用 ToInt32 的規則。

在 ToInt32 執行過程並沒有強制轉型,位元運算子(|或~)與某些特殊的 number 值並用,會產生類似強制轉型的效果,得出不同 number 值。

| 為位元 OR 運算子,先將兩數做二進制表示法,進行位元 OR 運算,再轉回 32 位元的數字。位元運算子也包含- + % / * >> <<。
OR 運算:轉換為二進制,如果任何一個運算式的數字有 1,結果的那個數字就會有 1。否則,結果會在該數字出現 0。

以舉例 0 | x:

0 | -0; // 0
0 | NaN; // 0
0 | Infinity; // 0
0 | -Infinity; // 0
像 NaN 或 Infinity 這種特殊值無法以 32 位元表示,所以 ToInt32 指定 0 作為這些值轉換的結果。換句話說,無法轉成功 32 位元,就是 0 。

~ 運算子會先強制轉型為每個 32 位元的 number 值,再反轉每個位元。然而為何需要反轉?這起緣於離散數學,~ 進行的是二的補數。

我們能明白~x等於-(x+1):

~42; // -(42+1) ==> -43
簡單的說 32 位元的有效範圍的 number 值的~運算,會為-1這個輸入值產生一個 falsy 的 0 值(-0),而其他值產生 truthy 的 number。

-1,常被稱為一個哨符值,已與相同型別的其他值做區隔。

以indexOf(..)來說,如果有找到值,就回傳從零算起的索引位置,如果沒有找到索引位置就回傳-1,另外一個常見的狀況就是indexOf常做在一個布林的檢查,常判斷某個子字串是否有出現在另一個字串中:

var a = “Hello World”;

if (a.indexOf( “lo” ) >= 0) { // true
// 找到了!
}
if (a.indexOf( “lo” ) != -1) { // true
// 找到了
}

if (a.indexOf( “ol” ) < 0) { // true
// 沒找到!
}
if (a.indexOf( “ol” ) == -1) { // true
// 沒找到!
}
像是>= 0或== -1的寫法是一種容易洩露資訊的抽象層,我們可以用~搭配indexOf來改寫:

var a = “Hello World”;

~a.indexOf( “lo” );            // -4   <– truthy!

if (~a.indexOf( “lo” )) { // true
// 找到了!
}

~a.indexOf( “ol” );         // 0    <– falsy!
!~a.indexOf( “ol” ); // true

if (!~a.indexOf( “ol” )) { // true
// 沒找到!
// 這個相等於 includes(..);
}
~ 接受indexOf的回傳值,對於-1,會得到 falsy 的 0,而其他值都是 truthy。
~ 和 >= 0 或 == -1 的寫法比起來還是比較清楚明白。

截斷位元
~~ 截斷位元。

常用:多數開發者會用來截斷數字的小數部分。
誤解:多數人認為~~產生的結果與Math.floor(..)相同。
結果:就只是做 ToInt32 的強制轉型。

運作方式:

第一個~先套用 ToInt32 的強制轉型,讓位元反轉
第二個~進行另一次的逐位元反轉
注意:

~~逐位元雙次反轉類似!!的行為。
在 32 位元上才可能可靠運作。
在負數上的運作與Math.floor(..)不同。
比較:~~x與x | 0都可以把數字截斷成 32 位元的整數,但因為運算子的優先序,所以優先選用~~x,細節在第八章說明。

明確地:剖析數值字串
var a = “42”;
var b = “42px”;

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

Number( b ); // NaN
parseInt( b ); // 42
parseInt 剖析數字字串:

傳值:字串。
對於非數字字元:能夠容忍非數值字元。
過程:在進行剖析時,遇到非數值字元就單純停下來。
Number 轉態字串為數字:

傳值:數值字元字串。
對於非數字字元:不容忍這種狀況,
過程:在進行剖析時,遇到非數值字元轉換會失敗,產生 NaN 值。
兩者雖然相似,但有不同用途。
如果你不知道或是不在意其他非數值字元,就應該使用parseInt,
如果能接受的值只有數字,就應該使用Number。

注意:parseInt 的第二個引數是設定轉數字的數字進制。如果在舊型瀏覽器的parseInt傳入08的數值,在第二個引數沒有設置下,預設為八進制,最好永遠設置第二個引數是 10。

剖析非字串
parseInt( 1/0, 19 ); // 18
parseInt(“Infinity”, 19); //18
錯誤:傳入非字串給parseInt。
base-19 的有效數值字元:0-9 與 a-i(不分大小)。
剖析過程:I 在 base-19 的值為 18,n不在有效數值字元中,剖析停止。

其他 parseInt 的怪異行為:

parseInt( 0.000008 ); // 0   (“0” from “0.000008”)
parseInt( 0.0000008 ); // 8   (“8” from “8e-7”)
parseInt( false, 16 ); // 250 (“fa” from “false”)
parseInt( parseInt, 16 ); // 15  (“f” from “function..”)

parseInt( “0x10” ); // 16
parseInt( “103”, 2 ); // 2
明確地:* <——> Boolean
任何非布林值強制轉型為布林值,強制進行 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
但Boolean(..) 並不常見也不慣用,原因是它也會反轉該值,將」 truthy 變成 falsy,因此最常用的是!!雙否定運算子。

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
如果沒有 Boolean(..) 或 !! ,其他在 if(..) 述句中都是隱含的布林轉型,但這裡的目標是明確地轉型。

假設你希望在 JSON 序列化的過程中強制進行轉布林值,可以用下面方法:

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]”
或是

var a = 42;

var b = a ? true : false;
第二個方法,雖然看起來像是明確的強制轉型,但當中有個隱含的強制轉型,a 要先被強制轉型成布林值,才能進行真假值的測試,建議避免這種方法。

转载请注明:XAMPP中文组官网 » YDKJS 第四次讀書會 筆記(下)

您必须 登录 才能发表评论!