美文网首页
JS专题系列之惰性函数与记忆函数

JS专题系列之惰性函数与记忆函数

作者: DY_alley | 来源:发表于2021-06-21 23:03 被阅读0次

一、惰性函数

惰性函数:顾名思义就是懒惰的函数,举一个简单的例子,如果我们需要判断当前浏览器是哪一种浏览器,我们需要封装一个函数,根据判断来进行返回浏览器类型,但是如果你在同一个浏览器中调用2次这个函数,那么这个函数中就需要做2次判断。其实这是一种无用的性能消耗,因此我们的惰性函数就登场了

原理:根据第一次调用的判断重写当前函数

function getStyle(obj,attr){
  if(obj.currentStyle) {
    return obj.currentStyle[attr]
  } else {
    return getComputedStyle(obj,false)[attr];
  }
}

上述方法我们知道用来获取元素的属性值,但是问题是我们每次调用该函数都要进行一次判断,如果在同一个浏览器中连续调用2次,每次都进行一次判断明显这是无用功,因此我们可以根据惰性函数原理进行优化

function getStyle(obj,attr){
  if(obj.currentStyle) {
    getStyle = function(obj,attr) {
      return obj.currentStyle[attr]
    }
  } else {
    getStyle = function(obj,attr) {
      return getComputedStyle(obj,false)[attr];
    }
  }
  return getStyle(obj,attr);
}

例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        #box{width: 200px;}
        #box1{width:300px;}
    </style>
</head>
<body>
    <div id="box"></div>
    <div id="box1"></div>
</body>
</html>
<script>
     var div = document.getElementsByTagName("div")[0];
     function getStyle(obj,attr){  
        if(obj.currentStyle){
            getStyle = function(obj,attr){
                return obj.currentStyle[attr]
            }
        }else{
            getStyle = function(obj,attr){
                return getComputedStyle(obj,false)[attr]
            }
        }
        return getStyle(obj,attr)
    }
  console.log(getStyle)
  /*
    function getStyle(obj,attr){  
        if(obj.currentStyle){
            getStyle = function(obj,attr){
                return obj.currentStyle[attr]
            }
        }else{
            getStyle = function(obj,attr){
                return getComputedStyle(obj,false)[attr]
            }
        }
        return getStyle(obj,attr)
    }
  */
  console.log(getStyle(box,"width"))
  console.log(getStyle)
  /*
    chrome浏览器
    (obj,attr){
            return getComputedStyle(obj,false)[attr]
        }
  */
</script>

二、记忆函数

如果熟悉Vue的同学应该知道vue中有一个属性叫做computed它可以缓存计算后的结果。记忆函数的功能也类似于computed。它可以将上次的结果缓存起来,当下次调用的时候,如果传递的参数相同,则直接返回缓存中的数据

举个例子:

function add(a, b) {
    return a + b;
}

// 假设 memoize 可以实现函数记忆
var memoizedAdd = memoize(add);

memoizedAdd(1, 2) // 3
memoizedAdd(1, 2) // 相同的参数,第二次调用时,从缓存中取出数据,而非重新计算一次

原理

我们只需要把参数和对应的结果存到一个对象中,调用时,判断参数对应的数据是否存在,如果存在则直接返回对应的结果

第一版

function memoize(f) {
    var cache = {};
    return function(){
        var key = arguments.length + Array.prototype.join.call(arguments, ",");
        if (key in cache) {
            return cache[key]
        }
        else {
            return cache[key] = f.apply(this, arguments)
        }
    }
}

// 调用
var add = function(a, b, c) {
  return a + b + c
}
var memoizedAdd = memoize(add)
memoizedAdd(1, 2, 3) // 5

因为第一版使用了join方法,我们很容易想到当参数是对象的时候,就会自动调用 toString方法转换成 [Object object],再拼接字符串作为 key 值。这样就很容易造成key值相同

var propValue = function(obj){
    return obj.value
}

var memoizedAdd = memoize(propValue)

console.log(memoizedAdd({value: 1})) // 1
console.log(memoizedAdd({value: 2})) // 1

两者都返回了 1,显然是有问题的,所以我们看看 underscore 的 memoize 函数是如何实现的:

// 第二版 (来自 underscore 的实现)
var memoize = function(func, hasher) {
    var memoize = function(key) {
        var cache = memoize.cache;
        var address = '' + (hasher ? hasher.apply(this, arguments) : key);
        if (!cache[address]) {
            cache[address] = func.apply(this, arguments);
        }
        return cache[address];
    };
    memoize.cache = {};
    return memoize;
};

可以看出underscore 默认使用 function 的第一个参数作为 key,所以如果直接使用

var add = function(a, b, c) {
  return a + b + c
}

var memoizedAdd = memoize(add)

memoizedAdd(1, 2, 3) // 6
memoizedAdd(1, 2, 4) // 6

肯定是有问题的,如果要支持多参数,我们就需要传入 hasher 函数,自定义存储的 key 值。所以我们考虑使用 JSON.stringify:

var memoizedAdd = memoize(add, function(){
    var args = Array.prototype.slice.call(arguments)
    return JSON.stringify(args)
})

console.log(memoizedAdd(1, 2, 3)) // 6
console.log(memoizedAdd(1, 2, 4)) // 7

总结:

使用场景:当有需要大量重复计算或者计算依赖之前的结果的函数,我们都可以使用记忆函数。

相关文章

  • JS专题系列之惰性函数与记忆函数

    一、惰性函数 惰性函数:顾名思义就是懒惰的函数,举一个简单的例子,如果我们需要判断当前浏览器是哪一种浏览器,我们需...

  • 前端_JavaScript

    JavaScript 专题之惰性函数 JavaScript 专题系列第十五篇,讲解惰性函数 需求 我们现在需要写一...

  • 『JavaScript专题』之惰性函数

    需求 我们现在需要写一个 foo 函数,这个函数返回首次调用时的 Date 对象,注意是首次。 解决一:普通方法 ...

  • 【基础系列】JS使用技巧专题

    JS使用技巧专题 1开发技巧 1.1函数使用 1.1.1函数声明方式 JS函数的写法总结 http://blog....

  • JS专题: 函数

    函数声明 匿名函数 具名函数 箭头函数 词法作用域 我们有如下代码 对于上面的代码, 浏览器先把代码变成抽象语法树...

  • JS函数专题

    函数编写 JS的函数可以嵌套(骚不骚?但是好像其他语言也支持?) 变量提升JavaScript的函数定义时,它会先...

  • 『JavaScript专题』之函数记忆

    定义 函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。 举个例子:...

  • js面向对象之 惰性函数和即时函数

    惰性函数定义: 特点是在第二次调用函数的时候这个函数才被正确的定义。第一次调用函数的时候只是做一些初始化的处理 特...

  • 构造函数和析构函数

    鸡啄米:C++编程入门系列之十四(类与对象:构造函数和析构函数)

  • JS性能优化之惰性加载函数

    前端开发不可避免的会有跨浏览器的需求,为了兼容各浏览器,绝大时候我们的处理方式都是用几个if...else或者tr...

网友评论

      本文标题:JS专题系列之惰性函数与记忆函数

      本文链接:https://www.haomeiwen.com/subject/vlguyltx.html