闭包治愈“全局变量恐惧症”,利用闭包实现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

相关文章
|
1月前
|
JavaScript 前端开发
js 闭包的优点和缺点
【10月更文挑战第27天】JavaScript闭包是一把双刃剑,在合理使用的情况下,它可以带来很多好处,如实现数据封装、记忆功能和模块化等;但如果不注意其缺点,如内存泄漏、变量共享和性能开销等问题,可能会导致代码出现难以调试的错误和性能问题。因此,在使用闭包时,需要谨慎权衡其优缺点,根据具体的应用场景合理地运用闭包。
117 58
|
1月前
|
缓存 JavaScript 前端开发
js 闭包
【10月更文挑战第27天】JavaScript闭包是一种强大的特性,它可以用于实现数据隐藏、记忆和缓存等功能,但在使用时也需要注意内存泄漏和变量共享等问题,以确保代码的质量和性能。
40 7
|
1月前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
23 2
|
1月前
|
存储 缓存 自然语言处理
掌握JavaScript闭包,提升代码质量与性能
掌握JavaScript闭包,提升代码质量与性能
|
1月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包(Closures)
深入理解JavaScript中的闭包(Closures)
|
1月前
|
存储 自然语言处理 JavaScript
深入理解JavaScript的闭包(Closures)
深入理解JavaScript的闭包(Closures)
31 0
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理、应用与代码演示
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理、应用与代码演示
|
前端开发 JavaScript 开发者
|
1月前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
27 1
JavaScript中的原型 保姆级文章一文搞懂
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
107 2