Skip to content

JavaScript 中的惰性函数

惰性函数(Lazy Evaluation)是一种编程技术,其核心思想是推迟计算或执行某个操作,直到真正需要的时候才进行。这种延迟计算的方式有助于提高程序的性能,因为它避免了不必要的计算或操作,只在必要时才进行。

在某些编程语言中,惰性函数通常通过延迟加载(Lazy Loading)或惰性求值(Lazy Evaluation)的方式实现。具体来说,当需要某个值或结果时,才会进行相应的计算或操作,而不是在定义时就立即执行。

这种技术的应用场景包括:

  1. 性能优化: 当某个计算量较大或复杂的操作不一定会被每次都使用时,可以使用惰性函数来推迟执行,以提高程序的整体性能。
  2. 资源节约: 当某些资源(例如内存)的分配和初始化较为昂贵时,可以延迟这些操作,仅在需要时才执行,从而节约资源。
  3. 处理无限序列: 在处理无限序列的情况下,惰性函数也能够有效地应用。只计算和获取序列中实际需要的部分,而不是一次性计算整个序列。

在一些函数式编程语言中,惰性函数的概念更为突出,而在其他语言中,开发者可能需要手动实现惰性行为。

示例

事件绑定兼容性处理

标准的现代浏览器的事件绑定方法为:element.addEventListener。而早期版本的 IE 浏览器(< IE 9)引入的非标准事件绑定方法为:element.attachEvent。(虽然 IE 家族已经退出历史舞台了~)

JavaScript
/**
 * 绑定点击事件 - 非惰性函数实现
 */
function addClickEvent() {
    var element = document.getElementById('myButton');

    // 检查是否已经绑定了事件处理程序
    if (element.addEventListener) {
        element.addEventListener('click', handleClick, false);
    } else if (element.attachEvent) {
        element.attachEvent('onclick', handleClick);
    }
}

function handleClick() {
    alert('按钮被点击!');
}
/**
 * 绑定点击事件 - 非惰性函数实现
 */
function addClickEvent() {
    var element = document.getElementById('myButton');

    // 检查是否已经绑定了事件处理程序
    if (element.addEventListener) {
        element.addEventListener('click', handleClick, false);
    } else if (element.attachEvent) {
        element.attachEvent('onclick', handleClick);
    }
}

function handleClick() {
    alert('按钮被点击!');
}
JavaScript
/**
 * 绑定点击事件 - 惰性函数实现
 */
function addClickEventLazy() {
    var element = document.getElementById('myButton');

    // 使用惰性函数,只在第一次调用时绑定事件处理程序
    addClickEventLazy = function() {
        if (element.addEventListener) {
            element.addEventListener('click', handleClick, false);
        } else if (element.attachEvent) {
            element.attachEvent('onclick', handleClick);
        }
    };

    // 第一次调用
    addClickEventLazy();
}

function handleClick() {
    alert('按钮被点击!');
}
/**
 * 绑定点击事件 - 惰性函数实现
 */
function addClickEventLazy() {
    var element = document.getElementById('myButton');

    // 使用惰性函数,只在第一次调用时绑定事件处理程序
    addClickEventLazy = function() {
        if (element.addEventListener) {
            element.addEventListener('click', handleClick, false);
        } else if (element.attachEvent) {
            element.attachEvent('onclick', handleClick);
        }
    };

    // 第一次调用
    addClickEventLazy();
}

function handleClick() {
    alert('按钮被点击!');
}

复制文本兼容性处理

JavaScript
/**
 * 复制文本 - 非惰性函数实现
 */
function copyText(text) {
  if (navigator.clipboard) {
    navigator.clipboard.writeText(text)
  } else {
    const textArea = document.createElement('textarea')
    textArea.value = text
    textArea.style.position = 'fixed'
    textArea.style.top = 0
    textArea.style.left = 0
    textArea.style.opacity = 0
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()
    document.execCommand('copy')
    document.body.removeChild(textArea)
  }
}
/**
 * 复制文本 - 非惰性函数实现
 */
function copyText(text) {
  if (navigator.clipboard) {
    navigator.clipboard.writeText(text)
  } else {
    const textArea = document.createElement('textarea')
    textArea.value = text
    textArea.style.position = 'fixed'
    textArea.style.top = 0
    textArea.style.left = 0
    textArea.style.opacity = 0
    document.body.appendChild(textArea)
    textArea.focus()
    textArea.select()
    document.execCommand('copy')
    document.body.removeChild(textArea)
  }
}
JavaScript
/**
 * 复制文本 - 惰性函数实现
 */
function copyText(text) {
  if (navigator.clipboard) {
    copyText = text => navigator.clipboard.writeText(text)
  } else {
    copyText = text => {
      const textArea = document.createElement('textarea')
      textArea.value = text
      textArea.style.position = 'fixed'
      textArea.style.top = 0
      textArea.style.left = 0
      textArea.style.opacity = 0
      document.body.appendChild(textArea)
      textArea.focus()
      textArea.select()
      document.execCommand('copy')
      document.body.removeChild(textArea)
    }
  }
  copyText(text)
}
/**
 * 复制文本 - 惰性函数实现
 */
function copyText(text) {
  if (navigator.clipboard) {
    copyText = text => navigator.clipboard.writeText(text)
  } else {
    copyText = text => {
      const textArea = document.createElement('textarea')
      textArea.value = text
      textArea.style.position = 'fixed'
      textArea.style.top = 0
      textArea.style.left = 0
      textArea.style.opacity = 0
      document.body.appendChild(textArea)
      textArea.focus()
      textArea.select()
      document.execCommand('copy')
      document.body.removeChild(textArea)
    }
  }
  copyText(text)
}

计算斐波那契数列

斐波那契数列(Fibonacci sequence)是一个数学上的数列,其特点是每个数字都是前两个数字之和。数列的开始通常为 0 和 1,之后的每个数字都是前两个数字之和。斐波那契数列的前几项是:

text
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

换句话说,第 n 项(n ≥ 2)是前两项的和,即 F(n) = F(n-1) + F(n-2),其中 F(0) = 0,F(1) = 1。

斐波那契数列在数学、计算机科学等领域都有广泛的应用,例如在算法、动态规划、递归等方面。斐波那契数列的增长速度相当快,因此它经常用于测试算法和计算机程序的性能。

JavaScript
/**
 * 计算斐波那契第 n 项的值 - 非惰性函数实现
 */
function calculateFibonacci(n) {
    function fibonacci(n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }

    return fibonacci(n);
}

console.time('Non-Lazy Fibonacci');
console.log(calculateFibonacci(10)); // 非惰性计算,可能较慢
console.timeEnd('Non-Lazy Fibonacci');
/**
 * 计算斐波那契第 n 项的值 - 非惰性函数实现
 */
function calculateFibonacci(n) {
    function fibonacci(n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }

    return fibonacci(n);
}

console.time('Non-Lazy Fibonacci');
console.log(calculateFibonacci(10)); // 非惰性计算,可能较慢
console.timeEnd('Non-Lazy Fibonacci');
JavaScript
/**
 * 计算斐波那契第 n 项的值 - 惰性函数实现
 */
function calculateFibonacciLazy(n) {
    // 使用惰性函数,只在第一次调用时计算斐波那契数列
    calculateFibonacciLazy = function (n) {
        if (n <= 1) {
            return n;
        } else {
            return calculateFibonacciLazy(n - 1) + calculateFibonacciLazy(n - 2);
        }
    };

    return calculateFibonacciLazy(n);
}

console.time('Lazy Fibonacci');
console.log(calculateFibonacciLazy(10)); // 惰性计算,可能更快
console.timeEnd('Lazy Fibonacci');
/**
 * 计算斐波那契第 n 项的值 - 惰性函数实现
 */
function calculateFibonacciLazy(n) {
    // 使用惰性函数,只在第一次调用时计算斐波那契数列
    calculateFibonacciLazy = function (n) {
        if (n <= 1) {
            return n;
        } else {
            return calculateFibonacciLazy(n - 1) + calculateFibonacciLazy(n - 2);
        }
    };

    return calculateFibonacciLazy(n);
}

console.time('Lazy Fibonacci');
console.log(calculateFibonacciLazy(10)); // 惰性计算,可能更快
console.timeEnd('Lazy Fibonacci');

Last updated: