[译]JavaScript响应式的最佳解释

栏目: JavaScript · 发布时间: 6年前

内容简介:原文地址:许多前端JavaScript框架(例如Angular,React和Vue)都有自己的Reactivity引擎。通过了解响应式及其工作原理,您可以提高开发技能并更有效地使用JavaScript框架。在视频和下面的文章中,我们构建了您在Vue源代码中看到的相同类型的Reactivity。当你第一次看到它时,Vue的响应式系统看起来很神奇。拿这个简单的Vue应用程序来说:

原文地址: The Best Explanation of JavaScript Reactivity

许多前端JavaScript框架(例如Angular,React和Vue)都有自己的Reactivity引擎。通过了解响应式及其工作原理,您可以提高开发技能并更有效地使用JavaScript框架。在视频和下面的文章中,我们构建了您在Vue源代码中看到的相同类型的Reactivity。

:bulb:响应式系统

当你第一次看到它时,Vue的响应式系统看起来很神奇。拿这个简单的Vue应用程序来说:

[译]JavaScript响应式的最佳解释
[译]JavaScript响应式的最佳解释
不知何故 Vue 只是知道如果 price

改变,它应该做三件事:

  • 更新网页上 price 的值。
  • 重新计算乘法表达式 price * quantity ,并更新页面。
  • 再次调用函数 totalPriceWithTax 并更新页面。 但是等等,你是否会好奇,Vue如何知道 price 更改时所要更新的内容,以及它如何跟踪所有内容?
    [译]JavaScript响应式的最佳解释
    这并不是JavaScript通常的工作方式

我们解决一个大问题是通常不会这样编程。例如,如果我运行如下代码:

[译]JavaScript响应式的最佳解释

你觉得它打印什么?由于我们没有使用Vue,它将打印出来 10

[译]JavaScript响应式的最佳解释

在Vue中,我们希望 total 随着 pricequantity 更新而更新。我们想要:

[译]JavaScript响应式的最佳解释

不幸的是,JavaScript是程序性的,而不是响应式的,所以这在现实中不起作用。为了实现 total 响应,我们必须使用JavaScript来使事情表现得与众不同。

:warning: 问题

我们需要保存如何计算得到 total ,这样可以在 pricequantity 更新时重新运行它,

:white_check_mark: 解决方案

首先,需要一些方法告诉我们的应用程序,“我即将运行的代码, 存储它 ,我可能需要在其他时间运行它。”然后我们开始运行代码,如果 pricequantity 变量得到更新,再次运行存储的代码。

[译]JavaScript响应式的最佳解释

我们可以通过记录函数来执行此操作,以便我们可以再次运行它。

[译]JavaScript响应式的最佳解释
请注意 ,我们在 target 变量中存储了一个匿名函数,然后调用一个 record

函数。使用ES6箭头语法我也可以这样写:

[译]JavaScript响应式的最佳解释
这个 record

函数定义很简单:

[译]JavaScript响应式的最佳解释
我们正在存储 target (在我们的例子中 { total = price * quantity } ),所以我们可以稍后运行它,可以通过一个 replay

函数来运行存储的所有内容。

[译]JavaScript响应式的最佳解释
这将遍历执行 storage

数组中存储的所有匿名函数。 然后在代码中,我们可以:

[译]JavaScript响应式的最佳解释

很简单吧?如果您需要阅读并尝试再次理解它,这里有完整的代码,仅供参考,如果您想知道原因,我会以特定的方式对此进行编码。

[译]JavaScript响应式的最佳解释
[译]JavaScript响应式的最佳解释

:warning: 问题

我们可以根据需要继续记录 target ,但是有一个更强大的解决方案可以扩展我们的应用程序。一个负责维护 target 列表的类,当需要它们重新运行时,这些 target 列表会得到通知。

:white_check_mark: 解决方案:依赖类

我们解决这个问题的一种方法是将这种行为封装到它自己的类中,这是一个实现标准观察者模式的依赖类。

因此,如果我们创建一个JavaScript类来管理我们的依赖项(它更接近Vue的处理方式),它可能看起来像这样:

[译]JavaScript响应式的最佳解释
请注意 ,我们现在存储匿名函数是 subscribers 而不是 storage 。我们现在调用的函数是 depend 而不是 record ,我们现在使用 notify 而不是 replay

。为了让这个运行:

[译]JavaScript响应式的最佳解释
它仍然有效,现在的代码感觉更可重用。唯一仍然感觉有点奇怪的是设置和运行 target

:warning: 问题

我们将为每个变量设置一个 Dep 类,并且很好地封装了创建需要监视更新的匿名函数的行为。也许一个 watcher 函数可能是为了处理这种行为。

所以不要这样调用:

[译]JavaScript响应式的最佳解释

(这只是上面的代码) 我们可以改为:

[译]JavaScript响应式的最佳解释

:white_check_mark: 解决方案:观察者函数

在我们的 Watcher 函数中,我们可以做一些简单的事情:

[译]JavaScript响应式的最佳解释
如您所见,该 watcher 函数接受一个 myFunc 参数,将其设置为全局 target 属性,调用 dep.depend()target 添加到订阅者 subscriber ,执行 target 函数,然后重置 target

函数。

现在,当我们运行以下内容时:

[译]JavaScript响应式的最佳解释
[译]JavaScript响应式的最佳解释

您可能想知道为什么我们将target设为全局变量,而不是将其传递到我们需要的函数中。这将在我们的文章结尾处解释。

:warning: 问题

我们有一个单独的 Dep class ,但我们真正想要的是每个变量都有自己的 Dep 。在继续之前,将数据设为对象属性。

[译]JavaScript响应式的最佳解释
假设每个属性( pricequantity )都有自己的内部 Dep

类。

[译]JavaScript响应式的最佳解释

现在我们执行时:

[译]JavaScript响应式的最佳解释
由于访问了 data.price 的值,我希望 price 属性的 Dep 类将存储在 target 的匿名函数推送到其 subscriber 数组(通过调用 dep.depend() )。由于 data.quantity 被访问,我还希望 quantity 属性 Dep 类将存储在 target 的匿名函数推送到其 subscriber

数组中。

[译]JavaScript响应式的最佳解释
如果我有另一个匿名函数,只是 data.price 被访问,我希望它只是推送到 price 属性 Dep

类。

[译]JavaScript响应式的最佳解释
pricesubscribers 什么时候调用 dep.notify() ?我希望在 price

设置时调用它们。在文章的最后,我希望能够进入控制台并执行:

[译]JavaScript响应式的最佳解释
我们需要一些方式来挂钩数据属性(如 pricequantity ),所以当它被访问时,我们可以保存 target 到我们的 subscribers 数组中,当它被更改时,运行存储在 subscribers

数组中的函数。

:white_check_mark: 解决方案:Object.defineProperty()

我们需要了解 Object.defineProperty() 函数,它是简单的ES5 JavaScript。它允许我们为属性定义 gettersetter 函数。在我向您展示如何在 Dep 类中使用它之前,将向您展示最基本的用法。

[译]JavaScript响应式的最佳解释
[译]JavaScript响应式的最佳解释

如您所见,它只记录两行。但是,它实际上没有 getset 任何值,因为我们过度使用了该功能。我们现在加回来吧。 get() 期望返回一个值, set() 仍然需要更新一个值,所以让我们添加一个 internalValue 变量来存储我们当前的 price 值。

[译]JavaScript响应式的最佳解释

既然我们的 getset 工作正常,您认为将打印到控制台的是什么?

[译]JavaScript响应式的最佳解释
因此,当我们 getset

值时,我们可以获得通知。通过一些递归,我们可以为数据数组中的所有项运行它,对吧?

Object.keys(data) 返回对象键的数组。

[译]JavaScript响应式的最佳解释

现在一切都有 gettersetter ,我们在控制台上看到了这一点。

[译]JavaScript响应式的最佳解释

将两种想法放在一起

[译]JavaScript响应式的最佳解释
当像这样的一段代码运行并 get price 值时,我们想要 price 记住这个匿名函数 (target) 。这样,如果 price 被更改,或者 set

为新值,它将触发此函数以重新运行,因为它知道此行依赖于它。

Get=>记住当前匿名函数,当我们的值发生变化时,会再次运行它。

Set=>运行保存的匿名函数,我们的值随之改变。

或者就我们的 Dep Class 而言

Price accessed (get)=>调用 dep.depend() 以保存当前 target

Price set=>调用 dep.notify()price ,重新运行全部 targets

让我们结合这两个想法,并完成我们的最终代码。

[译]JavaScript响应式的最佳解释

现在看看我们执行时会发生什么。

[译]JavaScript响应式的最佳解释

正是我们所希望的! pricequantity 确实都响应了!每当值 pricequantity 更新时,全部的代码都会重新运行。

Vue文档中的这个插图现在应该开始有意义了。

[译]JavaScript响应式的最佳解释

你看到那个美丽的紫色数据圈 getters and setters 了吗?看起来应该很熟悉!每个组件实例都有一个 watcher 实例(蓝色),它从 getter (红线)收集依赖项。稍后调用 setter 时,它会 通知 watcher 导致组件重新渲染。注释之后的图如下。

[译]JavaScript响应式的最佳解释

是的,这现在不是更有意义吗?

显然,Vue如何做到这一点更复杂,但你现在知道了基础知识。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Web Application Hacker's Handbook

The Web Application Hacker's Handbook

Dafydd Stuttard、Marcus Pinto / Wiley / 2011-9-27 / USD 50.00

The highly successful security book returns with a new edition, completely updated Web applications are the front door to most organizations, exposing them to attacks that may disclose personal infor......一起来看看 《The Web Application Hacker's Handbook》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具