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
}
})
Source Code Reading for Vue 3: How does `hasChanged` work?的更多相关文章
- Tips for newbie to read source code
This post is first posted on my WeChat public account: GeekArtT Reading source code is always one bi ...
- Memcached source code analysis (threading model)--reference
Look under the start memcahced threading process memcached multi-threaded mainly by instantiating mu ...
- Learning from the CakePHP source code - Part I
最近开始痛定思痛,研究cakephp的源码. 成长的路上从来没有捷径,没有小聪明. 只有傻傻的努力,你才能听到到成长的声音. 下面这篇文章虽然过时了,但是还是可以看到作者的精神,仿佛与作者隔着时空的交 ...
- Spring 4 MVC example with Maven - [Source Code Download]
In this tutorial, we show you a Spring 4 MVC example, using Maven build tool. Technologies used : Sp ...
- Troubles in Building Android Source Code
Some Troubles or problems you may encounter while you setup the Android source code build environmen ...
- Finding Comments in Source Code Using Regular Expressions
Many text editors have advanced find (and replace) features. When I’m programming, I like to use an ...
- Website's Game source code
A Darkroom by doublespeakgames <!DOCTYPE html> <html itemscope itemtype="https://schem ...
- 编程等宽字体Source Code Pro(转)
Source Code Pro - 最佳的免费编程字体之一!来自 Adobe 公司的开源等宽字体下载 每一位程序员都有一套自己喜爱的代码编辑器与编程字体,譬如我们之前就推荐过一款"神 ...
- How to build the Robotics Library from source code on Windows
The Robotics Library is an open source C++ library for robot kinematics, motion planning and control ...
随机推荐
- ListIterator特有的方法
import java.util.ArrayList; import java.util.List; import java.util.ListIterator; /* 迭代 listIterator ...
- 第10讲:Flink Side OutPut 分流
Flink系列文章 第01讲:Flink 的应用场景和架构模型 第02讲:Flink 入门程序 WordCount 和 SQL 实现 第03讲:Flink 的编程模型与其他框架比较 第04讲:Flin ...
- epoll反应堆模型实现
epoll反应堆模型demo实现 在高并发TCP请求中,为了实现资源的节省,效率的提升,Epoll逐渐替代了之前的select和poll,它在用户层上规避了忙轮询这种效率不高的监听方式,epoll的时 ...
- 使用docker部署canal
文章目录 mysql开启binlog mysql创建canal用户 启动canal容器 配置canal 启动canal容器 查看docker容器日志 canal-client 验证 关于canal m ...
- NSSCTF-easyupload1.0
2.0和3.0已经说过,这个1.0上传也可以使用那两个题目的做法,就是使用htaccess的方式进行定义上传文件的类型来进行连接shell,1.0肯定是没有2.0和3.0难的,所以说,也不要将这个题目 ...
- 关于 Word2Vec 使用时遇到的一系列问题!!
1 训练时 model = Word2Vec(x, size=250, window=5, min_count=5, workers=12, iter=10, sg=1) 这句代码一直报错 查了 ...
- RIP协议测试——信而泰网络测试仪实操
一.简介: RIP(Routing Information Protocol,路由信息协议)是一种内部网关协议(IGP),是一种动态路由选择协议,用于自治系统(AS)内的路由信息的传递.RIP协议基于 ...
- C#索引器-有参属性
总结 只要类中有类似于属性的元素就应创建索引器,此属性代表的不是一个值,而是值的集合,其中每一个项由一组参数标识. 这些参数可以唯一标识应引用的集合中的项. 索引器延伸了属性的概念,索引器中的一个成员 ...
- SyntaxError: keyword can't be an expression
创建字典对象时: D1=dict('name'='Bob','age'=20,'score'=90) SyntaxError: keyword can't be an expression 解决方法: ...
- MySQL:输入密码后闪退的解决方法
原因:MySQL服务没有启动 解决方法:在 "服务" 中启动MySQL