原生JS系列-01-数据类型的显隐式转换

37 阅读4分钟

1.1 原始值转换为原始值

1.1.1 原始值转为 - Number类型

原始类型值: number string boolean undefined null symbol
Number(123); // 123
Number('123'); // 123
Number('   123'); // 123
Number('.123'); // 0.123
Number('1  2'); // NaN
Number('abc'); // NaN
Number(''); // 0
Number(' '); // 0
Number('true'); // NaN
Number(true); // 1
Number(false); // 0
Number(undefined); // NaN
Number(null); // 0
Number(Infinity); // Infinity
Number(-Infinity); // -Infinity
Number(-0); // -0
Number(Symbol()); // Cannot convert a Symbol value to a number (无法将符号值转换为数字)

1.1.2 原始值转为 - Boolean类型

虚值(falsey): undefined null 0 NaN '' false;(Boolean类型转换,除了虚值返回的都是true)
Boolean(123); // true
Boolean(Infinity); // true
Boolean('asc'); // true
Boolean(''); // false
Boolean('  '); // true   空格也是字符串
Boolean(true); // true
Boolean(false); // false
Boolean(undefined); // false
Boolean(null); // false
Boolean(NaN); // false

1.1.3 原始值转为 - String类型

原始值被String(参数)转换相当于: 参数 + '' 的形式,直接转为原始值。
String(null); // 'null'
String(123); // '123'
String(true); // 'true'
String(NaN); // 'NaN'
String(false); // 'false'

1.2 对象转为原始值

1.2.1 typeof判断数据类型

typeof数据类型: number string boolean undefined object function symbol
typeof(Infinity); // number
typeof(''); // string
typeof('undefined'); // string 注意,此处加了引号,所以是字符串,而不是undefined
typeof(true); // boolean
typeof(false); // boolean
typeof(undefined); // undefined
typeof(null); // object 这是历史遗留bug,ECMA已经收到多次修正提案,均被拒绝
typeof(function(){}); // function
typeof(Symbol()); // symbol

1.2.2 对象转为 - Boolean类型

只有虚值的情况,Boolean()类型转换的才是false,所以对象转为原始值也是这个规则。
Boolean({}); // true
Boolean(/\d/); // true 正则对象,表示一个空格
Boolean(new Error()); // true  
Boolean(Symbol()); // true

1.2.3 对象转为 - Number类型

1. 首先清楚Object.prototype.toString.call()可能出现的结果


// 三大包装类。因为call改变this指向,this指向对象,原始值不是对象,所以系统自动将原始值包装成对象。
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call('abc')); // [object String]
console.log(Object.prototype.toString.call(true)); // [object Boolean]


// toString() 调用 null 返回[object Null],undefined 返回 [object Undefined]。
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(null)); // [object Null]


console.log(Object.prototype.toString.call(function(){})); // [object Function]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call({})); // [object Object]


// 数字,布尔值不能直接像下面这种方式调用。
console.log(123.toString()); // Uncaught SyntaxError: Invalid or unexpected token
console.log((123).toString()); // 123

// null 和 undefined 两种具体的原始值没有包装类。
console.log(null.toString()); // Uncaught TypeError: Cannot read properties of null (reading 'toString')
console.log(undefined.toString()); // Uncaught TypeError: Cannot read properties of undefined (reading 'toString')

// ECMA262系统内置构造函数
console.log(Object.prototype.toString.call(new Error)); // [object Error]
console.log(Object.prototype.toString.call(/\d/)); // [object RegExp]
console.log(Object.prototype.toString.call(Date)); // [object Function]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(Symbol())); // [object Symbol]


// 浏览器提供的构造函数。
(function(){
	console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
})

(Object.prototype.toString.call(document)); // [object HTMLDocument]

2. 其次清楚valueOf()方法

Object.prototype.valueOf():返回指定对象的原始值。
JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。
因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同。
没有看懂没有关系,下面通过4的案例可以明白是怎么回事。

3. 对象转为Number的步骤

var obj = {
	toString() {
  	return 10;
  },
  valueOf() {
  	return 20;
  }
}
console.log(Number(obj)); // 20

1. 明确Number()类型是将对象转换成Number类型,所以先去找valueOf()方法,如果返回值是原始值,就直接通过Number(原始值)进行包装以后返回。

2. valueOf()返回引用值,就去找"自身(valueOf()返回值引用数据类型)"的数据类型的toString()方法,如果没有对象中没有重写toString()方法就通过原型链去父类寻找toString()方法。

3. 如果toString()方法返回原始值,就通过Number(原始值)进行包装以后返回,如果toString()方法返回引用值,就会报错。

5. 案例

console.log(Number([1, 2])); 
valueOf --> [1, 2] --> Array.prototype.toString.call([1, 2]) --> '1, 2' --> Number('1, 2');
// NaN

console.log(Number([10])); 
valueOf --> [10] --> Array.prototype.toString.call([10]) --> '10' --> Number('10'); 
// 10

console.log(Number({}));
valueOf --> {} --> Object.prototype.toString.call({}) --> '[object Object]' --> Number('[object Object]');
// NaN

1.2.4 对象转为 - String类型

var obj = {
	toString() {
            return 1;
  },
        valueOf() {
            return 2;
  }
}
console.log(String(obj)); // '1'

1. String()转换的本意是转化成字符串,所以首先去寻找toString()方法(没有就去参数数据类型的prototype找),如果toString()返回值是原始值,通过String(原始值)进行包装返回。

2. 如果toString()返回的是引用数据类型,就去寻找valueOf()方法,如果valueOf()方法返回值的是原始值就通过String(原始值)包装返回。

3. 如果valueOf()方法返回的是引用类型数据的值,那么报错。

1.3 隐式类型转换的场景

1.3.1 隐式类型转换涉及布尔转换

if()语句
switch()语句
for(;;)循环
while()循环
! !! && || 逻辑运算
?:三元运算

1.3.2

+(加法运算,拼接字符串) - * / %  ++a  a-- +a -a
== != >= <= > <
  
// 特例: undefined 和 null 谁都不等(针对于 == 来说)。
console.log(undefined == null); // true
console.log(NaN == NaN); // false  NaN代表的是一个类型的值,非数字


// 原始值转换 boolean number string
console.log(1 == true); // true  布尔值转为数值Number(boolean);
console.log('1' == true); // true 布尔值转为数值Number(boolean);字符串转为数值Number('1');
console.log('1' == 1); // 字符串转为数值Number(str);

// 引用类型值
console.log([] == ![]); 
// [] == false --> Number([]); --> '' == false --> Number('') == Number(false);
// true

console.log({} == !{}); 
// {} = false --> Number({}); --> '[object Object]' == false --> Number('[object Object]') == Number(false); 
// false

console.log([1] == 1); // true
console.log([1] == true); // true
console.log([] == false); // true