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
?
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:
undefined
null
string
s of the same length with the same characters in the same ordertrue
or both false
object
s reference to the same memory address allocated in heapnumber
s and-0
or both +0
NaN
NaN
and both have the same valueAs 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
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)
}
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.
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
}
})
手机扫一扫
移动阅读更方便
你可能感兴趣的文章