欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

引用类型转换原始类型

程序员文章站 2022-03-25 10:37:40
...

有很多转换类型的函数,或者隐式转换,也适用于对象。例如Number()、String()、isNaN()之类,在这个过程中我们不经会好奇,把引用类型变成原始类型中,经历了什么过程?

首先,我们看高程3里面的一句话(结合了一点自己的总结)

isNaN()确实也适用于对象。在基于对象调用isNaN()函数时,调用对象自身的valueOf方法。如果返回原始类型的值,则直接使用该值,不再进行后续步骤。如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,使用该值,不再进行后续步骤。如果toString方法返回的是对象,就报错。

这个过程也是ECMAScript中内置函数和操作符的一般执行流程

以上加粗的字体就是我们划出的重点:valueOf、toString、一般执行流程。

为了验证以上所说,我们用代码先撸为敬!

    // 准备了valueOf和toString两个函数
     let obj = {
      valueOf() {
        console.log('valueOf')
        return 1
      },
      toString() {
        console.log('toString')
        return '2'
      }
    };
    console.log(isNaN(obj))

运行结果为:

引用类型转换原始类型

根据以上结果我们能看出是经过了valueOf函数(打印了'valueOf');那么根据上面的引用,我们修改valueOf的返回:

    let obj = {
      valueOf() {
        console.log('valueOf')
        return {}
      },
      toString() {
        console.log('toString')
        return '2'
      }
    };
    console.log(isNaN(obj))

此时的运行结果为:

引用类型转换原始类型

这里能看出来,因为首次调用的valueOf返回了引用类型,所以调用toString了函数;最后我们看看,如果toString返回的也是引用类型会是什么结果:

    let obj = {
      valueOf() {
        console.log('valueOf')
        return {}
      },
      toString() {
        console.log('toString')
        return {}  // 也返回了引用类型
      }
    };
    console.log(isNaN(obj))

运行结果:

引用类型转换原始类型

这时也验证了一开始引用的高程3中所说,会是报错,Cannot convert object to primitive value(无法将对象转换为原始值)

在了解了转换类型的流程之后,我们知道isNaN()函数在接收一个值时,会先尝试将这个值转换成数值,也就是说以上的流程适用于将引用类型转换成数值的方法,例如Number(),那么如果时转换成其他基本类型,例如字符串会是什么结果?

    let obj = {
      valueOf() {
        console.log('valueOf')
        return {}
      },
      toString() {
        console.log('toString')
        return 'i am obj'
      }
    };
    console.log(String(obj))

运行结果:

引用类型转换原始类型

能看出直接调用了toString方法;废话不多说,再让toString函数返回引用类型

    let obj = {
      valueOf() {
        console.log('valueOf')
        return 'i am obj -- valueOf'
      },
      toString() {
        console.log('toString')
        return {}
      }
    };
    console.log(String(obj))

运行结果为:

引用类型转换原始类型

以上结果等于把转换数值的流程反了过来:先调用toString,如果返回的不是基本类型,再调用valueOf;那么根据这个套路,如果在valueOf函数返回一个引用类型,应该也是会报错,我们看看结果:

    let obj = {
      valueOf() {
        console.log('valueOf')
        return {}  // 返回引用类型
      },
      toString() {
        console.log('toString')
        return {}
      }
    };
    console.log(String(obj))

运行结果:

引用类型转换原始类型

根据以上测试,我们也能总结出引用类型转换基本类型的流程了,注意,没有返回也是返回了基本类型(undefined)

引用类型转换原始类型

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我们知道,es6新出了一个Symbol的基本类型,其中,在内置的Symbol值中,提到了Symbol.toPrimitive方法,原文链接来自阮一峰的ECMAScript6入门:https://es6.ruanyifeng.com/#docs/symbol#%E5%86%85%E7%BD%AE%E7%9A%84-Symbol-%E5%80%BC,我们先看这个方法的作用

引用类型转换原始类型

我们试试将这个方法用在以上例子

    let obj = {
      valueOf() {
        console.log('valueOf')
        return 1
      },
      toString() {
        console.log('toString')
        return '2'
      },
      [Symbol.toPrimitive]() {
        console.log('toPrimitive')
        return 3
      }
    };
    console.log(String(obj))

运行结果:

引用类型转换原始类型

能看出来,首先直奔toPrimitive方法(转为原始类型就调用次方法,不管是字符串还是数值及其他);我们想,既然valueOf或者toString返回了引用类型的话,还是有余地去调用对应的方法,如果还是返回引用类型才会报错,那我们在toPrimitive返回是引用类型又会怎么样?

    let obj = {
      valueOf() {
        console.log('valueOf')
        return 1
      },
      toString() {
        console.log('toString')
        return '2'
      },
      [Symbol.toPrimitive]() {
        console.log('toPrimitive')
        return {}
      }
    };
    console.log(String(obj))

结果是直接报错;

引用类型转换原始类型

综合刚刚的转换流程及内置方法,得出最后的结论

引用类型转换原始类型

相关标签: Javascript