看破JS底层——实现a==1、2、3

2,235 阅读3分钟
  • 写在前面

    假如我和你说a == 1 && a == 2 && a == 3结果为true你会怎么看?或许你会怀疑,a怎么可能同时为3个值?!但是它确实是存在的!

    今天,就让我为你们揭开这层神秘的面纱!

  • 底层核心

    如果真的想要搞懂如何实现a == 1 && a == 2 && a == 3,那么我们首先就要搞清楚,在实现a == 1的背后,JS究竟做了哪些工作?

    接下来我们看一段代码

        const a = {
            value:1
        }
    
        console.log(a == 1)
    

    很多人第一眼或许会认为这是true,但是我可以很负责的和你说结果是false!在这里我们要清楚的认知到,value=1只是a的一个属性,并不等于a本身。接下来我们再看一段代码:

    const a = {
        value: 1,
        valueOf() {
            return this.value
        }
    }
    
    console.log(a == 1) //true
    
    

    为什么加了一个valueOf这里就为true了?说到这,我们就有必要了解一下==的背后,核心原理是啥。在进行数据类型转换时候,复杂数据类型转变为简单数据类型一共发生了4步

    引用自三元博客

    对象转原始类型是根据什么流程运行的?
    对象转原始类型,会调用内置的[ToPrimitive]函数,对于该函数而言,其逻辑如下:
    1. 如果有Symbol.toPrimitive()方法,优先调用再返回
    2. 调用valueOf(),如果转换为原始类型,则返回
    3. 调用toString(),如果转换为原始类型,则返回
    4. 如果都没有返回原始类型,会报错
    
  • 实现过程

    所以想要实现文章开头的a == 1 && a == 2 && a == 3,我们只需要简单对其进行应用,复写其中一个方法就可以实现了。 代码如下:

    var a = {
       // 设置默认值为0
       value: 0,
       // 复写valueOf方法
       valueOf() {
           // 每次自增,让value慢慢增加
           this.value++;
           return this.value;
       }
    }
    
    console.log(a == 1 && a == 2 && a == 3);//true
    

  • 更新

    受评论区几位大佬的指点,发现除此之外还可以使用Object.defineProperty和proxy实现,下面更新实现使用Object.defineProperty进行实现(proxy代理模式还在学习中)。官方文档

    语法:Object.defineProperty(obj, prop, desc)

    obj:需要定义属性的当前对象

    prop 当前需要定义的属性名

    desc 属性描述符

    代码实现

    // 定义一个临时变量
    var val = 0;
    
    //从全局捕获a,并且将++val作为a的值返回
    Object.defineProperty(window, 'a', {
        get: function () {
            return ++val;
        }
    });
    
    console.log(a === 1 && a === 2 && a === 3); // true
    

    对于defineProperty和proxy我也正在学习之中,希望有大牛指点迷津!


  • 写在最后

    在这我们需要牢记对象转原始类型是根据什么流程运行的?

    对象转原始类型,会调用内置的[ToPrimitive]函数,对于该函数而言,其逻辑如下:

    1. 如果有Symbol.toPrimitive()方法,优先调用再返回

    2. 调用valueOf(),如果转换为原始类型,则返回

    3. 调用toString(),如果转换为原始类型,则返回

    4. 如果都没有返回原始类型,会报错

    我是江河,前端实习生一枚,欢迎各位大佬滴滴,文章如有不正之处敬请斧正!