Vue3源代码阅读:“hasChanged”是如何工作的?

嘿,伙计们!下一代Vue已经发布。不仅有全新的合成API,更强大和灵活的反应系统,一流的渲染功能,而且还有构建现代浏览器的自然性能。

关于VUE3和源代码分析的帖子和教程已经有上百篇。本系列是关于源代码阅读的,但包括相关的技术说明。如果是你的问题,请保持沉默。

作为本系列的第一篇文章,不妨细细品味一下Vue 3的一小部分。HasChanged用于比较某个值是否发生了变化,以说明NaN,并利用trigger 函数避免不必要的影响函数重新运行,该函数位于[email protected]。源代码片段如下所示:

export const hasChanged = (value: any, oldValue: any): boolean => {
    return !Object.is(value, oldValue)
}

这是多么简单。但Object.is是什么?

Object.is是什么?

Object.is方法来自ES6,能够确定两个值是否相同。如果满足以下条件之一,则两个值相同:

  • 两个都是undefined
  • 两个都是null
  • 两个长度相同、字符顺序相同的string
  • 两个都是true或者都是false
  • 两个object对象都引用堆中分配的相同内存地址
  • 两个值是number
    • 都是-0或者都是+0
    • 都是NaN
    • 都是非零和非NaN都具有相同的值

正如我们所知,相等运算符(==)在测试相等性之前,如果两侧的类型不同,则会对它们应用各种强制。但是Object.is不强制任何一个值。

严格相等运算符(==)和Object.is之间的区别在于它们对有符号零和NaN的处理。

NaN是相等和严格相等的特殊值

NaN代表非数字,两个NaN值之间通过相等或严格相等进行比较将导致错误。我们可以通过调用x!==x来确定值是否为NaN

然而,来自ES5的window.isNaN有助于我们确定某个点上的值是否为NaN类型。但有一种方式是我们可以忽略的重要而微妙的细节。这就是在比较之前进行类型转换,如下所示

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

因此,当我们想要比较一个值是否已经改变,将NaN解释为Vue 3时,我们应该编写如下代码:

function hasChanged(x, y) {
    x !== y
    && !(typeof x === 'number' && isNaN(x) && typeof y === 'number' && isNaN(y))
}

因为window.isNaN会在比较之前首先将其参数强制为数字类型,所以我们必须采取一些措施来构建自己的严格isNaN。幸运的是,ES6中出现了所谓的严格 isNaN Number.isNaN,在它的帮助下,上面的代码片段可以简化为 hasChanged = (x, y) => x !== y && !(Number.isNaN(x) && Number.isNaN(y))

实际上,不用window.isNaNNumber.isNaN,我们可以以更精简的方式获得相同的结果。因为当一个值的计算结果为NaN时,只有一个值可能不严格等于它本身。

function hasChanged(x, y) {
    x !== y
    && !(x !== x && y !== y)
}

严格地讲,+0和-0是不同的

根据常识,+0-0是相同的值,但在JavaScript中并非如此。例如,以下整数除法表达式将在Java中引发错误:

int i = 1;
int positiveZero = +0;

int result1 = i / positiveZero; // raise an ArithmeticException

然而,JavaScript是一种动态类型编程语言,在上面的示例中,它与Java一样进行双重划分。

1/+0 === 1/0 === Infinity
1/-0 === -Infinity

但是+0-0与严格相等运算符相比是相同的。

构建自己的Object.is

现在,我们已经了解了Object.is的所有特性以及它与相等/严格相等运算符之间的区别。让我们撸起袖子,构建自己的Object.is

Object.defineProperty(Object, 'is', {
    value(x, y) {
        return x === y
            ? 1 / x === 1 / y // +0 != -0
            : x !== x && y !== y // NaN == NaN
    }
})

「点点赞赏,手留余香」

1

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:
1. 本站所有文章教程及资源素材均来源于网络与用户分享或为本站原创,仅限用于学习和研究。
2. 如果内容损害你的权益请联系客服QQ:1642748312给予处理。
码云笔记 » Vue3源代码阅读:“hasChanged”是如何工作的?

发表评论

IT互联网行业相关广告投放 更专业 更精准

立即查看 联系我们