那些短小精悍的&奇葩的&令人感到惊讶的JavaScript代码

自学习前端以来,陆陆续续遇见很多短小令人惊讶的js代码,固有了专门开一片日记来记录这些代码的想法。借此提高写代码的姿势和深度理解JavaScript。

1.JavaScript中 (a ==1 && a== 2 && a==3) 可能为 true 吗?

来自Stack Overflow的一个问题:链接

国外面试题,Nothing is impossible.

解决方案1:
自定义 toString(或者 valueOf)方法,每次调用改变一次返回值,从而满足判断条件。

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

tostring()属于Object对象,当使用 == 时,如果两个参数的类型不一样,那么 JS 会尝试将其中一个的类型转换为和另一个相同。在这里左边对象,右边数字的情况下,会首先尝试调用 valueOf(如果可以调用的话)来将对象转换为数字,如果失败,再调用 toString。

第二个方法,有点像障眼法,=-=:

var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

注意在if语句(我从你的问题中复制)怪异的间距。 这是半角Hangul(即那些不熟悉的韩语),它是一个Unicode空格字符,不被ECMA脚本解释为空格字符 - 这意味着它是一个标识符的有效字符。 因此,有三个完全不同的变量,一个是在一个之后的Hangul,另一个是前一个,最后一个只有一个。 为了便于阅读,用_替换空格,相同的代码如下所示:

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

哈哈哈,我一般还通过切换半角全角符号方便在Markdown里做段落的空格处理。

还有一种解决方法就是js的with语句,把对象的作用域的范围明确出来(听说with语句缓慢)

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

还有很多办法来解决这个,感兴趣自己可探究。

2.JavaScript合并数组

第一种方法

ES6之前,

// `b` onto `a`:
a.push.apply( a, b );
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

// or `a` into `b`:
b.unshift.apply( b, a );

b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

看apply的文档;

第二个参数:argsArray 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或
undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

所以

let a = [1,2,3],b=[4,5,6];
a.push.apply(a,b);

实质上会将b中三个元素4,5,6当作a.push的参数,这里的a不是apply左边的a,而是传给apply的第一个参数。前面的a只是为了使用push方法,这里的fun函数就是push,换句话说,apply会将第二个类数组参数拆分成一个个单独项。
而与之对应的有个call方法。

let a = [1,2,3];
a.push.call(a,4,5,6);

虽然支持超过2个参数,但需要将参数都列出来,在数组操作上比apply要弱上许多。

第二种方法

ES6后有了扩展运算符很方便

let a = [1,2,3],b=[4,5,6];
a.push(...b) // 6
a // [1, 2, 3, 4, 5, 6]

第三种方法

用reduce函数,文档:

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)这里写图片描述

合并操作:

// `b` onto `a`:
a = b.reduce( function(coll,item){
    coll.push( item );
    return coll;
}, a );
a; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

// or `a` into `b`:
b = a.reduceRight( function(coll,item){
    coll.unshift( item );
    return coll;
}, b );

b; // [1,2,3,4,5,6,7,8,9,"foo","bar","baz","bam","bun","fun"]

3.万能变量类型检测

1.首先想到的肯定是用typeof 检测
2.利用toString()检测:

通过toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为thisArg。

如果在控制台输入:
var a = ‘111’
Object.prototype.toString(a)
返回:”[object Object]”
Object.prototype.toString(a) 中toString 的 this 是 Object.prototype,会返回[Object ],a 是 toString 的参数。 Object.prototype.toString.call(a) 中toString 的 this 是 a,没有参数。

变量检测:

var toString = Object.prototype.toString;

toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]

//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]

很强大吧,undefined和null都能检测出来。。

展开阅读全文

请教一个令人惊讶效率的问题(循环 & 函数调用)

09-27

//原代码:rn#include rn#include rn#include rn/* 自定义函数 */rnint my_strlen(char * string)rnrn char * sc=string;rnrn while(*sc)rn sc++;rnrn return(sc - string);rnrnrnint main(void)rnrn char str[999999];rn char * sc;rn int len;rn struct timeval time1,time2;rn struct timezone tz1,tz2;rnrn memset(str,42,sizeof(str));rn str[999998]='\0';rn sc=str;rnrn gettimeofday(&time1,&tz1);rn /* 循环 */rn while(*sc)rn sc++;rn len= sc - str;rn gettimeofday(&time2,&tz2);rnrn printf("Before do the time second = [%d]\n",time1.tv_sec);rn printf("Before do the time usecond = [%d]\n",time1.tv_usec);rn printf("After do the time second = [%d]\n",time2.tv_sec);rn printf("After do the time usecond = [%d]\n",time2.tv_usec);rn printf("Use time : [%d] usec\n",time2.tv_usec-time1.tv_usec);rnrn printf("*********\n");rnrn gettimeofday(&time1,&tz1);rn /* 函数调用 */rn len=my_strlen(str);rn gettimeofday(&time2,&tz2);rn /* 输出时间 */rn printf("Before call the time second = [%d]\n",time1.tv_sec);rn printf("Before call the time usecond = [%d]\n",time1.tv_usec);rn printf("After call the time second = [%d]\n",time2.tv_sec);rn printf("After call the time usecond = [%d]\n",time2.tv_usec);rn printf("Use time : [%d] usec\n",time2.tv_usec-time1.tv_usec);rnrn//运行结果rn//直接循环循环:rnBefore do the time second = [1127790678]rnBefore do the time usecond = [261634]rnAfter do the time second = [1127790678]rnAfter do the time usecond = [262725]rnUse time : [1091] usecrn//函数调用:rnBefore call the time second = [1127790678]rnBefore call the time usecond = [262990]rnAfter call the time second = [1127790678]rnAfter call the time usecond = [264068]rnUse time : [1078] usecrn 论坛

令人惊艳的代码!!

05-23

这是我在CodeGuru上看到的令人惊艳的代码。(http://www.codeguru.com/misc/undo_redo_cdocument.shtml)。rnrnclass CUndo rnprivate:rn CObList m_undolist; // Stores undo statesrn CObList m_redolist; // Stores redo statesrn long m_growsize; // Adjust for faster savesrn long m_undoLevels; // Requested Undolevels rn long m_chkpt;rnrn void AddUndo(CMemFile*);rn void AddRedo(CMemFile *pFile); rn void Load(CMemFile*);rn void Store(CMemFile*);rn void ClearRedoList();rn rnpublic:rnrn // Here are the hooks into the CDocument classrn virtual void Serialize(CArchive& ar) = 0;rn virtual void DeleteContents() = 0;rnrn // User accessable functionsrn CUndo(long undolevels = 4, long = 32768); // Constructorrn ~CUndo(); // Destructorrn BOOL CanUndo(); // Returns TRUE if can Undorn BOOL CanRedo(); // Returns TRUE if can Redorn void Undo(); // Restore next Undo statern void Redo(); // Restore next Redo state rn void CheckPoint(); // Save current state rn void EnableCheckPoint();rn void DisableCheckPoint();rn;rnrn只要你的应用程序文档类从这个CUndo类派生,可以给SDI/MDI应用程序添加UNDO/REDO的功能。rn例如这样:class CMyDoc : public CDocument, public CUndo;rnrn它使用的实现技巧是利用CMyDoc::Serialize()虚函数保存文档实例的状态,virtual void Serialize(CArchive& ar)=0的声明迫使子类一定要实现它;rnrn我之所以惊叹这段码,并不是它使用的实现技巧,而是它的采用的设计模式。rnrn虽说可以归纳为Command模式的范畴。动态地给一个类添加功能;父类的实现(Undo/Redo)依赖子类的具体实现(CMyDoc::Serialize);rn接口和实现的分离,难道就没有Decorator(装饰)Bridge(桥接)的影子?rnrn解脱之味不独饮!rn 论坛

[转]那些令人喷的程序注释

10-13

程序源代码中的注释经常是一个卧虎藏龙的地方,来看看这一辑国外某公司产品中的注释。注意:看的时候严禁喝水或进食。rn rn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940172L7eG.jpg][/img]rn rn亲爱的代码维护人员:rn当您尝试优化这段代码但发现这是一个极端错误的决定的时候,请修改下面的计时器,以便警示后人。rn总计浪费在这段代码的时间 = 16小时rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_12869401745rJg.jpg][/img]rnrn真的很有问题rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940174dnBH.jpg][/img]rnrn谨以此代码献给我的妻子达琳,感谢她一直支持我,还有我三个孩子和一只狗。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_12869401746FF4.jpg][/img]rnrn神奇代码,请勿改动rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940175raqZ.jpg][/img]rnrn喝醉啦,迟些再弄rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940175jmtp.jpg][/img]rnrn你可能会认为你读得懂以下的代码。但是你不会懂的,相信我吧。rn要是你尝试玩弄这段代码的话,你将会在无尽的通宵中不断地咒骂自己为什么会认为自己聪明到可以优化这段代码。rn好了,现在请关闭这个文件去玩点别的吧。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940175deA1.jpg][/img] rnrn程序员1(于2002年6月7日):在登陆界面临时加入一些调试代码rn程序员2(于2007年5月22日):临你个屁啊rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940175h3Wq.jpg][/img]rnrn反正这个办法就修复了问题,我也不知道为什么会这样rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940175Hr3F.jpg][/img]rnrn要理解什么是递归的话,请参考本文件的底部(在文件的底部)rn要理解什么是递归的话,请参考本文件的顶部rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940178ZZ2n.jpg][/img]rnrn双龙入洞; //啊~~好痛rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940178iiGj.jpg][/img] rnrn亲爱的未来的我自己,请原谅我。rn我有着难以表达的歉意。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940178DuD7.jpg][/img]rnrn我不对以下代码负责。rn是他们逼我写的,是违背我意愿的。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940178L96p.jpg][/img] rnrn疯了吗?欢迎来到斯巴达。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181Za42.jpg][/img]rnrn要是你能修正这个问题的话,我会送给你两个七十二岁的处女rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_12869401814LdV.jpg][/img]rnrn没有注释留给你,难写的代码必定难读rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181IF0f.jpg][/img]rnrnIE 浏览器的 Hack (在这里先假设IE是浏览器)rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181smqM.jpg][/img]rnrn有待修正。 修正什么啊?rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181wYHz.jpg][/img] rnrn要是再让我看到这种代码,我会带着枪来上班的rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181s4mM.jpg][/img] rnrn有只龙在这里……rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181vZz5.jpg][/img]rnrn在你阅读以下代码时,你要先搞懂为什么我在这样做。rn我想读取一个根节点下面所有的子节点,以便控制根节点不会显示在选择框上。但那个傻逼的DBA找了一些某些傻逼的借口不让我用索引去读取这些数据,而要求我用他们傻逼的迭代器。所以有了以下代码。rnrn[img=http://hi.csdn.net/attachment/201010/13/137647_1286940181r87a.jpg][/img] rnrn当我写这段代码的时候,只有老天和我自己知道我在做什么。rnrn现在,只剩老天知道了。rn 论坛

谈一谈工作中那些令人蛋疼的同事~

10-15

本人目前干程序员的工作约1年半了……先后呆过两个公司,碰到些蛋疼的同事,本人脾气在朋友圈中是非常好的,实在是被弄的哭笑不得……写出来跟大家一起乐乐。rnrn 1.第一个公司是个小公司,姑且称那个人为A同事吧。据我所知我进去的时候他已经呆了几个月了,当时有个bootloader的启动参数需要调整一下,我就把一串命令通过一个即时聊天软件发给他了,让他自己改个小参数。因为急着看效果就站在他后面看情况,然后就看到了很蛋疼的一幕:rnrn 他先跑到聊天软件的接收窗口去改,然后发现改不了,想了下,退到桌面上,新建了一个文本文档,切回聊天窗口,选了一堆,右键复制,然后右键粘贴,然后改了下,再重新用鼠标拖动选择全部的,右键复制……而且他复制东西的时候还顿一会,不知道在想什么,我在一边等了半天,看的忍无可忍,我说“兄弟你不用快捷键的么,聊天窗口输入栏也是可以编辑的啊?”rnrn 这还算好的……A同事在讨论问题的时候从来不提解决办法,假如联合调试后,已经确定了问题B是我出的,我就说:“嗯,这个问题我回去查下,咱们继续下一个。”你就发现他又绕回第一个问题去了……然后我明着问他,如果你这么干,你有什么办法没?A往往都是闭口无言。rnrn 第一个公司呆了3个月,果断拍屁股走人。rnrn 2.第二个公司,是个创业团队……额,主要是觉得小地方锻炼人,十多个人。有个同事B,也算是比我早进来的,不过就大概半个月。B同事喜欢各种肯定,别人的代码哪出错了,他就说肯定是你哪出的问题。听多了就恼火,我自己的代码我都不敢肯定哪个问题导致的,你还乱肯定。rnrn 某次工作安排,需要他提供个动态库给我用。我一用就出问题了,一个提示有两个文件全局变量重复定义,还有个函数运行到一半出段错误。我检查下自己的代码没发现问题,就让他过来看下,他看了那两个错误后就说肯定是你的问题,我把代码在他面前确认了,压根就没那两个变量,他还在嘴硬……然后我给他提了个修改建议就懒得理他了。实时证明我是对的。rnrn 另外那个段错误,我让他把代码看了一会我就哭笑不得了,C++在某个类的实现文件:rnrn A a;rn A::A ()rn rn ...rn a.result = 0;rn ...rn rn 有哪位大大可以告诉我有谁这么写……这是怎么构造的(g++编译器编译通过,应该是做了特殊处理)。我是觉得这种思维完全是匪夷所思,而且听说B也干过一些其它匪夷所思的事情。rn rn 我本来是个很随和的人,见到他们之后突然觉得自己的人生观某些方面更清晰了……rn 论坛

没有更多推荐了,返回首页