那些短小精悍的&奇葩的&令人感到惊讶的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都能检测出来。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值