2018年1月

(a ==1 && a== 2 && a==3)结果是否为true

最近在查资料的时候发现了一个有趣的帖子:

https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true

内容是帖主在一个大型IT公司面试时遇到的奇怪面试题,题目是这样的:

在JavaScript中,(a ==1 && a== 2 && a==3)可能被判断为 true 吗?

贴主当时回答了“不可能”,然后面试就没有然后了……贴主表示两个星期来自己都没有弄明白这个问题的解法,于是才来发帖求助。

…………

……

恩,对于这个问题,我这类渣渣看了之后也是一脸懵逼的。a作为一个变量,怎么可能同时等于1又等于2还等于3呢……所以我很快就放弃了思考直接往下看大佬们的解答。

最高票答案

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

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

是不是有点懵,我也一样,让我们慢慢来看这个代码……

我们的思路是,如何让a在用==运算符和其他数值进行比较时,那一瞬间a的值和右边的数值一样。

所以我们首先要明白JavaScript中==运算符的机制,使用==进行比较时,若两边的参数类型不一致,就会尝试将左边的参数类型转换为与右边相同。而在这段代码中,a是一个对象,右边与a进行比较的参数则是数字,于是会首先尝试调用valueOf方法,如果失败,则会继续尝试调用toString方法。

知道了这个原理就可以来搞事情了,就像这段代码里一样,直接重写了a对象的toString方法,让它返回a对象的i属性,之后i属性自增1。

于是输出结果当然就是:

Hello World!

看完后我只能说:“还有这种操作!”

另外也可以直接重写valueOf方法来实现,不过这种操作属于奇技淫巧,纯粹用于解答这个面试问题,拓宽思路,正常开发时还是最好不要这样重写valueOf……

还有这种操作?!

等等,这个帖子下面还有更多其他解答,让我们来看看……

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

这是什么操作?!没错,如果你仔细观察原题目,会发现语句里面有两个奇怪的空格间距。

那真的是空格吗?如果是空格的话,编译时会忽略掉,这三个仍然是同一个变量,最后的表达式的结果当然也是false。

不过,如果你像给出这个答案的答主一样博闻广见,也许会想到这个答案,这个间距其实是半宽度韩文,一个Unicode编码中的空格字符,但是ECMAScript并不将其解释为空格,所以aᅠaᅠa其实是不同的对象……

那结果当然就是true啦~

还有这种操作???!

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

恩,这段代码看上去似乎是不可能在控制台打印出东西的……因为这次没有什么奇怪的间距了……

等等,中间那个a好像有点奇怪?好吧,其实这三个a真不是同一个字符。

  • a——正常的拉丁字母小写a
  • ——全角下的拉丁字母小写a
  • а——西里尔字母的小写a

恩……所以这仨也不是同一个变量,if判断的最后结果也就是true。

还有这种操作???!!!

var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    console.log("Yes, it is possible!:sunglasses:");
}

function if‌(){return true;}

等等!怎么可能可以重写if,关键词不是不能重写吗,我怕是学了假的JavaScript。

天真,看了上面的几个答案后难道还认为这个if真的就是if吗?没错……这其实是一个自定义的函数,名字是if‌,虽然看起来好像和关键词长一个样了,但实际上……这个if后面有一个隐藏的字符,这是Unicode编码中的零宽度字符(U+200C,维基参考零宽不连字),所以这样就不跟关键词的if冲突啦。

然后这个自定义函数不论三七二十一直接返回个true,问题就解决了~

结尾

其实后面这种障眼法多少有些抬杠的感觉,但是很有趣嘛就分享出来了2333,这个帖子还有一些有趣和高大上到我看不懂的答案,可以自己去看看,不失为写代码之间的调味剂。

记一次Kimsufi服务器救援模式使用

唔……事情是这样的……

我之前不是入手了法国Kimsufi家的特价独立服务器,并且把这个博客放在了上面吗,然而昨天由于我折腾些事情,差点翻车了。

起因是昨天为了更改apache2的用户配置,去手动修改了/etc/passwd文件,修改完成后,apache2的用户可以使用了,然而却发现root用户登不上了,sudo命令也无法使用。

原因很简单……我不知道什么时候手滑了一下,现在/etc/passwd文件的第一行root前面多了一个"\"符号……变成了\root

啊啊!果然是缺少Linux系统使用和运维经验啊,居然犯下了如此可笑的失误……由于我并没有创建和root同组的用户,所以现在还有救吗?

这样果然不行……那使用su命令去切换到\root这个用户呢?

看来是没救了……于是我决定等第二天有空的时候重装系统……

峰回路转

就在今天我打开Kimsufi控制面板准备重装的时候,无意间点开"Netboot",发现里面有不少选项……似乎有个叫做"Rescue"的选项来着?

去网上一查,这貌似是Kimsufi控制面板提供的以救援模式启动服务器的功能!

难道能把我之前的迷之误操作救回来?于是二话不说开干——

如图所示,打开浮动层后选择"Rescue"一项。

这里要我选择救援模式使用的系统,我选了"rescue64-pro"。

选好之后点击"Next",然后点击"Confirm"确认,接着需要手动将服务器重启一次,可以使用Kimsufi控制面板上的"Restart"硬重启功能。

接下来可能需要等数分钟,系统会发送一封主题为"Access settings for RESCUE mode"的邮件给你,打开一看,这里面有救援模式系统的root账户密码。

好了,得到了root账户密码,接下来可以用SSH客户端连接上去了!

开始救援

成功用root账户登入救援系统后,首先会发现这里的/etc/passwd文件是正常的,废话,不正常还怎么登进来啊。

所以首先我们要找到服务器所在系统的硬盘分区和/etc/passwd文件的所在。

使用df -lhfdsik -l查看后,可以看到救援系统下还没有挂在我们主系统所在的硬盘分区,我的系统安装在/dev/sda2这个分区,接下来需要用mount命令挂载。

mount /dev/sda2 /home/luxnk

要挂载到的文件夹请自己创建,之后进入这个文件夹就应该能看到服务器主系统的所有文件了。

Bingo!那么这里面的etc/passwd就一定是我要找的那个误操作文件了。

小心翼翼的把第一行的"\"去掉……然后保存……

接着将之前挂载的磁盘卸载。

umount /dev/sda2

最后还要在Kimsufi控制面板中的"Netboot"里把启动模式改回"Hard disk",然后重启服务器就可以了~

结尾

在这一番折腾之后,我服务器上的root用户又重新复活了~可以说比起重装系统不知道省去了多少功夫……当然这也是建立在Kimsufi这家主机商提供了救援模式的功能,如果是在其他没有这类功能的主机商上“神操作”了一把,恐怕就真玩完了……

所以,最后的结论是,Linux下涉及系统的操作一定要小心谨慎,我经常拿sudo rm -rf /*作为玩笑话,没想到自己居然也犯下了差不多等级的错误……还好最后挽回了,也算长一个教训吧。