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

YDKJS 第五次讀書會(下)

XAMPP下载 admin 649浏览 0评论
 寬鬆相等 vs. 嚴格相等
嚴格和寬鬆他們之間最重要的差異就是如何判斷相等。
普遍的誤解:

==:檢查值的相等性。
===:檢查值與型別的相等性。
但正確的應該是:

==:允許相等性比較中的強制轉型。
===:不允許強制轉型。
相等性的效能
思考一下誤解觀念和正確觀念之間的差異。
誤解的想法:嚴格比較似乎做比較多事。
正確的想法:寬鬆比較才是做比較多事,因為型別不同還需要依照步驟強制轉型。

而這在效能的比較只有微秒的差異,選用運算子應該判斷當下是否需要強制轉型。

抽象相等性
ECMA 5 11.9.3.1

被比較的兩個值具有相同型別,他們就會以同一性來進行比較。
例外:
NaN 永遠不同等於自己
+0 與 -0 彼此相等
物件之間的寬鬆比較:兩個值只會在兩個都指向完全相同值的參考時才會相等,這邊不會發生強制轉型。
使用寬鬆比較兩個值,需要將其中一個值或兩個值隱含地強制轉型,讓兩個值都具有同一型別。
比較:字串與數字
var a = 42;
var b = “42”;

a === b; // false
a == b; // true
嚴格等於不會強制轉型,所以第一組是 false,
那在寬鬆等於這邊是怎麼運算呢?

ECMA 5 11.9.3:
如果 Type(x) 是 Number 而 Type(y) 是 String, 返回比较 x == ToNumber(y)的结果。
如果 Type(x) 是 String 而 Type(y) 是 Number, 返回比较 ToNumber(x) == y的结果。

所以第二組相等被強制轉型成數字做運算,就是ToNumber的抽象運算。

比較:boolean 與其他值
var a = “42”;
var b = true;

a == b; // false
而 42 是 truthy 的值,為何結果會 false 呢?

ECMA 5 11.9.3:
如果 Type(x) 是Boolean, 返回比较 ToNumber(x) == y 的结果。
如果 Type(y) 是Boolean, 返回比较 x == ToNumber(y) 的结果。

轉型過程是這樣:

true 根據上面規格被轉型為1
’42’ 理所當然被轉型為 42
42 不等於 1
而 false 理所當然被轉為0。

永遠不要用 == true 和 == false

可以嘗試以下判斷:

var a = “42”;

// 不好(會失敗的!):
if (a == true) { // .. }

// 也不該(會失敗的!):
if (a === true) { // .. }

// 足夠好(隱含地工作):
if (a) { // .. }

// 更好(明確地工作):
if (!!a) { // .. }

// 也很好(明確地工作):
if (Boolean( a )) { // .. }
比較:null 與 undefined
ECMA 5 11.9.3:
如果 x 是 null 而 y 是 undefined,返回 true。
如果 x 是 undefined 而 y 是 null,返回 true。

所以 null 和 undefined 在寬鬆相等會等於彼此,但不會等於整個語言的其他值。

var a = null;
var b;

a == b; // true
a == null; // true
b == null; // true

a == false; // false
b == false; // false
a == “”; // false
b == “”; // false
a == 0; // false
b == 0; // false
null 和 undefined 之間的強制轉型是安全的。

var a = doSomething();

if (a == null) {
// ..
}
這樣 a 除了 null 和 undefined ,就算是其他 falsy 值都不會過。

比較:物件與非物件
ECMA 5 11.9.3:
如果 Type(x) 是一个 String 或者 Number 而 Type(y) 是一个Object, 返回比较 x == ToPrimitive(y) 的结果。
如果 Type(x) 是一个 Object 而 Type(y) 是 String 或者 Number, 返回比较 ToPrimitive(x) == y 的结果。

沒有布林是因為布林會先被強制轉型為數字

var a = 42;
var b = [ 42 ];

a == b; // true
步驟:

b 會呼叫 ToPrimitive
b 會變成’42’
轉型為數字
相等
解封裝與 ToPrimitive 強制轉型有關:

var a = “abc”;
var b = Object( a ); // 與`new String( a )`相同

a === b; // false
a == b; // true

a == b 是 true,因為經過 ToPrimitive 強制轉型。

解封裝就是解開基本型別值周圍的包裹器,回傳底層的基底值。
例如new String( a ) 回傳 abc。

== 有其他優先的規則:

var a = null;
var b = Object( a ); // 與`Object()`相同
a == b; // false

var c = undefined;
var d = Object( c ); // 與`Object()`相同
c == d; // false

var e = NaN;
var f = Object( e ); // 與`new Number( e )`相同
e == f; // false
null 和 undefined 無法被封裝,沒有對應的物件包裹器,所以一樣會產生一個普通的物件,而 NaN 可封裝他的 Number 包裹器,但在 == 解封後會失敗,因為 NaN 永遠不與自己相等。

邊緣情況
檢視修改內建的原生原型會產生什麼結果。

有任何其他值可能會⋯⋯
Number.prototype.valueOf = function() {
return 3;
};

new Number( 2 ) == 3; // true
因為 2 或 3 兩個都是基本型別值,所以可以直接比較,並不會用到 valueOf,但new Number( 2 )必須經過 ToPrimitive 強制轉型,因此會呼叫valueOf。

if (a == 2 && a == 3) {
// ..
}
…不會有變數等於 2 又等於 3,所以這段程式沒有任何意義。

var i = 2;

Number.prototype.valueOf = function() {
return i++;
};

var a = new Number( 42 );

if (a == 2 && a == 3) {
console.log( “Yep, this happened.” );
}
這段程式碼有 side-effect,每次產生的結果都不相同。

Falsy 的比較
列出 Falsy 的比較:

“0” == null; // false
“0” == undefined; // false
“0” == false; // true — 噢!
“0” == NaN; // false
“0” == 0; // true
“0” == “”; // false

false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true — 噢!
false == “”; // true — 噢!
false == []; // true — 噢!
false == {}; // false

“” == null; // false
“” == undefined; // false
“” == NaN; // false
“” == 0; // true — 噢!
“” == []; // true — 噢!
“” == {}; // false

0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true — 噢!
0 == {}; // false
“”和”NaN”是根本不可能相等的值。
而”0″和0是合理相等的。
瘋狂的例子
[] == ![]; // true
! 運算子優先性大於==
寬鬆相等強制轉型
[] == Boolean(![])
” == false
0 == 0
true
2 == [2]; // true
“” == [null]; // true
右手邊的[2]及[null]會經過 ToPrimitive 的強制轉型
2 == ‘2’ 而 ” == ”
0 == “\n”; // true
經由 ToNumber 轉型後 “\n” 會等於””。

42 == “43”; // false
“foo” == 42; // false
//NaN == 42
“true” == true; // false
//NaN == 1

42 == “42”; // true
“foo” == [ “foo” ];         // true
合理性的檢查
“0” == false; // true — 噢!
false == 0; // true — 噢!
false == “”; // true — 噢!
false == []; // true — 噢!
“” == 0; // true — 噢!
“” == []; // true — 噢!
0 == []; // true — 噢!
扣除掉永遠都該避免使用的東西後:

“” == 0; // true — 噢!
“” == []; // true — 噢!
0 == []; // true — 噢!
安全地使用隱含的強制轉型
一邊 true 或 false ,千萬不要使用 ==。
任一邊有可能[]、””或 0 ,就考慮不要用==。

QQ截图20181108151159
 JavaScript-Equality-Table

抽象的關係式比較
var a = [ 42 ];
var b = [ “43” ];

a < b; // true
b < a; // false
呼叫 ToPrimitive
任一回傳不是字串,就會轉型為數字
var a = [ “42” ];
var b = [ “043” ];

a < b; // false
ToPrimitive 轉型後皆為字串,如果兩者都是字串,就會開始逐字比較。

同樣邏輯也適用於:

var a = [ 4, 2 ];
var b = [ 0, 4, 3 ];

a < b; // false
此範例也為逐字比較。

var a = { b: 42 };
var b = { b: 43 };

a < b; // ?
兩個皆為[object Object],在辭典順序 a 沒有小於 b。

var a = { b: 42 };
var b = { b: 43 };

a < b; // false
a == b; // false
a > b; // false

a <= b; // true
a >= b; // true
a 與 b 不相等是因為他們不是同一個參考。
a <= b; 先估算 b < a 再否定其結果,所以 false 的反向是 true。
var a = [ 42 ];
var b = “043”;

a < b; // false — 字串比较!
Number( a ) < Number( b ); // true — 數字比较!

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

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