Source Code Reading for Vue 3: How does `hasChanged` work?
Hey, guys! The next generation of Vue has released already. There are not only the brand new composition API, much more powerful and flexible reactivity system, first-class render function, but also the natural performance with building off the modern browsers.
There have been tens of hundreds of posts and tutorials which are about Vue 3 and source code analysis even. This series is about the source code reading, but includes the related technology explanations. If it's your jam, please stay tune;)
As the first post of this series, it might be nice to nibble a small part of the great Vue 3 pie. hasChanged
is used to compare whether a value has changed accounting for NaN
, and is leveraged in trigger
function to avoid unnecessary effect function re-running, which locates in vue/@shared
. And the source code snippet is as below:
export const hasChanged = (value: any, oldValue: any): boolean => {
return !Object.is(value, oldValue)
}
How simple it is. But what is Object.is
?
What is Object.is
for?
Object.is
method came from ES6 and is capable of determining whether two values are the same. Two values are the same if the one of the following holds:
- both
undefined
- both
null
- both
string
s of the same length with the same characters in the same order - both
true
or bothfalse
- both
object
s reference to the same memory address allocated in heap - both
number
s and- both
-0
or both+0
- both
NaN
- both non-zero and both not
NaN
and both have the same value
- both
As we know, loose equality operator(==
) applies various coercions to both sides if they are not the same type, before testing for equality. But Object.is
doesn't coerce either value.
And the difference between strict equality operator(===
) and Object.is
is in their treatment of signed zero and NaN
s.
NaN
a Special Value for Loose and Strict Equality
NaN
stands for Not a Number, and the comparison between two NaN
value by loose or strict equality will result in false
always. We can determine whether a value is NaN
by calling x !== x
.
However window.isNaN
came up from ES5 does us a favor for determining whether a value is type of NaN
in some point. But there is a way important and subtle detail that we would ignore. That is doing type conversion before comparison as below
isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
isNaN(null) //false
So when we want to compare whether a value has changed accounting for NaN
as Vue 3, we should author as below
function hasChanged(x, y) {
x !== y
&& !(typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y))
}
Since window.isNaN
will coerce its argument to type of Number
first before comparison, and we have to take some effect to build our own strict isNaN
. Fortunately, the so-called strict isNaN Number.isNaN
has came up in ES6, and with the help of it, the above code snippet could be simplified into hasChanged = (x, y) => x !== y && !(Number.isNaN(x) && Number.isNaN(y))
Actually we can get the same result without window.isNaN
and Number.isNaN
in a much leaner manner. Because there is only a possible for a value to not be strictly equal to itself when a value evaluates to NaN
.
function hasChanged(x, y) {
x !== y
&& !(x !== x && y !== y)
}
Strictly Speaking, +0
and -0
are different
As a common sense, +0
and -0
are the same value, but it's not true in JavaScript. For example, the following integer division expression will raise an error in Java
int i = 1;
int positiveZero = +0;
int result1 = i / positiveZero; // raise an ArithmeticException
However, JavaScript is a dynamic type programming language which acts as doing double division as Java for the above example.
1/+0 === 1/0 === Infinity
1/-0 === -Infinity
But +0
and -0
are the same comparing with strict equality operator.
Build your own Object.is
For now, we have known all about the features of Object.is
and the differences between it and the loose/strict equality operators. Let's rollup our sleeve to build an own one.
Object.defineProperty(Object, 'is', {
value(x, y) {
return x === y
? 1 / x === 1 / y // +0 != -0
: x !== x && y !== y // NaN == NaN
}
})
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的