摘要:稍后我們?cè)僭敿?xì)剖析,接下來(lái)先看一個(gè)問(wèn)題。還內(nèi)建了一些在之前沒(méi)有暴露給開(kāi)發(fā)者的,它們代表了內(nèi)部語(yǔ)言行為。使用,可能有不少朋友一開(kāi)始就想到這種方式,簡(jiǎn)單貼一下閱讀更多
在 JavaScript 環(huán)境下,可以讓表達(dá)式 a == true && a == false 為 true 嗎?
就像下面這樣,可以在控制臺(tái)打印出 ’yeah":
// code here if (a == true && a == false) { console.log("yeah"); }
JavaScript 是一門(mén)類型松散的語(yǔ)言,在使用 == 進(jìn)行比較時(shí),倘若左右類型不一致,是會(huì)進(jìn)行類型裝換的。首先來(lái)了解一下寬松相等的概念,
寬松相等 ==先看看 ECMA 5.1 的規(guī)范,包含 toPrimitive:
規(guī)范 11.9.3 The Abstract Equality Comparison Algorithm
If Type(x) is the same as Type(y), then
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is ?0, return true.
If x is ?0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Return false.
9.1 ToPrimitiveTable 10 — ToPrimitive Conversions
Input Type | Result |
---|---|
Undefined | The result equals the input argument (no conversion). |
Null | The result equals the input argument (no conversion). |
Boolean | The result equals the input argument (no conversion). |
Number | The result equals the input argument (no conversion). |
String | The result equals the input argument (no conversion). |
Object | Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8. |
對(duì)于下述表達(dá)式:
x == y
類型相同,判斷的就是 x === y
類型不同
如果 x,y 其中一個(gè)是布爾值,將這個(gè)布爾值進(jìn)行 ToNumber 操作
如果 x,y 其中一個(gè)是字符串,將這個(gè)字符串進(jìn)行 ToNumber 操作
若果 x,y 一方為對(duì)象,將這個(gè)對(duì)象進(jìn)行 ToPrimitive 操作
至于 ToPrimitive,即求原始值,可以簡(jiǎn)單理解為進(jìn)行 valueOf() 和 toString() 操作。
稍后我們?cè)僭敿?xì)剖析,接下來(lái)先看一個(gè)問(wèn)題。
Question:是否存在這樣一個(gè)變量,滿足 x == !x就像這樣:
// code here if (x == !x) { console.log("yeah"); }
可能很多人會(huì)想到下面這個(gè),畢竟我們也曾熱衷于各種奇技淫巧:
[] == ![] // true
但答案絕不僅僅局限于此,比如:
var x = new Boolean(false); if (x == !x) { console.log("yeah"); }
理解這個(gè)問(wèn)題,基本上下面的這些例子都不是問(wèn)題了。
寬松相等的栗子9 == "9" 9 == "9x" 9 == true 9 == undefined 9 == null 0 == undefined 0 == null undefined == null 0 == false "" == false "1" == true "9" == true 9 == [9] "9" == [9] "9" == [9, 4] "9,4" == [9, 4] [] == [] [] == ![] ![] == ![] [] == {} [] == !{} {} == ![] {} == {} {} == !{} 9 == { toString() { return 9 }} 9 == { valueOf() { return 9 }} 9 == { a: 9 } 9 == {} "[object Object]" == {}
在來(lái)看看什么是 ToPrimitive
ToPrimitive貼個(gè)規(guī)范:8.12.8 [[DefaultValue]] (hint)
如果是 Date 求原始值,則 hint 是 String,其他均為 Number,即先調(diào)用 valueOf() 再調(diào)用 toString()。
如果 hint 為 Number,具體過(guò)程如下:
調(diào)用對(duì)象的 valueOf() 方法,如果值是原值則返回
否則,調(diào)用對(duì)象的 toString() 方法,如果值是原值則返回
否則,拋出 TypeError 錯(cuò)誤
// valueOf 和 toString 的調(diào)用順序 var a = { valueOf() { console.log("valueof") return [] }, toString() { console.log("toString") return {} } } a == 0 // valueof // toString // Uncaught TypeError: Cannot convert object to primitive value // Date 類型先 toString,后 valueOf var t = new Date("2018/04/01"); t.valueOf = function() { console.log("valueof") return [] } t.toString = function() { console.log("toString") return {} } t == 0 // toString // valueof // Uncaught TypeError: Cannot convert object to primitive value
到目前為止,上面的都是 ES5 的規(guī)范,那么在 ES6 中,有什么變化呢
ES6 中 ToPrimitive7.1.1ToPrimitive ( input [, PreferredType] )
在 ES6 中嗎,是可以自定義 @@toPrimitive 方法的,是 Well-Known Symbols(§6.1.5.1)中的一個(gè)。JavaScript 還內(nèi)建了一些在 ECMAScript 5 之前沒(méi)有暴露給開(kāi)發(fā)者的 symbol,它們代表了內(nèi)部語(yǔ)言行為。
// 沒(méi)有 Symbol.toPrimitive 屬性的對(duì)象 var obj1 = {}; console.log(+obj1); // NaN console.log(`${obj1}`); // "[object Object]" console.log(obj1 + ""); // "[object Object]" // 擁有 Symbol.toPrimitive 屬性的對(duì)象 var obj2 = { [Symbol.toPrimitive](hint) { if (hint == "number") { return 10; } if (hint == "string") { return "hello"; } return true; } }; console.log(+obj2); // 10 -- hint is "number" console.log(`${obj2}`); // "hello" -- hint is "string" console.log(obj2 + ""); // "true" -- hint is "default"
有了上述鋪墊,答案就呼之欲出了
最初題目的答案var a = { flag: false, toString() { return this.flag = !this.flag; } }
或者使用 valueOf():
var a = { flag: false, valueOf() { return this.flag = !this.flag; } }
或者是直接改變 ToPrimitive 行為:
// 其實(shí)只需設(shè)置 default 即可 var a = { flag: false, [Symbol.toPrimitive](hint) { if (hint === "number") { return 10 } if (hint === "string") { return "hello" } return this.flag = !this.flag } }如果是嚴(yán)格相等呢
但是,有沒(méi)有辦法是嚴(yán)格相等,即:
// code here if (a === true && a === false) { console.log("yeah"); }
答案是:有。
使用 defineProperty,可能有不少朋友一開(kāi)始就想到這種方式,簡(jiǎn)單貼一下:
let flag = false Object.defineProperty(window, "a", { get() { return (flag = !flag) } }) if (a === true && a === false) { console.log("yeah"); }閱讀更多
Can (a== 1 && a ==2 && a==3) ever evaluate to true?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93950.html
摘要:通過(guò)使用其構(gòu)造函數(shù),可以將一個(gè)值的類型轉(zhuǎn)換為另一種類型。如果使用兩次,可用于將該值轉(zhuǎn)換為相應(yīng)的布爾值。 編譯自:[1] + [2] – [3] === 9!? Looking into assembly code of coercion.全文從兩個(gè)題目來(lái)介紹類型轉(zhuǎn)換、寬松相等以及原始值的概念: [1] + [2] – [3] === 9 如果讓 a == true && a == fa...
摘要:那么,它到底是如何工作的呢讓我們從一種更簡(jiǎn)單的實(shí)現(xiàn)開(kāi)始實(shí)際上這種實(shí)現(xiàn)代碼更短,并且更易讀是函數(shù)原型中的一個(gè)函數(shù),它調(diào)用函數(shù),使用第一個(gè)參數(shù)作為參數(shù),并傳遞剩余參數(shù)作為被調(diào)用函數(shù)的參數(shù)。 原文:The Most Clever Line of JavaScript 作者:Seva Zaikov 原文 最近 一個(gè)朋友 發(fā)給我一段非常有趣的 JavaScript 代碼,是他在某個(gè) 開(kāi)源庫(kù)中...
摘要:參考鏈接在中,和是對(duì)象自帶的三個(gè)方法,都是為了改變函數(shù)體內(nèi)部的指向。返回值是函數(shù)方法不會(huì)立即執(zhí)行,而是返回一個(gè)改變了上下文后的函數(shù)。而原函數(shù)中的并沒(méi)有被改變,依舊指向全局對(duì)象。原因是,在中,多次是無(wú)效的。 參考鏈接:https://juejin.im/post/59bfe8... 在JavaScript中,call、apply和bind是Function對(duì)象自帶的三個(gè)方法,都是為了改變...
摘要:于是退而求其次叫為類的構(gòu)造函數(shù)。如果這個(gè)函數(shù)被用在創(chuàng)建自定義對(duì)象的場(chǎng)景中,我們稱這個(gè)函數(shù)為構(gòu)造函數(shù)。遇到的問(wèn)題始終指向創(chuàng)建當(dāng)前對(duì)象的構(gòu)造函數(shù)。 Object.constructor,prototype 對(duì)象的prototype和constructor是兩個(gè)重要的屬性,他們總是成對(duì)出現(xiàn),提到constructor的地方,不得不涉及到另外一個(gè)非常重要的屬性prototype,它是js中基于...
摘要:于是乎同源策略應(yīng)運(yùn)而生主要限制在于和無(wú)法讀取。怎么繞過(guò)同源策略首先一般來(lái)說(shuō)協(xié)議和端口造成的跨域問(wèn)題大部分方法是沒(méi)有辦法繞過(guò)的。二級(jí)域名是寄存在主域名之下的域名。當(dāng)主域名受到懲罰二級(jí)域名也會(huì)連帶懲罰。 前言 這是一道前端跨不過(guò)躲不掉面試必備的知識(shí),掙扎多年沒(méi)能做到刻骨銘心深入脊髓,只能好好寫(xiě)篇博文記錄起來(lái)了; 什么是跨域? 廣義來(lái)說(shuō),A域執(zhí)行的文檔腳本試圖去請(qǐng)求B域下的資源是不被允許的,...
閱讀 1368·2021-11-24 09:39
閱讀 1358·2021-11-04 16:12
閱讀 2701·2021-09-24 09:47
閱讀 3346·2021-09-01 10:50
閱讀 1487·2019-08-30 15:55
閱讀 1432·2019-08-30 15:43
閱讀 652·2019-08-30 11:08
閱讀 3588·2019-08-23 18:33