在工程实践中,咱们经常会遇到一些奇技淫巧。所谓奇技淫巧,就是官方在设计或者实践中并未想象出的代码风格或者使用场景。其实也就是相似于 react 的 hoc,原本源自于社区,可是该方案却成为了官方确定的方案。那么究竟应不该在平时学习呢?究竟应不该该在工程中使用呢,或者使用怎么样的奇技淫巧。前端
两年前。我尚未毕业,在大学的最后一个学期中选择了进入前端,同时,被吸引到前端阵营中一个不得不说的缘由就是 js 的奇技淫巧,同时我的是一个比较猎奇的人,因此就学了不少关于 js 的奇技淫巧。react
如今这些奇技淫巧要么变成了这门语言不可或缺的一部分,要么随着时间的推移而消失,还有一些在不知不觉中却忘记了,既然此次的文章是介绍这方面的知识,也就多介绍一下以前学习的一些例子。git
在 es6 includes 还没有推行以前,咱们判断判断字符串或者数组包含只能使用 indexOf 这个方法,可是 indexOf 返回的确实元素的索引,若是不存在则返回 -1。
由于在以前写 c 语言的时候,咱们每每使用 0 表明成功,1 2 3表明着不一样的错误。由于0是独一无二的。在类c的语言中是具备 truthy falsy 这个概念。并不指代bool的 true 与 false。es6
下表表明了js 的 truthy 以及 falsy。github
变量类型 | falsy | truthy |
---|---|---|
布尔 | false | true |
字符串 | " " | 非空字符串 |
数值 | 0 NaN | 任何不为falsy的数值 |
null | 是 | 否 |
undefined | 是 | 否 |
对象(数组), {} 以及 [] | 否 | 是 |
对于数值而言,咱们知道 0 对于数值是惟一的,而 -1不是。那么咱们能够经过 ~ 运算符来把-1 变为 0.typescript
~-1 // 0 ~1 //-2
解释下
对每个比特位执行非(NOT)操做。NOT a 结果为 a 的反转(即反码)。数组
9 (base 10) = 00000000000000000000000000001001 (base 2) ~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
由于在计算机中第一位表明着 符号位置。 浏览器
同时简单理解。对任一数值 x 进行按位非操做的结果为 -(x + 1)。
也就是说经过 ~ 能够把 -1(且仅仅只是 -1) 变为 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 中 }
没学习惰性函数时候,若是建立 xhr,每次都须要判断。函数
function createXHR(){ var xmlhttp; try{ //firfox,opear,safari xmlHttp=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; }
在学习完了惰性函数以后
function createXHR(){ // 定义xhr, var xhr = null; if (typeof XMLHttpRequest!='undefined') { xhr=new XMLHttpRequest(); createXHR=function(){ return new XMLHttpRequest(); //直接返回一个懒函数 } } 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 } } } } // 第一次调用也须要 返回 xhr 对象,因此须要返回 xhr return xhr; }
若是代码被使用于两次调用以上则会有必定的性能优化。第一次调用时候 把 xhr 赋值并返回,且在进入层层 if 判断中把 createXHR 这个函数赋值为其余函数。
// 若是浏览器中有 XMLHttpRequest 对象在第二次调用时候 createXHR=function(){ return XMLHttpRequest(); //直接返回一个懒函数 }
该方案能够在不须要第二个变量的状况下直接对函数调用进行优化。同时对于调用方也是透明的,不须要修改任何代码。
在最近的学习中,我看到了一篇关于 ... (扩展运算符)的另类用法,The shortest way to conditional insert properties into an object literal, 这篇文章介绍了如何最简化的写出条件性插入对象属性。
在没有看过这篇文章时会写出以下代码:
// 得到手机号 const phone = this.state.phone const person = { name: 'gogo', age: 11 } // 若是手机号不为空,则添加到person中 if (phone) { person.phone = phone }
可是,看完该文章以后能够写出这样的代码
// 得到手机号 const phone = this.state.phone const person = { name: 'gogo', age: 11, ...phone && {phone} }
上面的代码与该代码功能相同,可是代码量却减小不少。
要理解上述代码的运行原理,首先先介绍一下 ... 运算符,
对象的扩展运算符(...)用于取出参数对象的全部可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 } // 若是是 空对象,没有任何效果 {...{}, a: 1} // { a: 1 } // 若是扩展运算符后面不是对象,则会自动将其转为对象。可是若是对象没有属性,就会返回空对象 // {...1} 会变为 {...Object(1)} 可是由于没有属性 {...1} // {} // 同理获得 {...undefined} {...null} {...true} // 都会变为 {}
能够参考 阮一峰的 es6入门的对象的扩展运算符
原理是由于代码能够以下理解:
const obj = { ...(phone && {phone}) } // 若是 phone 有数据,&& 执行则会变为 const obj = { ...{phone} } // 而对象扩展运算符 执行就会变为 const obj = { phone } 可是 若是 phone 为空字符串或者其余 falsy 数据,则代码会直接短路 const obj = { ...false ...null ...0 ...undefined } 则不会添加任何属性进入对象
关于 ~ 操做符 + indexOf 其实加深了对位运算与比特位的理解。可是在es6以后咱们彻底可使用 includes。彻底能够再也不使用~indexOf。
对于惰性函数,在typescript中,该代码是不可使用的。固然,咱们能够经过函数变量以及增长代码实现上述功能。
function createXHR(){} // 修改成 let createXHR = function() { // ... }
这里也能够看出 ts 不承认函数声明的函数名是一个变量。
对于扩展运算符的特殊用法。关于 typescript 使用,上述代码是能够在ts中使用的,不过不可使用 &&,要使用 三元运算符
{ ...phone ? {phone} : {} }
可是不建议在ts中使用,由于该代码不会被代码ts检测到。
const phone = '123' // 定义接口 interface Person { name: string; } // 不会爆出 error const person: Person = { name: 'ccc', ...phone ? {phone} : {} }
该代码是与 ts 严重相悖的,ts首要就是类型定义,而使用该代码逃出了 ts 的类型定义,这个对于语言上以及工程维护上是没法接受的。
一样的代码,我认为 js 是能够接受的(可是未必要在工程中使用),可是 ts 确实没法接受的,这也是不一样的语言之间的差别性。
在关于这片文章的评论中,最大的论点在于 为何要使用最简的代码,最好的代码应该是不言自明的。
而做者也相对而言探讨了本身的一些见解,应该学习一些本身不理解的东西。同时若是一个东西可以解释前因后果,彻底能够从原理性解释,那么值得学习与使用。同时我我的实际上是和做者持着相赞成见的。
若是你以为这篇文章不错,但愿能够给与我一些鼓励,在个人 github 博客下帮忙 star 一下。
博客地址
The shortest way to conditional insert properties into an object literal