找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

160

积分

0

好友

19

主题
发表于 3 小时前 | 查看: 1| 回复: 0

基本使用

闭包是JavaScript中的一个重要概念,它允许函数访问并操作函数外部的变量。下面通过两个典型示例展示闭包的基本用法。

基础闭包示例:

function outFunc() {
  const name = "王独秀";
  function inFunc() {
    console.log(name);
  }
  return inFunc;
}

const inFunc = outFunc();
inFunc(); // 输出:王独秀

模拟私有属性:

function User() {
  this.name = "王独秀"; // 公有属性
  const age = 28; // 私有属性

  this.sayAge = function() {
    console.log("my age is " + age);
  }
}

const user = new User();
console.log(user.name);    // 王独秀(公有属性可访问)
console.log(user.age);     // undefined(私有属性不可直接访问)
user.sayAge();            // my age is 28(通过闭包访问私有属性)

应用场景

1. 返回值(最常用)

function fn(){
  var name = "Symbol(王独秀)";
  return function(){
    return name;
  }
}

var fnc = fn();
console.log(fnc()); // Symbol(王独秀)

2. 函数赋值

var fn2;
function fn(){
  var name = "Symbol(王独秀)";
  // 将闭包函数赋值给外部变量
  fn2 = function(){
    return name;
  }
}

fn(); // 先执行函数完成赋值
console.log(fn2()); // Symbol(王独秀)

3. 函数参数

function fn(){
  var name = "王独秀";
  return function callback(){
    return name;
  }
}

var fn1 = fn(); // 获取闭包函数

function fn2(f){
  // 将闭包函数作为参数传入
  console.log(f());
}

fn2(fn1); // 输出:王独秀

4. IIFE(自执行函数)

(function(){
  var name = "王独秀";
  var fn1 = function(){
    return name;
  }

  // 在自执行函数中直接调用外部函数
  fn2(fn1);
})();

function fn2(f){
  console.log(f()); // 输出:王独秀
}

5. 循环赋值

// 每秒输出1次,分别显示1-10
for(var i = 1; i <= 10; i++){
  (function(j){
    // 使用闭包保存当前循环的值
    setTimeout(function(){
      console.log(j);
    }, j * 1000);
  })(i); // 立即传入当前i值
}

6. Getter和Setter

function fn(){
  var name = '王独秀';

  setName = function(n){
    name = n;
  }

  getName = function(){
    return name;
  }

  return {
    setName: setName,
    getName: getName
  }
}

var fn1 = fn();
console.log(fn1.getName()); // getter
fn1.setName('world');       // setter修改闭包内的name
console.log(fn1.getName()); // getter

7. 迭代器

var arr = ['aa', 'bb', 'cc'];
function incre(arr){
  var i = 0;
  return function(){
    return arr[i++] || '数组值已经遍历完';
  }
}

var next = incre(arr);
console.log(next()); // aa
console.log(next()); // bb
console.log(next()); // cc
console.log(next()); // 数组值已经遍历完

8. 首次区分(避免重复执行)

var fn = (function(){
  var arr = []; // 缓存数组

  return function(val){
    if(arr.indexOf(val) == -1){
      arr.push(val);
      console.log('函数被执行了', arr);
      // 实际业务逻辑
    } else {
      console.log('此次函数不需要执行');
    }
    console.log('已缓存的数组:', arr);
  }
})();

fn(10);    // 函数被执行了 [10]
fn(10);    // 此次函数不需要执行
fn(1000);  // 函数被执行了 [10,1000]

9. 缓存优化

var fn = (function(){
  var cache = {}; // 缓存对象

  var calc = function(arr){
    var sum = 0;
    for(var i = 0; i < arr.length; i++){
      sum += arr[i];
    }
    return sum;
  }

  return function(){
    var args = Array.prototype.slice.call(arguments, 0);
    var key = args.join(",");
    var result, tSum = cache[key];

    if(tSum){
      console.log('从缓存中取:', cache);
      result = tSum;
    } else {
      result = cache[key] = calc(args);
      console.log('存入缓存:', cache);
    }
    return result;
  }
})();

fn(1,2,3,4,5);     // 存入缓存
fn(1,2,3,4,5);     // 从缓存中取
fn(1,2,3,4,5,6);   // 存入新缓存

10. 事件处理中的索引获取

<button>button1</button>
<button>button2</button>
<button>button3</button>

<script>
  const btns = document.querySelectorAll('button');

  // 使用闭包方案
  for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = (function(tmpI) {
      return function() {
        console.log(tmpI + 1);
      }
    })(i)
  }

  // 或者使用let声明(现代[前端开发](https://yunpan.plus/f/22-1)推荐)
  for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = function() {
      console.log(i + 1);
    }
  }
</script>

闭包在函数式编程中扮演着重要角色,合理运用可以显著提升代码的可维护性和性能表现。通过上述10个实际场景的演示,相信大家对闭包的理解会更加深入。

您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-1 14:51 , Processed in 1.206423 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表