函数缓存,就是将函数运算过的结果进行缓存
本质上就是用空间(缓存存储)换时间(计算过程)
常用于缓存数据计算结果和缓存对象
- 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) // 缓存得到的结果
过程分析:
虽然使用缓存效率是非常高的,但并不是所有场景都适用,因此千万不要极端的将所有函数都添加缓存
以下几种情况下,适合使用缓存:
在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'
从上面可以看到:
现在在构建函数中显式加上返回值,并且这个返回值是一个原始类型
- 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关键字主要做了以下的工作:
举个例子:
- 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
- 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。