闭包

作者: 靴唯白 | 来源:发表于2024-02-26 11:06 被阅读0次

什么是闭包

能够读取其他函数内部变量的函数就是闭包

1.提问:两个函数嵌套,一个函数能够访问另外一个函数内部变量的函数就形成了闭包,这个时候会造成内存泄漏吗?

答:不一定,只有内部函数被return,保存到外部,并且被执行的时候才造成内存泄漏

2. 闭包的实战应用

  1. 回调函数是闭包吗?
    是闭包
  function add(num1, num2, callback) {
    var sum = num1 + num2
    if(typeof callback === 'function') { // 通过类型判断是否是一个函数
        callback(sum)
    }
  }
  add(1, 2, function(sum) {
    console.log(sum)
  })
  1. 手写js方法, bind方法
  var name ='s'
  function a() {
    console.log(arguments[0]+this.name + ',' + arguments[1] + arguments[2] );
    // 我是nina,今年12岁
  }

  var b = {
    name: "nina",
  };

  Function.prototype.newBind = function () {
    if (typeof this !== "function") throw "caller must be a function";
    let self = this;
    let context = arguments[0];
    let args = Array.prototype.slice.call(arguments, 1); // 得到bind上的除this指向的剩余参数
    let fn = function () {
      let newArgs = Array.prototype.slice.call(arguments); // 得到回调函数上面的所有参数
      // 改变this指针指向,并且传递参数
      self.apply(this instanceof self ? this : context, args.concat(newArgs));
    };
    fn.prototype = Object.create(self.prototype); // 维护原型
    return fn;
  };

  a.newBind(b, "我是")("今年", "12岁");
  1. 防抖节流是闭包
      function ajaxFn() {
        console.log('发起请求');
      }

      // 防抖  只维护一个定时器,有新的进来,则清除旧定时器,再开始操作
      function shake(fn, wait) {
        let timer = null;
        return function() {
          if (timer) clearTimeout(timer);
          timer = setTimeout(fn, wait);
        };
      }

      window.addEventListener('resize', shake(ajaxFn, 2000))

      // 节流 在定时器结束以后才能继续执行下一次操作
      function throttle(fn, wait) {
        let timer = null
        return function() {
            if(timer) return
            timer = setTimeout(() => {
                fn()
                timer = null
            }, wait)
        }
      }

      window.addEventListener('scroll', throttle(ajaxFn, 2000))
  1. 单例模式是闭包
// 单例模式也称为单体模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点
// 比如:一个班级只有一个班主任,只有一个太阳,一个国家只有一个主席这些 “唯一” “便于访问(全局访问)” 的行为对象便称作是单例

let Person = function(name) {
  this.name = name;
}
Person.prototype.getName = function() {
  return this.name;
}
Person.getInstance = (function() {
  let instance = null;
  return function(name) {
    if(!instance) {
      instance = new Singleton(name)
    }
    return instance;
  }
})()

let instance1 = Singleton.getInstance('why');
let instance2 = Singleton.getInstance('www');
console.log(instance1 === instance2); // 输出true

  1. 定时器穿参是闭包
  function aa(a) {
    return function() {
        console.log(a)
    }
  }
  setTimeout(aa(11), 1000)
  1. 利用闭包判断数据类型
  function isType(type) {
    return function(target) { // type Array
        // 第一个 [object Array]
        // 第二个 [object Object]
        return `[object ${type}]` === Object.prototype.toString.call(target)
    }
  }
  const isArray = isType('Array')
  console.log(isArray([1,2,3]))  // true
  console.log(isArray({}))  // false
  1. 封装私有变量和函数
  function createPerson(name) {
    var age = 0
    return {
        getName: function(){
            return name
        },
        getAge: function() {
            return age
        },
        setAge: function(newAge) {
            age = newAge
        }
    }
  }

  var person = new createPerson('summer')
  console.log(person.getName()) // 'summer'
  console.log(person.getAge())  // 0
  person.setAge(15)
  console.log(person.getAge())  // 15
  1. 高阶函数
  • 高阶函数除了可以接受函数作为参数以外,还可以将函数作为结果值返回
  • 实现对一个数组的求和
function sum(arr) {
    return arr.reduce((a, b) => a+b) 
}
console.log(sum([1,2,3,4,5,6,7,8,9,10])  55
  • 但是如果不需要立刻取值,在后续的需求中再去取值,怎么做,这个时候可以不要直接返回求和以后的值,而是返回求和的函数
function lazy_sum(arr) {
    let sum = function() {
        return arr.reduce((a,b) => a+b)
    }
    return sum
}
let res  = lazy_sum([1,2,3,4,5]) // 返回的是求和的函数
console.log(res()) // 15
  1. 迭代器(执行一次函数往下取一个值)
var arr = ['aa', 'bb', 'cc']
function inter(arr) {
    var i = 0
    return function () {
        // 这个函数每次被执行 都会返回 arr 对应下标的元素
        return arr[i++] || '数组值已遍历完'
    }
}
var next = inter(arr)
console.log(next()) // 'aa'
console.log(next()) // 'bb'
console.log(next()) // 'cc'
console.log(next()) // '数组值已遍历完'
  1. 缓存
    比如求和操作,如果没有缓存,每次调用都要重新计算,采用缓存,已经执行过的去查找,查找到了直接返回,不需要重新计算
var fn = (function() {
    var cache = {} // 缓存对象
    var calc = function (arr) { // 计算函数
        return arr.reduce((a,b) => a+b)
    }
    return function() {
        var args = Array.prototype.slice.call(arguments, 0) // 将arguments转化成数组
        var key = args.join(',') // 将args用,连接成字符串
        var result, tsum = cache[key]
        if(tsum) {
            // 如果缓存里面有值,则直接赋值给 result 并且返回
            console.log(cache) // 打印查看
            result = tsum
        } else {
            result = cache[key] = calc(args)
            console.log('存入缓存', cache) // 打印查看
        }
        return result
    }
})()
fn(1,2,3,4,5)   // 存入缓存 {1,2,3,4,5: 15}
fn(1,2,3,4,5)  // {1,2,3,4,5: 15}
fn(1,2,3,4,5,6)  // 存入缓存 {1,2,3,4,5: 15, 1,2,3,4,5,6: 21}
fn(1,2,3,4,5,8) // 存入缓存 {1,2,3,4,5: 15, 1,2,3,4,5,6: 21, 1,2,3,4,5,8: 23}
fn(1,2,3,4,5,6) //{1,2,3,4,5: 15, 1,2,3,4,5,6: 21, 1,2,3,4,5,8: 23}

相关文章

  • swift-闭包

    闭包 闭包定义 闭包简化 - 尾随闭包 闭包参数 闭包返回值 闭包的循环引用

  • 闭包,闭包,闭包

    1、这家伙到底是什么? 网上关于这个的讨论的太多了太多了,有各种的举例子,但是大部分还在寻找这个答案的小伙伴对于变...

  • 闭包-Closures [swift 5.1]

    闭包的语法 尾随闭包 闭包逃离 自动闭包

  • Day7 闭包(Closures)

    本页包含内容:• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包 1、闭包表达式 闭包...

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

  • swift- 闭包一

    /*• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包*/

  • (9) python之闭包

    闭包闭包 = 函数 + 环境变量(函数定义的时候) 一个最简单的闭包 闭包不受外部变量影响 非闭包 闭包 闭包 只...

  • Swift-进阶 :闭包(二)逃逸闭包 & 非逃逸闭包

    本文主要分析逃逸闭包 、非逃逸闭包、自动闭包 逃逸闭包 & 非逃逸闭包 逃逸闭包定义 当闭包作为一个实际参数传递给...

  • javascript闭包详解

    跟我念 bi 闭 bao包 ,闭包的闭,闭包的包。。 闭包的简介 在计算机科学中,闭包(英语:Closure),又...

网友评论

      本文标题:闭包

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