“有意思的前端函数面试题”第一题答案原理解析

3,546 阅读3分钟
if(a == 1 && a == 2 && a == 3){
    console.log("我走进来了");
}

<!--答案1:-->
var a = {num:0};
a.valueOf = function(){
    return ++a.num
}

<!--答案2:-->
var num = 1;
function a(){
    return num++;
}
if(a() == 1 && a() == 2 && a() == 3){
    console.log("我走进来了");
}

<!--答案3:-->

var num = 0;
Function.prototype.toString = function(){
	return ++num;
}
function a(){}

<!--答案4:-->
var  a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};
  1. =====

宽松相等== 和严格相等===都是来判断两个值是够“相等”,但是他们有两个有一个很重要的区别 ==允许在相等比较中进行强制类型转换,而===不允许 那么这也是这道题之所以成为这道题的原因。

  1. 对象和非对象之间的相等比较

关于(对象/函数/数组)和标量基本类型(字符串/数字/布尔值)之间相等比较,ES5有下面规定:

  • 如果Type(x)是字符串或数字,Type(y)是对象,则返回x == ToPrimitive(y)的结果;
  • 如果Type(x)是对象,Type(y)是字符串或数字,则返回ToPromitive(x) == y 的结果。

那么ToPromitive操作是什么呢?

对象(包括数组)会转换为相应的基本类型,ToPromitive会首先检查该值是否有valueOf()方法。如果有并返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。

如果valueOf()toString()均不返回基本类型值,会产生TypeError错误。

那么按照这个规则那么答案一的原理就显而易见了。

那么按照这个规则下面代码也可以正常运行

var a = [3,4]

a.i = 0;

a.valueOf = function() {
    return ++a.i
}
// 或者
// a.toString = function() {
//     return ++a.i
// }

if(a == 1 && a == 2 && a == 3){
    console.log("我走进来了");
}

注意:数组也是对象,所以也可以赋值属性,所以a.i是正确的写法,一般不推荐这么做!!

  1. ++a, 和 a++

大家可以看到在答案一和答案二中有一个区别是 ++aa++ 那么他们的初始值也是不一样的,那么这个是为什么呢? 这个就要说到++aa++的副作用了。

大部分的表达式是没有副作用的,我们来看下下面的代码

function foo(){
    a = a + 1
}
var a = 1
foo() // 结果值:undefined。副作用:a的值被改变

再看

var a = 1
var b = a++

a++ 首先返回变量a的当前值1,再将值赋值给b,然后将a的值加1:

var a = 1
var b = a++ 
a // 2
b // 1

看下面代码

var a = 1
a++ // 1
a // 2
++a // 3
a++ // 3

++在前面时,它的副作用产生在表达式返回结果之前,而a++的副作用则产生在之后。

根据上面的这些原理,那么也就解释了num++a.num++和为什么他们的初始值不相同了。

  1. Symbol.toPrimitive

这是元编程的里面的东西。那么什么是元编程呢?

元编程是针对程序本身的行为进行操作的编程。换句话说,它是为你的程序的编程而进行的编程。

元编程关注几点:代码检视自己,代码修改自己,或者代码修改默认的语言行为而使其她代码受影响

那么我们来看toPrimitive

== 操作符将在一个对象上不使用任何提示来调用ToPrimitive操作--如果存在@@toPrimitive方法的话,将使用default被调用

  1. Function.prototype.toString

由于原型链的关系,方法a(){}可以调用到Function上的toString()方法。 那当然下面的代码也可以使用开发中不要这么做

var num = 0;
Object.prototype.toString = function(){
   return ++num;
}

以上就是这道题的原理解析,有什么不同的错误请大家指正和提出意见建议。

希望大家知其然知其所以然,也希望社区里关于这些题能给出更多的原理分析和解析,而不是简单的写出一个答案。

愿世界和平!

封面: ColiN00B