当前位置: 首页 > 科技观察

JavaScript中的延迟加载属性

时间:2023-03-13 16:38:32 科技观察

本文转载自微信公众号《TianTianUp》,作者小毅。转载本文请联系天天向上公众号。大家好,我是天天。今天分享的内容是JavaScript中的懒加载属性模式。提高性能的最佳方法之一是避免重复相同的工作两次。所以只要你能缓存结果供以后使用,你就可以加速你的程序。LazyLoadedAttributes模式等技术使任何属性都可以成为缓存层以提高性能。这里提到的延迟加载属性模式是使用访问器属性将计算量大的操作推迟到需要的时候。场景有时您会在JavaScript类中创建属性,以保存实例中可能需要的任何数据。对于在构造函数中随时可用的小数据,这不是问题。但是,如果您需要在实例中可用之前计算一些大数据,您可能需要执行昂贵的计算操作。例如,考虑这个类:classMyClass{constructor(){this.data=someExpensiveComputation();}}这里,数据属性是通过执行一些昂贵的计算创建的。如果您不确定该属性是否会被使用,那么提前使用它可能不好而且效率低下。幸运的是,有几种方法可以推迟这些操作。接下来,主要围绕存取器属性展开。使用按需属性模式优化计算操作执行的最简单方法是等到需要数据时再执行计算。例如,您可以使用带有getter的数据属性来按需进行计算,如下所示:classMyClass{getdata(){returnsomeExpensiveComputation();}}操作发生,这是一个改进。但是,也存在每次读取数据属性时都执行相同的昂贵计算操作的问题,这比前面的示例(至少只执行一次计算)更糟糕。根据我们的分析,这不是一个好的解决方案,所以可以在此基础上创建更好的解决方案。仅在访问属性时执行计算的延迟加载属性模式是一个好的开始。你真正需要的是在那之后缓存信息,然后只使用缓存的数据结果。但是,有一个问题需要我们考虑,你把这些信息缓存到哪里方便访问呢?最简单的方法是定义一个具有相同名称的属性并将其值设置为计算数据,如下所示:,writable:false,configurable:false,enumerable:false});returnactualData;}}在这里,数据属性再次定义为类的getter,但这次它将缓存结果。调用Object.defineProperty()会创建一个名为data的新属性,该属性具有固定值actualData并设置为不可写、不可配置和可枚举。下次数据访问该属性时,它将从新创建的属性中读取,而不是调用getter:constobject=newMyClass();//callsthegetterconstdata1=object.data;//readsfromthedatapropertyconstdata2=object.data;事实上,所有的计算都是在第一次读取数据属性时才完成的。数据属性的每次后续读取都将返回缓存的版本。这种模式的缺点是data属性一开始是不可枚举的原型属性,最后是不可枚举的自身属性:constobject=newMyClass();console.log(object.hasOwnProperty("data"));//falseconstdata=object.data;console.log(object.hasOwnProperty("data"));//true虽然这种区别在很多情况下并不重要,但是理解这种模式很重要,因为在传递对象时,这种模式可能会导致细微的问题。幸运的是,我们可以使用下一个模式轻松解决这个问题。类的惰性加载属性如果您有一个实例,对于它而言,惰性加载属性的存在很重要,您可以使用Object.defineProperty()在类构造函数中创建该属性。它比前面的示例有点混乱,但它将确保该属性仅存在于实例上。这是一个例子:,configurable:false});returnactualData;},configurable:true,enumerable:true});}}从这个例子中我们可以发现构造函数使用Object.defineProperty()来创建数据访问器属性。该属性在实例上创建(使用this),定义一个getter并指定可枚举和可配置的属性。使数据属性可配置尤其重要,这样您就可以再次对其调用Object.defineProperty()。然后,getter函数进行计算并再次调用Object.defineProperty()。对于数据,将属性重新定义为具有特定值的数据属性,并使其不可写和不可配置,以保护最终数据。下次数据读取该属性时,将从存储的值中读取。data属性现在只作为它自己的属性存在,并且在第一次读取前后具有相同的效果:constobject=newMyClass();console.log(object.hasOwnProperty("data"));//trueconstdata=object.data;console.log(object.hasOwnProperty("data"));//true对于类,这很可能是您要使用的模式。另一方面,更简单的方法在对象模式下可用。延迟加载对象的属性如果您使用对象架构而不是类,则过程会简单得多,因为在对象架构上定义的getter被定义为可枚举的自身属性(而不是原型属性),就像数据属性一样。这意味着你可以为你的类使用延迟加载的属性模式而不会混淆:false,enumerable:false});returnactualData;}};console.log(object.hasOwnProperty("data"));//trueconstdata=object.data;console.log(object.hasOwnProperty("data"));//true总结通过将访问器属性重新定义为数据属性,您可以将计算推迟到第一次读取该属性时,然后缓存结果供以后使用。这种方法适用于类和对象字面量,并且在对象模式中更简单一些,因为您不必担心getter最终出现在原型上。