浅谈JavaScript 中的延迟加载属性模式
作者:飞奔的龟龟 发布时间:2024-04-17 10:29:56
一、前言
传统上,开发人员在 JavaScript 类中为实例中可能需要的任何数据创建属性。对于在构造函数中随时可用的小块数据来说,这不是问题。但是,如果在实例中可用之前需要计算某些数据,您可能不想预先支付该费用。例如,考虑这个类:
class MyClass {
constructor() {
this.data = someExpensiveComputation();
}
}
在这里,data
属性是作为执行一些昂贵计算的结果而创建的。如果您不确定是否会使用该属性,则预先执行该计算可能效率不高。幸运的是,有几种方法可以将这些操作推迟到以后。
二、按需属性模式
优化执行昂贵操作的最简单方法是等到需要数据后再进行计算。例如,您可以使用带有 getter 的访问器属性来按需进行计算,如下所示:
class MyClass {
get data() {
return someExpensiveComputation();
}
}
在这种情况下,直到有人第一次读取该data
属性时,您的昂贵计算才会发生,这是一种改进。但是,每次data
读取属性时都会执行相同的昂贵计算,这比之前的示例更糟糕,其中至少只执行了一次计算。这不是一个好的解决方案,但您可以在此基础上创建一个更好的解决方案。
三、凌乱的延迟加载属性模式
只有在访问属性时才执行计算是一个好的开始。您真正需要的是在该点之后缓存信息并仅使用缓存版本。但是您将这些信息缓存在哪里以便于访问?最简单的方法是定义一个具有相同名称的属性并将其值设置为计算数据,如下所示:
class MyClass {
get data() {
const actualData = someExpensiveComputation();
Object.defineProperty(this, "data", {
value: actualData,
writable: false,
configurable: false,
enumerable: false
});
return actualData;
}
}
在这里,该data
属性再次定义为类上的 getter,但这次它缓存了结果。调用Object.defineProperty()
创建一个名为的新属性data
,该属性具有固定值actualData
,并且设置为不可写、可配置和不可枚举(以匹配 getter)。之后,返回值本身。下次data
访问该属性时,它将从新创建的属性中读取而不是调用 getter:
const object = new MyClass();
// calls the getter
const data1 = object.data;
// reads from the data property
const data2 = object.data;
实际上,所有计算仅在第一次data
读取属性时完成。对该data
属性的每次后续读取都返回缓存的版本。
这种模式的一个缺点是data
属性开始是不可枚举的原型属性,最终是不可枚举的自己的属性:
const object = new MyClass();
console.log(object.hasOwnProperty("data")); // false
const data = object.data;
console.log(object.hasOwnProperty("data")); // true
虽然这种区别在很多情况下并不重要,但理解这种模式很重要,因为它在传递对象时可能会导致微妙的问题。幸运的是,使用更新的模式很容易解决这个问题。
四、类的唯一自己的延迟加载属性模式
如果您有一个用例,其中延迟加载的属性始终存在于实例中很重要,那么您可以使用Object.defineProperty()
在类构造函数中创建属性。它比前面的例子有点混乱,但它会确保该属性只存在于实例上。下面是一个例子:
class MyClass {
constructor() {
Object.defineProperty(this, "data", {
get() {
const actualData = someExpensiveComputation();
Object.defineProperty(this, "data", {
value: actualData,
writable: false,
configurable: false
});
return actualData;
},
configurable: true,
enumerable: true
});
}
}
在这里,构造函数data
使用Object.defineProperty()
.该属性是在实例上创建的(通过使用this
)并定义一个 getter 并指定该属性为可枚举和可配置的(典型的自己的属性)。将data
属性设置为可配置特别重要,以便您可以Object.defineProperty()
再次调用它。
然后 getter 函数进行计算并再次调用Object.defineProperty()
。该data
属性现在被重新定义为具有特定值的数据属性,并且不可写和不可配置以保护最终数据。然后,计算数据从 getter 返回。下次data
读取属性时,它将从存储的值中读取。作为奖励,该data
财产现在仅作为自己的财产存在,并且在第一次阅读之前和之后的行为都相同:
const object = new MyClass();
console.log(object.hasOwnProperty("data")); // true
const data = object.data;
console.log(object.hasOwnProperty("data")); // true
对于类,这很可能是您要使用的模式;另一方面,对象文字可以使用更简单的方法。
五、对象字面量的延迟加载属性模式
如果您使用对象字面量而不是类,则过程要简单得多,因为在对象字面量上定义的 getter 被定义为可枚举的自身属性(而不是原型属性),就像数据属性一样。这意味着您可以对类使用凌乱的延迟加载属性模式而对于对象来说不会凌乱:
const object = {
get data() {
const actualData = someExpensiveComputation();
Object.defineProperty(this, "data", {
value: actualData,
writable: false,
configurable: false,
enumerable: false
});
return actualData;
}
};
console.log(object.hasOwnProperty("data")); // true
const data = object.data;
console.log(object.hasOwnProperty("data")); // true
六、结论
在 JavaScript 中重新定义对象属性的能力提供了一个独特的机会来缓存可能计算成本很高的信息。通过从重新定义为数据属性的访问器属性开始,您可以将计算推迟到第一次读取属性时,然后缓存结果以供以后使用。这种方法既适用于类,也适用于对象字面量,并且在对象字面量中更简单一些,因为您不必担心您的 getter 会在原型上结束。
提高性能的最佳方法之一是避免重复执行相同的工作,因此任何时候您可以缓存结果以供以后使用,都可以加快程序的运行速度。延迟加载属性模式等技术允许任何属性成为缓存层以提高性能。
来源:https://www.cnblogs.com/nianzhilian/p/14900255.html


猜你喜欢
- 相信爬取大公司的数据时,常常会遇到页面信息动态加载的问题,如果仅仅使用content = urllib2.urlopen(URL).read
- pycharm全局修改pycharm 全局改函数方法1ctrl shift r全局替换方法2点击函数,右键 Refactor Ch
- 每次安装总是有些不同,这次用这种方式尝试一下,也记录一下。1、首先需要去下载rpm包:镜像地址:http://mysql.mirrors.p
- 最近在学习python,动手做了一个自动填写日报的小工具;由于请求中包含时间,格式如:2016-08-04;所以就了解了一下python的时
- 为最终用户提供的功能主要由一个HTML文件和两个ASP文件提供,它们负责接受用户的订阅申请以及退出邮件列表申请。 用户的个人信息在图1所示的
- 有台服务器,访问量挺大,每天近250w动态pv,数据库查询平均每秒近600次 另一台服务器,跑的程序跟这台一样,不过只有每天约40w动态pv
- 循环语句是一种常用的控制结构,在 Go 语言中,除了 for 关键字以外,还有一个 range 关键
- 一、概述索引太少,查询效率低;索引太多程序性能受到影响,索引的使用应该贴合实际情况。Innodb 支持的索引包括:全文检索,使用倒排索引哈希
- 要想在不宽裕的页面展现丰富的内容,现在通用的做法使用tab,在一块区域通过tab切换来更换该区域的内容。这篇文章分析了tab设计很在理,今天
- Function getIpvalue(clientIP)'得到客户端的IP转换成长整型,返回值getIpvalue&nb
- function checkPhoto(fnUpload) { var filename = fnUpload.value; alert(f
- 仿windows选项卡或叫做tabpan以及tabpage,现在还有最新的进展譬如仿淘宝网导航菜单效果皆属于此类:运行代码框<scri
- sympy版本:1.2假设求解矩阵方程AX=A+2X其中求解之前对矩阵方程化简为(A−2E)X=A令B=(A−2E)使用qtconsole输
- 到目前为止,我已经开发了两个HTML编辑器了,一个用在公司的CMS项目,另一个用在这个Blog(TidyEditor,暂时没有单独发布)。下
- 大家好,我是东哥。本篇和大家介绍一个经典的异常检测算法:局部离群因子(Local Outlier Factor),简称LOF算法。背景Loc
- 前情回顾在上一篇中,我们通过配置基本的信息,已经让我们的项目能够正常的跑起来了。但是,这里还没有涉及到 AJAX 请求接口的内容。vue 本
- 慢查询首先,无论进行何种优化,开启慢查询都算是前置条件。慢查询机制,将记录过慢的查询语句(事件),从而为DB维护人员提供优化目标。检查慢查询
- 使用threading写的一个定时器任务demo:import timeimport sysimport signalimport date
- 在进制学习时候,细心的小伙伴不免都发现unicher函数的存在,没错能够经常看到的,也就是关于进制的转化,那肯定有小伙伴要开心起来了,因为进
- 前言Python提供了多个内置模块用于操作日期时间,像 calendar,time,datetime。time模块提供的接口与C标准库 ti