探讨奇技淫巧
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
探討奇技淫巧
起源
在工程實踐中,我們常常會遇到一些奇技淫巧。所謂奇技淫巧,就是官方在設(shè)計或者實踐中并未想象出的代碼風(fēng)格或者使用場景。其實也就是類似于 react 的 hoc,本來源自于社區(qū),但是該方案卻成為了官方肯定的方案。那么究竟應(yīng)不應(yīng)在平時學(xué)習(xí)呢?究竟應(yīng)不應(yīng)該在工程中使用呢,或者使用怎么樣的奇技淫巧。
兩年前。我還沒有畢業(yè),在大學(xué)的最后一個學(xué)期中選擇了進入前端,同時,被吸引到前端陣營中一個不得不說的原因就是 js 的奇技淫巧,同時個人是一個比較獵奇的人,所以就學(xué)了很多關(guān)于 js 的奇技淫巧。
現(xiàn)在這些奇技淫巧要么變成了這門語言不可或缺的一部分,要么隨著時間的推移而消失,還有一些在不知不覺中卻忘記了,既然這次的文章是介紹這方面的知識,也就多介紹一下之前學(xué)習(xí)的一些例子。
~ 運算符 + indexOf
在 es6 includes 尚未推行之前,我們判斷判斷字符串或者數(shù)組包含只能使用 indexOf 這個方法,但是 indexOf 返回的確實元素的索引,如果不存在則返回 -1。 因為在之前寫 c 語言的時候,我們往往使用 0 代表成功,1 2 3代表著不同的錯誤。因為0是獨一無二的。在類c的語言中是具有 truthy falsy 這個概念。并不指代bool的 true 與 false。
下表代表了js 的 truthy 以及 falsy。
| 布爾 | false | true |
| 字符串 | " " | 非空字符串 |
| 數(shù)值 | 0 NaN | 任何不為falsy的數(shù)值 |
| null | 是 | 否 |
| undefined | 是 | 否 |
| 對象(數(shù)組), {} 以及 [] | 否 | 是 |
對于數(shù)值而言,我們知道 0 對于數(shù)值是唯一的,而 -1不是。那么我們可以通過 ~ 運算符來把-1 變?yōu)?0.
~-1 // 0 ~1 //-2解釋下
對每一個比特位執(zhí)行非(NOT)操作。NOT a 結(jié)果為 a 的反轉(zhuǎn)(即反碼)。
因為在計算機中第一位代表著 符號位置。
同時簡單理解。對任一數(shù)值 x 進行按位非操作的結(jié)果為 -(x + 1)。 也就是說通過 ~ 可以把 -1(且僅僅只是 -1) 變?yōu)?falsy。
var str = 'study pwa'; var searchFor = 'a';// 這是 if (str.indexOf('a') > -1) 或者 if ( -1 * str.indexOf('a') <= 0) 條件判斷的另一種方法 if (~str.indexOf(searchFor)) {// searchFor 包含在字符串 str 中 } else {// searchFor 不包含在字符串 str 中 }惰性函數(shù)
沒學(xué)習(xí)惰性函數(shù)時候,如果創(chuàng)建 xhr,每次都需要判斷。
function createXHR(){var xmlhttp;try{//firfox,opear,safarixmlHttp=new XMLHttpRequest();} catch(e) {try{xmlHttp=new ActiveXobject('Msxm12.XMLHTTP');} catch(e) {try{xmlHttp=new ActiveXobject("Microsoft.XMLHTTP")} catch(e) {alert("您的瀏覽器不支持AJAX")return false;}}}return xmlHttp; }在學(xué)習(xí)完了惰性函數(shù)之后
function createXHR(){// 定義xhr,var xhr = null;if (typeof XMLHttpRequest!='undefined') {xhr=new XMLHttpRequest();createXHR=function(){return new XMLHttpRequest(); //直接返回一個懶函數(shù)}} else {try{xhr=new ActiveXObject("Msxml2.XMLHTTP");createXHR=function(){return new ActiveXObject("Msxml2.XMLHTTP");}} catch(e) {try{xhr =new ActiveXObject("Microsoft.XMLHTTP");createXHR=function(){return new ActiveXObject("Microsoft.XMLHTTP");}} catch(e) {createXHR=function(){return null}} }}// 第一次調(diào)用也需要 返回 xhr 對象,所以需要返回 xhrreturn xhr; }如果代碼被使用于兩次調(diào)用以上則會有一定的性能優(yōu)化。第一次調(diào)用時候 把 xhr 賦值并返回,且在進入層層 if 判斷中把 createXHR 這個函數(shù)賦值為其他函數(shù)。
// 如果瀏覽器中有 XMLHttpRequest 對象在第二次調(diào)用時候createXHR=function(){return XMLHttpRequest(); //直接返回一個懶函數(shù)}該方案可以在不需要第二個變量的情況下直接對函數(shù)調(diào)用進行優(yōu)化。同時對于調(diào)用方也是透明的,不需要修改任何代碼。
擴展運算符號的另類用法
在最近的學(xué)習(xí)中,我看到了一篇關(guān)于 ... (擴展運算符)的另類用法,The shortest way to conditional insert properties into an object literal, 這篇文章介紹了如何最簡化的寫出條件性插入對象屬性。
在沒有看過這篇文章時會寫出如下代碼:
// 獲得手機號 const phone = this.state.phoneconst person = {name: 'gogo',age: 11 }// 如果手機號不為空,則添加到person中 if (phone) {person.phone = phone }但是,看完該文章之后可以寫出這樣的代碼
// 獲得手機號 const phone = this.state.phoneconst person = {name: 'gogo',age: 11,...phone && {phone} }上面的代碼與該代碼功能相同,但是代碼量卻減少很多。
要理解上述代碼的運行原理,首先先介紹一下 ... 運算符, 對象的擴展運算符(...)用于取出參數(shù)對象的所有可遍歷屬性,拷貝到當(dāng)前對象之中。
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 }// 如果是 空對象,沒有任何效果 {...{}, a: 1} // { a: 1 }// 如果擴展運算符后面不是對象,則會自動將其轉(zhuǎn)為對象。但是如果對象沒有屬性,就會返回空對象 // {...1} 會變?yōu)?{...Object(1)} 但是因為沒有屬性 {...1} // {}// 同理得到 {...undefined} {...null} {...true} // 都會變?yōu)?{}可以參考 阮一峰的 es6入門的對象的擴展運算符
原理是因為代碼可以如下理解:
const obj = {...(phone && {phone}) }// 如果 phone 有數(shù)據(jù),&& 執(zhí)行則會變?yōu)?const obj = {...{phone} } // 而對象擴展運算符 執(zhí)行就會變?yōu)?const obj = {phone }但是 如果 phone 為空字符串或者其他 falsy 數(shù)據(jù),則代碼會直接短路 const obj = {...false...null...0...undefined } 則不會添加任何屬性進入對象討論與思考
關(guān)于 ~ 操作符 + indexOf 其實加深了對位運算與比特位的理解。但是在es6之后我們完全可以使用 includes。完全可以不再使用~indexOf。
對于惰性函數(shù),在typescript中,該代碼是不可以使用的。當(dāng)然,我們可以通過函數(shù)變量以及增加代碼實現(xiàn)上述功能。
function createXHR(){} // 修改為 let createXHR = function() {// ... }這里也可以看出 ts 不認(rèn)可函數(shù)聲明的函數(shù)名是一個變量。
對于擴展運算符的特殊用法。關(guān)于 typescript 使用,上述代碼是可以在ts中使用的,不過不可以使用 &&,要使用 三元運算符
{...phone ? {phone} : {} }但是不建議在ts中使用,因為該代碼不會被代碼ts檢測到。
const phone = '123'// 定義接口 interface Person {name: string; }// 不會爆出 error const person: Person = {name: 'ccc',...phone ? {phone} : {} }該代碼是與 ts 嚴(yán)重相悖的,ts首要就是類型定義,而使用該代碼逃出了 ts 的類型定義,這個對于語言上以及工程維護上是無法接受的。 同樣的代碼,我認(rèn)為 js 是可以接受的(但是未必要在工程中使用),但是 ts 確實無法接受的,這也是不同的語言之間的差異性。
在關(guān)于這片文章的評論中,最大的論點在于 為什么要使用最簡的代碼,最好的代碼應(yīng)該是不言自明的。
而作者也相對而言探討了自己的一些看法,應(yīng)該學(xué)習(xí)一些自己不理解的東西。同時如果一個東西能夠解釋來龍去脈,完全可以從原理性解釋,那么值得學(xué)習(xí)與使用。同時我個人其實是和作者持著相同意見的。
總結(jié)
- js 是一門靈活的語言(手動滑稽)。
- 應(yīng)該多學(xué)習(xí)一些奇技淫巧,因為很多奇技淫巧往往代表一些混合的知識,往往會有一些新奇的思考與體驗(怎么我想不出來?)同時,在別人使用了奇技淫巧時候我可以迅速理解。
- 在項目中是否使用此類代碼要取決團隊類型,以及項目體系,并非個人喜惡。
鼓勵一下
如果你覺得這篇文章不錯,希望可以給與我一些鼓勵,在我的 github 博客下幫忙 star 一下。 博客地址
參考資料
The shortest way to conditional insert properties into an object literal
對象的擴展運算符
轉(zhuǎn)載于:https://my.oschina.net/wsafight/blog/3058605
總結(jié)
- 上一篇: C# teacher类【C#】
- 下一篇: Problem D: 分数减法——结构体