Javascript函数缓存的实现及应用场景
作者:前端青山
一、是什么
函数缓存,就是将函数运算过的结果进行缓存
本质上就是用空间(缓存存储)换时间(计算过程)
常用于缓存数据计算结果和缓存对象
const add = (a,b) => a+b; const calc = memoize(add); // 函数缓存 calc(10,20);// 30 calc(10,20);// 30 缓存
缓存只是一个临时的数据存储,它保存数据,以便将来对该数据的请求能够更快地得到处理
二、如何实现
实现函数缓存主要依靠闭包、柯里化、高阶函数,这里再简单复习下:
闭包
闭包可以理解成,函数 + 函数体内可访问的变量总和
(function() { var a = 1; function add() { const b = 2 let sum = b + a console.log(sum); // 3 } add() })()
add
函数本身,以及其内部可访问的变量,即 a = 1
,这两个组合在⼀起就形成了闭包
柯里化
把接受多个参数的函数转换成接受一个单一参数的函数
// 非函数柯里化 var add = function (x,y) { return x+y; } add(3,4) //7 // 函数柯里化 var add2 = function (x) { //**返回函数** return function (y) { return x+y; } } add2(3)(4) //7
将一个二元函数拆分成两个一元函数
高阶函数
通过接收其他函数作为参数或返回其他函数的函数
function foo(){ var a = 2; function bar() { console.log(a); } return bar; } var baz = foo(); baz();//2
函数 foo
如何返回另一个函数 bar
,baz
现在持有对 foo
中定义的bar
函数的引用。由于闭包特性,a
的值能够得到
下面再看看如何实现函数缓存,实现原理也很简单,把参数和对应的结果数据存在一个对象中,调用时判断参数对应的数据是否存在,存在就返回对应的结果数据,否则就返回计算结果
如下所示
const memoize = function (func, content) { let cache = Object.create(null) content = content || this return (...key) => { if (!cache[key]) { cache[key] = func.apply(content, key) } return cache[key] } }
调用方式也很简单
const calc = memoize(add); const num1 = calc(100,200) const num2 = calc(100,200) // 缓存得到的结果
过程分析:
在当前函数作用域定义了一个空对象,用于缓存运行结果
运用柯里化返回一个函数,返回的函数由于闭包特性,可以访问到
cache
然后判断输入参数是不是在
cache
的中。如果已经存在,直接返回cache
的内容,如果没有存在,使用函数func
对输入参数求值,然后把结果存储在cache
中
三、应用场景
虽然使用缓存效率是非常高的,但并不是所有场景都适用,因此千万不要极端的将所有函数都添加缓存
以下几种情况下,适合使用缓存:
对于昂贵的函数调用,执行复杂计算的函数
对于具有有限且高度重复输入范围的函数
对于具有重复输入值的递归函数
对于纯函数,即每次使用特定输入调用时返回相同输出的函数
new操作符具体干了什么?
一、是什么
在JavaScript
中,new
操作符用于创建一个给定构造函数的实例对象
例子
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.sayName = function () { console.log(this.name) } const person1 = new Person('Tom', 20) console.log(person1) // Person {name: "Tom", age: 20} t.sayName() // 'Tom'
从上面可以看到:
new
通过构造函数Person
创建出来的实例可以访问到构造函数中的属性new
通过构造函数Person
创建出来的实例可以访问到构造函数原型链中的属性(即实例与构造函数通过原型链连接了起来)
现在在构建函数中显式加上返回值,并且这个返回值是一个原始类型
function Test(name) { this.name = name return 1 } const t = new Test('xxx') console.log(t.name) // 'xxx' 可以发现,构造函数中返回一个原始值,然而这个返回值并没有作用 下面在构造函数中返回一个对象 function Test(name) { this.name = name console.log(this) // Test { name: 'xxx' } return { age: 26 } } const t = new Test('xxx') console.log(t) // { age: 26 } console.log(t.name) // 'undefined'
从上面可以发现,构造函数如果返回值为一个对象,那么这个返回值会被正常使用
二、流程
从上面介绍中,我们可以看到new
关键字主要做了以下的工作:
创建一个新的对象
obj
将对象与构建函数通过原型链连接起来
将构建函数中的
this
绑定到新建的对象obj
上根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理
举个例子:
function Person(name, age){ this.name = name; this.age = age; } const person1 = new Person('Tom', 20) console.log(person1) // Person {name: "Tom", age: 20} t.sayName() // 'Tom'
三、手写new操作符
现在我们已经清楚地掌握了new
的执行过程
那么我们就动手来实现一下new
function mynew(Func, ...args) { // 1.创建一个新对象 const obj = {} // 2.新对象原型指向构造函数原型对象 obj.__proto__ = Func.prototype // 3.将构建函数的this指向新对象 let result = Func.apply(obj, args) // 4.根据返回值判断 return result instanceof Object ? result : obj }
测试一下
function mynew(func, ...args) { const obj = {} obj.__proto__ = func.prototype let result = func.apply(obj, args) return result instanceof Object ? result : obj } function Person(name, age) { this.name = name; this.age = age; } Person.prototype.say = function () { console.log(this.name) } let p = mynew(Person, "huihui", 123) console.log(p) // Person {name: "huihui", age: 123} p.say() // huihui
可以发现,代码虽然很短,但是能够模拟实现new
到此这篇关于Javascript函数缓存的实现及应用场景的文章就介绍到这了,更多相关Javascript函数缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!