js基石之数据类型三:类型转换

110 阅读2分钟

相关文章

js基石之数据类型一:类型分类&区别
js基石之数据类型二:类型判断
js基石之数据类型三:类型转换
js基石之Number:本质
js基石之Number:应用(数字运算,数字&字符串转换,不同进制表示&相互转换)
js基石之字符: ASCII,GBK,Unicode,utf-32,utf-16,utf-8,encodeuri,encodeuricomponent,base64
js基石之Symbol值
js基石之Object,Map,WeakMap
js基石之Array,Stack,Queue,Set,WeakSet

类型转换(没错 八股本股)

原始值类型相互转换

截屏2024-01-08 下午8.24.36.png

引用类型转换为原始类型

to Boolean:

这种是最简单的 除了空对象(null) 其他任何对象都会转化为true.

to String & toNumber

对象在转换到这两个类型的时候 逻辑是相似的 只是顺序会有不同。

  1. 判断对象是否实现了Symbol.toPrimitive方法。
    如果实现了则按照这个方法返回,如果对象没有实现 则走js内部的Symbol.toPrimitive方法。
    内部Symbol.toPrimitive大概逻辑如下:
function ToPrimitive(input, preferredType) {
  switch (preferredType) {
    case Number:
      return toNumber(input);
      break;
    case String:
      return toString(input);
      break;
    default:
      return toNumber(input);
  }

  function isPrimitive(value) {
    return value !== Object(value);
  }

  function toString() {
    if (isPrimitive(input.toString())) return input.toString();
    if (isPrimitive(input.valueOf())) return input.valueOf();
    throw new TypeError();
  }

  function toNumber() {
    if (isPrimitive(input.valueOf())) return input.valueOf();
    if (isPrimitive(input.toString())) return input.toString();
    throw new TypeError();
  }
}
  1. 如果是转换为number则调用ToPrimitive(input, 'Number')
  2. 如果是转换为String 则调用ToPrimitive(input, 'String')
  3. 不能转换为原始值走报错逻辑
  4. 可以转换为原始值 则返回当前的原始值 然后在继续运算 后续可能还会将这个原始值在进行类型转换。具体看原始值类型相互转换

但是基于上面的步骤 有两个特例==和二元+运算符会触发默认转换模式 类似调用了ToPrimitive(input, Number)

valueOf()和toString()都是Object.prototype上的方法 因此所有对象都有这两个方法,valueOf默认返回对象本身,toString返回对象的类型标识。

这两个方法是可以被覆盖重写的,例如Array.prototype就覆盖了toString()方法,valueOf()一般没有重写。

例子1:

const obj = {
    value: 1,
    [Symbol.toPrimitive](){
        return 10
    },
    toString(){
        return '20'
    },
    valueOf(){
        return 30
    }
};

obj + 1 // 11
obj + '1' // '101'

例子2:

  const obj = {
    value: 1,
    toString(){
        return '20'
    },
    valueOf(){
        return 30
    }
};

obj + 1 // 31
obj + '1' // '301'

例子3:

  const obj = {
    value: 1,
    toString(){
        return '20'
    },
    valueOf(){
        return 30
    }
};

console.log(`${obj}`) // '20'

例子4

{} + [] + {} + [1]
// 按照上面的步骤 {} =>[object Object]
// [] => '' [1]=> '1'
// 所以结果应该是:
'[object Object][object Object]1'

然而直接在浏览器打印
// 结果是 '0[object Object]1'
因为第一个{}被解析为代码块了而不是一个对象
等价于 + [] + {} + [1]
+ [] 按照原始类型进行转换 所以是0 
{}转换为[object Object]
[1]转换为字符 '1'

想得到正确的结果 需要这样写({} + [] + {} + [1])

显式转换: 开发者主动调用api进行转换

to Number: Number()/parseInt()/parseFloat()

let str = "123";
let num = Number(str); // num 现在是数字 123

let str = "123.45";
let num1 = parseInt(str); // num1 现在是数字 123
let num2 = parseFloat(str); // num2 现在是数字 123.45

to String: String()/ toString()

let num = 123;
let str = String(num); // str 现在是字符串 "123"


let num = 123;
let str = num.toString(); // str 现在是字符串 "123"

to Boolean: Boolean()

let str = "hello";
let bool = Boolean(str); // bool 现在是布尔值 true

隐式转换:js引擎在运算过程中进行的转换

to Number

  1. 使用一元+运算符:
let str = "123";
let num = +str; // num 现在是数字 123
  1. 在数学运算中,非数字类型会被自动转换为数字:
let str = "123";
let num = str * 1; // num 现在是数字 123

to String

  1. +运算符中,如果其中一个操作数是字符串,那么另一个操作数会被转换为字符串
let num = 123;
let str = num + ""; // str 现在是字符串 "123"
  1. 在模板字符串中,${}内的表达式会被自动转换为字符串:
let num = 123;
let str = `${num}`; // str 现在是字符串 "123"

to Boolean

  1. 使用!!操作符:
let str = "hello";
let bool = !!str; // bool 现在是布尔值 true
  1. 在条件语句中,非布尔值会被自动转换为布尔值:
let str = "hello";
if (str) {
    // str 被转换为 true
}

参考

  1. javaScript 数据类型和数据结构
  2. 细说 JavaScript 七种数据类型 
  3. 数据类型
  4. 引用类型转换原始类型