关于js中对象类型的隐式转换

昨天在 @木易杨说 面试题整理看到这样一道题目,觉得非常有意思,今天一大早看了大家讨论出来的答案之后,不得不佩服一些人的思路,于是自己就整理了这篇文章对其中涉及的原理进行一下梳理总结。

// 下面代码中 a 在什么情况下会打印1
var a = ?;
if(a == 1 && a == 2 && a == 3){
 	console.log(1);
}
复制代码

在讨论区看到了很多答案,许多答案也值得去思考。

// 解法一: 利用 toString
let a = {
    i: 1,
    toString () {
    return a.i++
    }
}
if(a == 1 && a == 2 && a == 3) {
    console.log(1);
}
// 解法二: 利用 valueOf
let a = {
    i: 1,
    valueOf () {
    return a.i++
    }
}
if(a == 1 && a == 2 && a == 3) {
    console.log(1);
}
// 解法三: 
var a = [123];
var index = 0;
a.toString = function(){
    return this[index++]
}
if(a == 1 && a == 2 && a == 3) {
    console.log(1);
}
// 解法四: 利用数组
var a = [123];
a.join = a.shift;
if(a == 1 && a == 2 && a == 3) {
    console.log(1);
}

// 解法五: 利用 Object.defineProperty
Object.defineProperty(window'a', {
    get: function() {
        return this.value = this.value ? (this.value += 1) : 1;
    }
});

// 解法六: 利用symbol
let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};
if(a == 1 && a == 2 && a == 3) {
    console.log(1);
}
复制代码

比较操作

在比较操作涉及到不同类型值时,会涉及到隐式转换,其中存在着很多规则需要去记忆,那我们就根据这道题目去探讨一下其中涉及到的规则。

对象 和 原始类型值 比较

如果对象和原始类型的值比较,那么对象会转换为原始类型的值,再进行比较。 在转换的时候,会首先访问对象的 valueOf 方法,若返回值是 原始值类型,则转换为该值;否则,会调用对象的 toString 方法,若返回值是 原始值类型,则转换为该值,否则报错。

也就是说,通过 valueOf 或者 toString 将对象隐式转换成原始值的时候, 会调用 valueOf ,再调用 toString ,若两个方法都不能得到原始值,则报错。

valueOf 和 toString

默认情况下,两个方法都会被每个Object对象继承,也就是说每个对象都具有这两种方法,但是我们可以通过重写方法,来覆盖该对象原始的valueOftoString方法。前两种答案就是利用这种方式实现的。

不同类型对象的valueOf()方法的返回值
对象返回值返回值类型
Array返回数组对象本身。Array
Boolean布尔值。boolean
Date存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。number
Function函数本身。Object
Number数字值。number
Object对象本身。这是默认情况。Object
String字符串值。string
Math 和 Error 对象没有 valueOf 方法。
// Array:返回数组对象本身
var array = ["ABC"true12-5];
console.log(array.valueOf()); // ["ABC", true, 12, -5]
console.log(array.valueOf() === array);   // true

// Date:当前时间距1970年1月1日午夜的毫秒数
var date = new Date(2013718231159230);
console.log(date.valueOf());   // 1376838719230

// Number:返回数字值
var num =  15.26540;
console.log(num.valueOf());   // 15.2654

// 布尔:返回布尔值true或false
var bool = true;
console.log(bool.valueOf());   // true

// new一个Boolean对象
var newBool = new Boolean(true);
// valueOf()返回的是true,两者的值相等
console.log(newBool.valueOf() == newBool);   // true
// 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型
console.log(newBool.valueOf() === newBool);   // false

// Function:返回函数本身
function foo(){}
console.log( foo.valueOf() === foo );   // true
var foo2 =  new Function("x""y""return x + y;");
console.log( foo2.valueOf() );
/*
ƒ anonymous(x,y
) {
return x + y;
}
*/

// Object:返回对象本身
var obj = {name: "张三", age: 18};
console.log(obj.valueOf()); // {name: "张三", age: 18} 依然是对象类型
console.log( obj.valueOf() === obj );   // true

// String:返回字符串值
var str = "https://www.baidu.com/";
console.log( str.valueOf());   // https://www.bufanui.com/

// new一个字符串对象
var str2 = new String("https://www.baidu.com/");
// 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型
console.log( str2.valueOf() === str2 );   // false
复制代码
不同类型对象toString()方法的返回值

默认情况下,toString() 返回 "[object type]",其中type是对象的类型。那也就是说,我们可以通过toString()检测对象类型。

var o = new Object();
o.toString(); // returns [object Object]

var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
复制代码
数组 和 原始类型值 比较

我们知道 数组也属于对象,应该和对象的规则一样.(见解法三)

除此以外,对于数组对象,toString 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。 也就是说,我们可以通过修改数组的join方法,来达到目的。(解法四)

原始类型值 和 原始类型值 比较
  • 如果两个操作数都为数值,那么执行数值比较
  • 如果两个操作数都为字符串,那么比较两个字符串对应的字符串编码
  • 如果一个操作数为数值,那么将另一个操作数转换为数值,执行数值比较
  • 如果一个操作数为布尔值,那么将这个操作数转换为数值(true为1,false为0),执行数值比较

写到这里,突然发现了以下两篇文章,让我对 ToPrimitive 有了了解,才发现自己对隐式转换的理解还有待提高。原来认为这些总结记忆一下就可以了,却没想到一个对象类型的转换就这么值得深究。

对于那些这方面知识像我一样有欠缺的同学,强烈建议你们看一看上面两篇文章,一定会有所收获。

转载于:https://juejin.im/post/5c94506d6fb9a070b96f0b8c

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript ,显示类型转换隐式类型转换也是两种不同的类型转换方式。 1. 显示类型转换:在 JavaScript ,可以使用一些内置函数或操作符来进行显示类型转换。以下是一些常见的显示类型转换操作: - 使用 Number() 函数将值转换为数值类型。 - 使用 String() 函数将值转换为字符串类型。 - 使用 Boolean() 函数将值转换为布尔类型。 - 使用 parseInt() 或 parseFloat() 函数将字符串转换为数值类型。 - 使用 toString() 方法将数值或对象转换为字符串类型。 2. 隐式类型转换JavaScript 隐式类型转换是在表达式计算、赋值操作和比较运算等过程自动发生的。这些隐式转换是根据 JavaScript 强制类型转换的规则和规范进行的。以下是一些常见的隐式类型转换场景: - 字符串和数值之间的加法运算会将数值隐式转换为字符串并进行字符串拼接。 - 比较运算符(如 ==、>、< 等)会进行隐式类型转换来比较不同类型的值。 - 逻辑运算符(如 &&、|| 等)会根据 JavaScript 的真值表进行隐式类型转换来确定结果。 需要注意的是,JavaScript隐式类型转换有时可能会导致意外的结果,因此在编写代码时应当注意类型转换的规则,避免产生不可预料的行为。同时,在需要明确类型转换的情况下,建议使用显示类型转换来提高代码的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值