闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(二)

简介: 闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量

闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(一)https://developer.aliyun.com/article/1426535


2. 事件绑定

在JavaScript中,事件处理程序通常需要访问元素的一些属性或者其他变量。由于事件处理程序通常作为全局函数定义,因此它无法访问事件处理程序函数之外的变量。但是通过使用闭包,可以在事件处理程序内部访问外部的变量。

function addClickHandler(el, fn) {
  el.addEventListener('click', function() {
    fn();
  });
}
const button = document.querySelector('#myButton');
const name = '张三';
addClickHandler(button, function() {
  alert(`你好, ${name}!`);
});

在这个例子中, addClickHandler 函数通过闭包,允许事件处理程序内部访问外部变量 name,而且这种方式不会导致全局变量的污染。

3. 循环变量绑定

在循环语句中,经常需要将循环变量绑定到按钮或者链接等元素中。使用循环变量绑定时,需要注意循环变量和事件处理程序之间的作用域问题。使用闭包,可以解决循环变量和事件处理程序之间的作用域问题。

function createHandler(i) {
  return function() {
    console.log(`按钮 ${i} 被点击了`);
  }
}
for(let i = 0; i < 5; i++) {
  const button = document.createElement('button');
  button.innerText = `按钮 ${i}`;
  button.addEventListener('click', createHandler(i));
  document.body.appendChild(button);
}

在这个例子中, createHandler 函数使用闭包来创建一个可以访问循环变量的事件处理程序。而不使用闭包的话,事件处理程序将只能访问循环结束时循环变量的值。

IV. 闭包的优缺点

闭包的优点

数据的封装

闭包在数据封装上有以下优点:

1. 私有化变量和方法

闭包可以将变量和方法封装在一个函数作用域内,使得这些变量和方法只能在函数内部被访问,从而实现数据的封装。外部作用域无法直接访问闭包内部的变量和方法,只能通过相关的公有方法来访问或者修改数据。

function Counter() {
  let count = 0;
  return {
    increment: function() {
      count++;
    },
    decrement: function() {
      count--;
    },
    getCount: function() {
      return count;
    }
  };
}
const counter = Counter();
counter.increment(); // count+1
console.log(counter.getCount()); // 输出 1

在这个例子中, count 变量和三个方法都被封装在 Counter 函数内部,只能通过 Counter 函数返回的方法来访问或者修改 count 变量的值。

2. 避免全局变量的污染

使用闭包可以避免全局变量的污染。在函数作用域内部定义变量和方法时,它们不会影响全局作用域中已经存在的同名变量和方法,从而避免了命名冲突等问题。

let count = 0;
function Counter() {
  count = 10;
  return {
    increment: function() {
      count++;
    },
    decrement: function() {
      count--;
    },
    getCount: function() {
      return count;
    }
  };
}
const counter = Counter();
counter.increment(); // count+1
console.log(counter.getCount()); // 输出 11
console.log(count); // 输出 10

在这个例子中, count 变量已经被定义在全局作用域中,但是通过在 Counter 函数内部重新定义一个同名的 count 变量,实现了局部变量的封装,避免了对全局 count 变量的修改。

因此,使用闭包可以实现对数据的封装,并且避免全局变量的污染,有助于提高代码的可读性和可维护性。

可以实现高阶函数

闭包可以实现高阶函数,并且在高阶函数中发挥重要作用,具有以下优点:

1. 强大的表现力

闭包可以将函数作为参数和返回值传递,实现更加灵活的函数组合和转换,从而快速构建复杂的功能模块。这种能力称为函数式编程中的柯里化(currying)和组合(composition)。

function add(x) {
  return function(y) {
    return x + y;
  };
}
function multiply(x) {
  return function(y) {
    return x * y;
  };
}
const add5 = add(5);
const multiply2 = multiply(2);
const result = add5(2); // 5 + 2 = 7
const result2 = multiply2(result); // 7 * 2 = 14
console.log(result2); // 输出 14

在这个例子中,addmultiply 函数都是返回一个闭包,而且这两个闭包接受一个参数并进行计算。通过组合这两个闭包,可以实现一个更加复杂的计算过程,从而实现高阶函数的功能。

2. 支持延迟求值

闭包支持延迟求值,也就是说,在某些情况下,可以将函数的执行延迟到需要的时候再执行,从而避免不必要的计算和内存占用。这种方法称为惰性求值(lazy evaluation)。

function createSquares(max) {
  const squares = [];
  function getSquare(i) {
    return function() {
      return i * i;
    };
  }
  for(let i = 0; i <= max; i++) {
    squares.push(getSquare(i));
  }
  return squares;
}
const squares = createSquares(10000);
console.log(squares[0]()); // 输出 0
console.log(squares[1]()); // 输出 1
console.log(squares[2]()); // 输出 4
// 将一次性计算所有的平方数改成延迟计算
const squares2 = createSquares(10000);
console.log(squares2[0]()); // 输出 0
console.log(squares2[1]()); // 输出 1

在这个示例中,createSquares 函数返回一个闭包数组,这些闭包可以在需要时延迟计算实际的值,解决了在一次性计算所有平方数时可能面临的性能问题,从而提高了运行效率。对于大数据量的计算,使用惰性求值可以节省大量的内存和计算资源。

因此,利用闭包可以创建高阶函数,实现更加灵活的函数组合和转换,还可以支持惰性求值,提高代码性能和运行效率。


闭包治愈“全局变量恐惧症”,利用闭包实现JavaScript私有变量(三)https://developer.aliyun.com/article/1426537

相关文章
|
8月前
|
JavaScript 前端开发
如何减少Node.js应用中的全局变量?
如何减少Node.js应用中的全局变量?
465 133
|
8月前
|
JavaScript 前端开发
在Node.js中,如何合理使用模块来避免全局变量的问题?
在Node.js中,如何合理使用模块来避免全局变量的问题?
318 71
|
11月前
|
前端开发 JavaScript Java
JavaScript闭包深入剖析:性能剖析与优化技巧
JavaScript 闭包是强大而灵活的特性,广泛应用于数据封装、函数柯里化和事件处理等场景。闭包通过保存外部作用域的变量,实现了私有变量和方法的创建,提升了代码的安全性和可维护性。然而,闭包也可能带来性能问题,如内存泄漏和执行效率下降。为优化闭包性能,建议采取以下策略:及时解除对不再使用的闭包变量的引用,减少闭包的创建次数,使用 WeakMap 管理弱引用,以及优化闭包结构以减少作用域链查找的开销。在实际开发中,无论是 Web 前端还是 Node.js 后端,这些优化措施都能显著提升程序的性能和稳定性。
277 70
|
9月前
|
存储 JavaScript 前端开发
|
11月前
|
自然语言处理 JavaScript 前端开发
当面试官再问我JS闭包时,我能答出来的都在这里了。
闭包(Closure)是前端面试中的高频考点,广泛应用于函数式编程中。它不仅指函数内部定义的函数,还涉及内存管理、作用域链和垃圾回收机制。闭包可以让函数访问其外部作用域的变量,但也可能引发内存泄漏等问题。通过合理使用闭包,可以实现模块化、高阶函数和回调函数等应用场景。然而,滥用闭包可能导致代码复杂度增加、调试困难以及潜在的性能问题。为了避免这些问题,开发时应谨慎处理闭包,避免不必要的嵌套,并及时清理不再使用的变量和监听器。
491 16
当面试官再问我JS闭包时,我能答出来的都在这里了。
|
10月前
|
缓存 自然语言处理 JavaScript
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
存储 缓存 自然语言处理
掌握JavaScript闭包,提升代码质量与性能
掌握JavaScript闭包,提升代码质量与性能
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包(Closures)
深入理解JavaScript中的闭包(Closures)
|
存储 JavaScript 前端开发
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置
web前端学习(三十四)——JavaScript对象、函数及作用域(全局变量、局部变量)的相关设置