成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端面試中遇到 [] == ![] ? 刨祖墳式博客解析,從 ECMAScript 規(guī)范說起,比脫下

codeGoogle / 2796人閱讀

摘要:這種情況,它們返回一個布爾型值。語法描述邏輯非如果能轉(zhuǎn)換為,返回如果能轉(zhuǎn)換為,則返回。轉(zhuǎn)中能夠轉(zhuǎn)換為的字面量是可枚舉的,包含空字符串。

博客 github 地址: https://github.com/HCThink/h-blog/blob/master/interesting/in5.md

github 首頁(star+watch,一手動態(tài)直達): https://github.com/HCThink/h-blog

掘金 link , 掘金 專欄

segmentfault 主頁

原創(chuàng)禁止私自轉(zhuǎn)載

廣告

部門長期招收大量研發(fā)崗位【前端,后端,算法】,歡迎各位大神投遞,踴躍嘗試。

坐標(biāo): 頭條,大量招人,難度有降低,大多能拿到很不錯的漲幅,未上市,offer 給力!歡迎騷擾郵箱!

戳我: 戳我: [email protected]

[] == ![] ?
應(yīng)該是騰訊面試題, 原題更加復(fù)雜

面試遇到這種令人頭皮發(fā)麻的題,該怎么辦呢? 不要慌,我們科學(xué)的應(yīng)對即可。

經(jīng)驗法,簡稱瞎蒙

對于簡短而罕見的寫法,最好的方法就是經(jīng)驗法,基本原則就是瞎蒙,雖然聽著有點扯淡,實際上這不失為一個好辦法,對于一個比較陌生的問題,我們通過經(jīng)驗瞎幾把猜一個「大眾」答案:

簡單觀察此題,我們發(fā)現(xiàn)題目想讓一個 數(shù)組和他的 非 作比較, 從正常的思維來看,一個數(shù)和他的非,應(yīng)該是不相等的。

所以我們 first An is : false
反向操作法

然而你看著面試官淫邪的笑容,突然意識到,問題并不簡單,畢竟這家公司還可以,不會來這么小兒科的問題吧。再轉(zhuǎn)念一想,這 tm 的是 js 啊,畢竟 js 經(jīng)常不按套路出牌啊。

于是你又大膽做出了一個假設(shè): [] == ![] 是 true!

大致結(jié)論有了, 那該怎么推導(dǎo)這個結(jié)論呢?我們逐步分解一下這個問題。分而治之

最終結(jié)論

后面分析很長,涉及到大篇幅的 ECMAScript 規(guī)范的解讀,冗長而枯燥,不想看的同學(xué),可以在這里直接拿到結(jié)論

[] == ![] -> [] == false -> [] == 0 -> [].valueOf() == 0 -> [].toString() == 0 -> "" == 0 -> 0 == 0 -> true
分析

如果你決定要看,千萬堅持看完,三十分鐘之后我一定會給你一個驚喜。

這是個奇怪的問題,乍一看形式上有些怪異, 如果面試中你遇到這么個題,應(yīng)該會有些惱火:這 tm 什么玩意?! shift?。ǚ篮椭C梗)。

雖然有點懵,不過還是理性的分析一下,既然這個表達式含有多個運算符, 那首先還是得看看運算符優(yōu)先級。

運算符優(yōu)先級
運算符優(yōu)先級表

而此題中出現(xiàn)了兩個操作符: 「!」, 「==」, 查表可知, 邏輯非優(yōu)先級是 16, 而等號優(yōu)先級是 10, 可見先執(zhí)行 ![] 操作。在此之前我們先看看 邏輯非

邏輯非 !

mozilla 邏輯非: !

邏輯運算符通常用于Boolean型(邏輯)值。這種情況,它們返回一個布爾型值。

語法描述: 邏輯非(!) !expr

如果expr能轉(zhuǎn)換為true,返回false;

如果expr能轉(zhuǎn)換為false,則返回true。

轉(zhuǎn) bool

js 中能夠轉(zhuǎn)換為false的字面量是可枚舉的,包含

null;

NaN;

0;

空字符串("");

undefined。

所以 ![] => false

于是乎我們將問題轉(zhuǎn)化為: [] == false
== 運算符

這是個勁爆的操作符,正經(jīng)功能沒有,自帶隱式類型轉(zhuǎn)換經(jīng)常令人對 js 刮目相看, 實際上現(xiàn)在網(wǎng)上也沒有對這個操作符轉(zhuǎn)換規(guī)則描述比較好的,這個時候我們就需要去 ECMAscript 上去找找標(biāo)準(zhǔn)了。

ECMAScript? 2019 : 7.2.14 Abstract Equality Comparison

規(guī)范描述: The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

If Type(x) is the same as Type(y), then

Return the result of performing Strict Equality Comparison x === y.

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, Number, or Symbol 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, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.

Return false.

依據(jù)規(guī)范 6, 7 可知,存在 bool 則會將自身 ToNumber 轉(zhuǎn)換 !ToNumber(x) 參考 花絮下的 !ToNumber, 主要是講解 !的意思 ! 前綴在最新規(guī)范中表示某個過程會按照既定的規(guī)則和預(yù)期的執(zhí)行【必定會返回一個 number 類型的值,不會是其他類型,甚至 throw error】

得到: [] == !ToNumber(false)

ToNumber

ECMAScript? 2019 : 7.1.3ToNumber

If argument is true, return 1. If argument is false, return +0.

可知: !ToNumber(false) => 0; [] == 0

然后依據(jù)規(guī)范 8 9, 執(zhí)行 ToPrimitive([])

ToPrimitive

ECMAScript? 2019 : 7.1.1ToPrimitive ( input [ , PreferredType ] )

The abstract operation ToPrimitive converts its input argument to a non-Object type. [嘗試轉(zhuǎn)換為原始對象]

If an object is capable of converting to more than one primitive type, it may use the optional hint PreferredType to favour that type. Conversion occurs according to the following algorithm. [如果一個對象可以被轉(zhuǎn)換為多種原語類型, 則參考 PreferredType, 依據(jù)如下規(guī)則轉(zhuǎn)換]

Assert: input is an ECMAScript language value.

If Type(input) is Object, then

If PreferredType is not present, let hint be "default".

Else if PreferredType is hint String, let hint be "string".

Else PreferredType is hint Number, let hint be "number".

Let exoticToPrim be ? GetMethod(input, @@toPrimitive).

If exoticToPrim is not undefined, then

Let result be ? Call(exoticToPrim, input, ? hint ?).

If Type(result) is not Object, return result.

Throw a TypeError exception.

If hint is "default", set hint to "number".

Return ? OrdinaryToPrimitive(input, hint).

Return input.

大致步驟就是 確定 PreferredType 值[If hint is "default", set hint to "number".], 然后調(diào)用 GetMethod, 正常情況下 GetMethod 返回 GetV, GetV 將每個屬性值 ToObject, 然后返回 O.[[Get]](P, V).

Assert: IsPropertyKey(P) is true.

Let O be ? ToObject(V).

Return ? O.[[Get]](P, V).

[[Get]]

ECMAScript? 2019 : 9.1.8[[Get]] ( P, Receiver )

Return the value of the property whose key is propertyKey from this object[檢索對象的 propertyKey 屬性值]

然后 ToPrimitive step 7 返回 OrdinaryToPrimitive(input, hint)

OrdinaryToPrimitive( O, hint )

ECMAScript? 2019 : 7.1.1.1OrdinaryToPrimitive ( O, hint )

Assert: Type(O) is Object.

Assert: Type(hint) is String and its value is either "string" or "number".

If hint is "string", then

Let methodNames be ? "toString", "valueOf" ?.

Else,

Let methodNames be ? "valueOf", "toString" ?.

For each name in methodNames in List order, do

5.1 Let method be ? Get(O, name).

5.2 If IsCallable(method) is true, then

5.2.1 Let result be ? Call(method, O).

5.2.2 If Type(result) is not Object, return result.

Throw a TypeError exception.

上述過程說的很明白: 如果 hint is String,并且他的 value 是 string 或者 number【ToPrimitive 中給 hint 打的標(biāo)簽】,接下來的處理邏輯,3,4 步描述的已經(jīng)很清楚了。

步驟 5,則是依次處理放入 methodNames 的操作[這也解答了我一直以來的一個疑問,網(wǎng)上也有說對象轉(zhuǎn) string 的時候,是調(diào)用 tostring 和 valueof, 但是總是含糊其辭,哪個先調(diào)用,哪個后調(diào)用,以及是不是兩個方法都會調(diào)用等問題總是模棱兩可,一句帶過 /手動狗頭]。

推論

該了解的基本上都梳理出來了, 說實話,非常累,壓著沒有每個名詞都去發(fā)散。不過大致需要的環(huán)節(jié)都有了.

我們回過頭來看這個問題: 在對 == 操作符描述的步驟 8 9中,調(diào)用 ToPrimitive(y) 可見沒指定 PreferredType, 因此 hint 是 default,也就是 number【參考: 7.1.1ToPrimitive 的步驟2-f】

接著調(diào)用 OrdinaryToPrimitive(o, number) 則進入 7.1.1.1OrdinaryToPrimitive 的步驟 4 ,然后進入步驟 5 先調(diào)用 valueOf,步驟 5.2.2 描述中如果返回的不是 Object 則直接返回,否則才會調(diào)用 toString。

所以 [] == 0 => [].valueOf()[.toString()] == 0. 我們接著來看 數(shù)組的 valueOf 方法, 請注意區(qū)分一點,js 里內(nèi)置對象都繼承的到 valueOf 操作,但是部分對象做了覆寫, 比如 String.prototype.valueOf,所以去看看 Array.prototype.valueOf 有沒有覆寫。

結(jié)果是沒有,啪啪打臉啊,尼瑪,于是乎我們看 Object.prototype.valueOf

Array.prototype.valueOf from Object.prototype.valueOf

ECMAScript? 2019 : 19.1.3.7Object.prototype.valueOf ( )

When the valueOf method is called, the following steps are taken:

Return ? ToObject(this value).

This function is the %ObjProto_valueOf% intrinsic object.

我們接著看 ToObject【抓狂,但是要堅持】。

ToObject

ECMAScript? 2019 : 7.1.13ToObject ( argument )

Object : Return argument?! 這步算是白走了。我們接著看 toString,同樣的我們要考慮覆寫的問題。

Array.prototype.toString()

ECMAScript? 2019 : 22.1.3.28Array.prototype.toString ( )

Let array be ? ToObject(this value).

Let func be ? Get(array, "join").

If IsCallable(func) is false, set func to the intrinsic function %ObjProto_toString%.

Return ? Call(func, array).

可見調(diào)用了 join 方法【ps: 這里面還有個小故事,我曾經(jīng)去滴滴面試,二面和我聊到這個問題,我說數(shù)組的 toString 調(diào)用了 join ,面試官給我說,你不要看著調(diào)用結(jié)果就臆測內(nèi)部實現(xiàn),不是這樣思考問題的...... 我就搖了搖頭,結(jié)果止步二面,獵頭反饋的拒絕三連: 方向不匹配,不適合我們,滾吧。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/99965.html

相關(guān)文章

  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評論0 收藏0
  • 校招社招必備核心前端面試問題與詳細(xì)解答

    摘要:本文總結(jié)了前端老司機經(jīng)常問題的一些問題并結(jié)合個人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識點。此外還有網(wǎng)絡(luò)線程,定時器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機制叫做事件循環(huán)。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結(jié)了前端老司機經(jīng)常問題的一些問題并結(jié)合個...

    jonh_felix 評論0 收藏0
  • 校招社招必備核心前端面試問題與詳細(xì)解答

    摘要:本文總結(jié)了前端老司機經(jīng)常問題的一些問題并結(jié)合個人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識點。此外還有網(wǎng)絡(luò)線程,定時器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機制叫做事件循環(huán)。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結(jié)了前端老司機經(jīng)常問題的一些問題并結(jié)合個...

    Rango 評論0 收藏0
  • ++[[]][+[]]+[+[]]==10? 深入淺出弱類型 JS 的隱轉(zhuǎn)換

    摘要:與此相對,強類型語言的類型之間不一定有隱式轉(zhuǎn)換。三為什么是弱類型弱類型相對于強類型來說類型檢查更不嚴(yán)格,比如說允許變量類型的隱式轉(zhuǎn)換,允許強制類型轉(zhuǎn)換等等。在中,加性運算符有大量的特殊行為。 從++[[]][+[]]+[+[]]==10?深入淺出弱類型JS的隱式轉(zhuǎn)換 本文純屬原創(chuàng)? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉(zhuǎn)載! 原文收錄在【我的GitHub博客】,覺得本文寫的不算爛的...

    miya 評論0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強大而且簡單的方式。插....

    izhuhaodev 評論0 收藏0

發(fā)表評論

0條評論

codeGoogle

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<