摘要:讓我們快速的復習一下在中一共有兩種類型的值原始值和對象值原始值有布爾值數字還有字符串其他的所有值都是對象類型的值包括數組和函數類型轉化先按運算符來分一下類減號,乘號,肯定是進行數學運算,所以操作數需轉化為類型。
前言
很多小伙伴們覺得javaScript很簡單,下面的這行 javaScript代碼可能會讓你懷疑人生。
(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]
小伙伴們學會了,以后遇到一些講不通道理,讓你不開森的人就把這段代碼發給他。
那么這段代碼為什么會輸出sb呢?
其實這段代碼考的是js的類型轉化的一些基本原理
首先要運用到的第一個知識就是js運算符的優先級,因為這么長一段運算看的人眼花,我們必須得先根據優先級分成n小段,然后再各個擊破
1, js運算符的優先級優先級的排列如下表:
優先級從高到低:
根據此規則,我們把這一串運算分為以下16個子表達式:
運算符用紅色標出,有一點可能大家會意識不到,其實中括號[]也是一個運算符,用來通過索引訪問數組項,另外也可以訪問字符串的子字符,有點類似charAt方法,如:"abcd"[1] // 返回"b"。而且中括號的優先級還是最高的哦。
接下來需要運用的就是javascript的類型轉化知識了,我們先說說什么情況下需要進行類型轉化。當操作符兩邊的操作數類型不一致或者不是基本類型(也叫原始類型)時,需要進行類型轉化。
讓我們快速的復習一下.在JavaScript中,一共有兩種類型的值:原始值(primitives)和對象值(objects).
原始值有:undefined, null, 布爾值(booleans), 數字(numbers),還有字符串(strings).
其他的所有值都是對象類型的值,包括數組(arrays)和函數(functions).
2.類型轉化 (1)先按運算符來分一下類:減號-,乘號*,肯定是進行數學運算,所以操作數需轉化為number類型。
加號+,可能是字符串拼接,也可能是數學運算,所以可能會轉化為number或string
一元運算,如+[],只有一個操作數的,轉化為number類型
(2)下面來看一下轉化規則。ToPrimitive(input, PreferredType?)
可選參數PreferredType是Number或者是String。返回值為任何原始值.如果PreferredType是Number,執行順序如下:
如果input為primitive,返回
否則,input為Object。調用 obj.valueOf()。如果結果是primitive,返回。
否則,調用obj.toString(). 如果結果是primitive,返回
否則,拋出TypeError
如果 PreferredType是String,步驟2跟3互換,如果PreferredType沒有,Date實例被設置成String,其他都是Number
通過ToNumber()把值轉換成Number,直接看ECMA 9.3的表格
參數 | 結果 |
---|---|
undefined | NaN |
null | +0 |
布爾值 | true被轉換為1,false轉換為+0 |
數字 | 無需轉換 |
字符串 | 由字符串解析為數字.例如,"324"被轉換為324 |
如果輸入的值是一個對象,則會首先會調用ToPrimitive(obj, Number)將該對象轉換為原始值,然后在調用ToNumber()將這個原始值轉換為數字.
通過ToString()把值轉化成字符串, 直接看ECMA 9.8的表格
參數 | 結果 |
---|---|
undefined | "undefined" |
null | "null" |
布爾值 | "true" 或者 "false" |
數字 | 數字作為字符串,比如. "1.765" |
字符串 | 無需轉換 |
如果輸入的值是一個對象,則會首先會調用ToPrimitive(obj, String)將該對象轉換為原始值,然后再調用ToString()將這個原始值轉換為字符串.
規則就這么多,接下來實踐一下,根據我們上面劃分出的子表達式,一步一步將這個神奇的代碼給執行出來。開工~
先看最簡單的子表達式16:+[]
只有一個操作數[],肯定是轉化為number了,根據上面的規則2,[]是個數組,object類型,即對象。所以得先調用toPrimitive轉化為原始類型,并且PreferredType為number,這個參數表示更“傾向于”轉化的類型,這里肯定是number了。然后首先調用數組的valueOf方法,數組調用valueOf會返回自身,如下:
這個時候,我們得到一個空串“”,還沒有結束,看上面的規則2描述,繼續調用toNumber,轉化為number類型,如下:
大功告成!子表達式16轉化完畢,+[],最終得到0。
來看子表達式15:[~+""]
空串""前面有兩個一元操作符,但是操作數還是只有一個,所以,最終要轉化為的類型是number。看規則2吧,空串調用toNumber得到0。接下來是~,這是個什么東東呢?它是位運算符,作用可以記為把數字取負然后減一,所以~0就是-1 。
別忘了,這個子表達式外頭還包著中括號,所以最終的值為[-1],即一個數組,里面只有一個元素-1.
接下來看子表達式13就簡單了,把15、16求出來的填進去,就變成了這樣:---1,取數組的第0個元素,然后自減,結果為-2,是不so easy!
繼續往上走,子表達式14: [~+[]]
其實把15、和16的原理用上就非常明顯了,答案[-1]
繼續來求子表達式9,此刻它已變成:-2[-1],有稍許不一樣,不過沒關系,我們還是按照規則來,運算符是乘號,當然是做數學運算,那后面的[-1]就得轉化為number,與16的求法類似,過程如下:
①調用toPrimitive,發現是object類型
②調用valueOf,返回自身[-1]
③因為不是原始類型,繼續調用toString,返回"-1"
④"-1"是原始類型了,然后調用toNumber,返回-1
⑤與-2相乘,返回2
子表達式10:~~!+[],不多說了,答案1. 就是從右往左依次一元計算。
有了9和10,我們來到了子表達式4,此刻它已經長這樣了:2+1, 好,我不多說了。
繼續看表達式7:!(~+[]),~+[]=-1,這個根據上面已經知道了,那!-1是什么呢?這里要說一下這個感嘆號,它是邏輯取非的意思,會把表達式轉化為布爾類型,轉化規則和js的Truthy和Falsy原則是一樣的,后面跟數字的,除0以外都為false,后面跟字符串的,除空串以外都為false。這里的!-1當然就是false了。
接下來這個表達式3:false+{}有點關鍵。一個布爾加一個對象,那這個{}應該先轉化為原始類型,流程如下:
①調用toPrimitive,發現是object類型
②調用valueOf,返回自身{},
③不是原始類型,調用toString,返回"[object Object]"
④false與"[object Object]"相加,false先轉化為字符串"false"
⑤相加得結果"false[object Object]"
知道了表達式3和4,我們就可以來看表達式1了,此時它是這樣的:"false[object Object]"[3],因為這個[]可以取字符串的子字符,像charAt一樣,所以得到了結果"s"
經過上面艱難的流程,我們拿到了字符"s",也就是那張圖的左半邊,剩下的那個"b",相同的原理可以搞出來,我這里就不一一演示了,留給你練練吧~
回顧一下這個過程其實也不復雜,只是有一些需要重復勞動的,只要你掌握了運算的優先級,能把大串分解成一個個小串,然后運用類型轉化的知識挨個處理就搞定了。怎么樣,看到這里你還覺得神奇嗎?
同樣的,中文字符也是由這樣組成的,跟英文同樣的道理。
參考https://www.cnblogs.com/ziyun...
https://zhidao.baidu.com/ques...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98127.html
摘要:前端培訓初級階段語法變量值類型運算符語句前端培訓初級階段內置對象函數前端培訓初級階段類模塊繼承基礎內容知識我們會用到。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思想,我們開課啦(每周四)。 該文為前端培訓-初級階段(1...
摘要:來,今天我來教大家一個騷操作。我利用的就是數組的索引來排序的,大家都知道,索引就是從開始,然后依次遞增的。技術總結這個就是巧用了數組的索引,默認就是一個從小到大的排序的特性。 showImg(https://segmentfault.com/img/bVbsi8K);如果你想要對數組排序,可能會去百度去搜,于是有很多人教你用冒泡,什么二分插入排序、堆排序,如果不太懂其中的代碼意思,很難...
摘要:原文來源于我的前言身為一種弱類型的語言,不用像語言那樣要定義等等數據類型,因為允許變量類型的隱式轉換和允許強制類型轉換。 原文來源于我的github 0.前言 js身為一種弱類型的語言,不用像c語言那樣要定義int、float、double、string等等數據類型,因為允許變量類型的隱式轉換和允許強制類型轉換。我們在定義一個變量的時候,就一個var、let、const搞定,不用擔心...
摘要:今天的騷操作,分享的是一個自動拷貝電腦盤內容的程序。當別人的盤插入到你的電腦上時,腳本會自動把盤所有的內容,全部拷貝到你的電腦上。騷源碼程序主要是由三個函數組成,。每個操作都會記錄到日志中,以便日后查看相應的拷貝信息。 showImg(https://segmentfault.com/img/remote/1460000016794520); 閱讀文本大概需要 6 分鐘。 Python...
閱讀 2876·2021-10-08 10:12
閱讀 3977·2021-09-22 15:45
閱讀 2566·2019-08-30 15:52
閱讀 2634·2019-08-29 18:44
閱讀 2655·2019-08-29 12:37
閱讀 1164·2019-08-26 13:36
閱讀 2569·2019-08-26 13:34
閱讀 1483·2019-08-26 12:20