前言
平时我们比较大小的时候都是直接使用对应的比较富豪>、<、== 等操作符号进行比较,并且平时比较的最常见的就是数字之间的比较了,甚至稍微多一点点的就是数字、字符串之间的被动比较了
那么问题来了,如果我们想主动比较两个对象的大小该怎么比较呢,怎么正确的书写呢
实际上我们的对象之间的比较,某种程度上像运算符重载,实际上以面向对象的角度,需要比较值的时候,调用对应的获取值的函数来进行比较(所谓的隐式类型转换也是这个逻辑,具体的可以点进去看看)
对象的比较
对象之间比较,必定要将对象转化为能比较的值的形式,一般是数字、字符串
一个对象若要参与比较,需要进行隐式转换,因此要经过一系列执行一系列方法执行,分别是 [Symbol.toPrimitive]、valueOf、toString,他们需要返回原始值(数字、字符串、boolean等)
其中 [Symbol.toPrimitive] 是 ES6 对象转原始的标准方法,在比较转化为值的时候,第一个调用的就是他,效率最高,也最推荐
js
const obj = {
[Symbol.toPrimitive]: function () {
return 'toPrimitive'
},
valueOf: function () {
return "valueOf";
},
toString: function () {
return "toString";
},
};
分别取消注释,则会返回 toPrimitive1、valueOf1、toString1
console.log(obj + 1);
//如果是数字,则按照数字使用
const obj = {
[Symbol.toPrimitive]: function () {
return 2
},
};
const obj1 = {
[Symbol.toPrimitive]() {
return 3
},
};
//返回 5 这下应该明白了
console.log(obj + obj1);
当然我们可能觉得 valueOf 好像也挺符合语义的,用也没问题,但效率没有 [Symbol.toPrimitive]高,切js现在的隐式操作一般比较推荐使用Symbol,因为他基本不会被后续声明的属性不小心污染(尤其是新手,光这一点就足够了,毕竟一个新手找这种bug,还是很头疼的,甚至有时候无从下手的感觉😄)
扩展思考面向对象与深拷贝
对象的大小比较知道了,如果理解了,相信更能理解面向对象的思维了,假如让你深拷贝一个复杂对象,你打算怎么做简化操作呢,可以参考上面逻辑
平时网上看到的js对象深拷贝,逻辑比较简单统一,实际上单纯就是copy一个json对象罢了(甚至有时候还会专门多出来一个什么Date、RegExp之类,都是多余的)
如果要copy一些复杂对象,一定是不符合条件的,为什么这么说
例如:我要copy城市对象,城市对象里面分别有区、街道,区和街道分别都有住宅、屋子,区和街道,可能用同一个类,这是一个错综复杂的对象,里面各种类型的都会有,你怎么设计呢
方案:我们从面向对象的思维考虑,我们不管对象复杂不复杂,只要是我们自定义声明的对象,我们都重写一个clone的方法,只要调用clone的方法,就会创建一个新的自己,并且将基础类型都赋值,自定义对象只需要调用该对象的clone函数就行了,这样只要每一个支持深拷贝的对象都实现该函数,那么我们克隆的时候只需要一个简单的clone就能克隆出一个完整的大对象了
上面的方案又用到哪些设计模式呢,哈哈,实际开发中本身就是设计模式的大杂烩,也不会拘泥一种设计模式
最后
相信看了这篇,如果没有接触过面向对象的,现在已经开始有点喜欢面向对象了,其能将一个复杂的事情分摊到每一个对象身上,接口与实现,继承与多态,这也是我们面向对象中习以为常的操作,这种思维能帮助我们解决更复杂的问题
随口提一下,js中集合的枚举呢,有想到什么情况,是否随便一个对象只要实现了某一个固定接口,就能实现枚举了呢😄
本篇文章就到这里了,拜拜