閉包

什么是閉包

能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)就是閉包

1.提問:兩個函數(shù)嵌套,一個函數(shù)能夠訪問另外一個函數(shù)內(nèi)部變量的函數(shù)就形成了閉包,這個時候會造成內(nèi)存泄漏嗎?

答:不一定,只有內(nèi)部函數(shù)被return,保存到外部,并且被執(zhí)行的時候才造成內(nèi)存泄漏

2. 閉包的實戰(zhàn)應(yīng)用

  1. 回調(diào)函數(shù)是閉包嗎?
    是閉包
  function add(num1, num2, callback) {
    var sum = num1 + num2
    if(typeof callback === 'function') { // 通過類型判斷是否是一個函數(shù)
        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指向的剩余參數(shù)
    let fn = function () {
      let newArgs = Array.prototype.slice.call(arguments); // 得到回調(diào)函數(shù)上面的所有參數(shù)
      // 改變this指針指向,并且傳遞參數(shù)
      self.apply(this instanceof self ? this : context, args.concat(newArgs));
    };
    fn.prototype = Object.create(self.prototype); // 維護原型
    return fn;
  };

  a.newBind(b, "我是")("今年", "12歲");
  1. 防抖節(jié)流是閉包
      function ajaxFn() {
        console.log('發(fā)起請求');
      }

      // 防抖  只維護一個定時器,有新的進來,則清除舊定時器,再開始操作
      function shake(fn, wait) {
        let timer = null;
        return function() {
          if (timer) clearTimeout(timer);
          timer = setTimeout(fn, wait);
        };
      }

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

      // 節(jié)流 在定時器結(jié)束以后才能繼續(xù)執(zhí)行下一次操作
      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. 利用閉包判斷數(shù)據(jù)類型
  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. 封裝私有變量和函數(shù)
  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. 高階函數(shù)
  • 高階函數(shù)除了可以接受函數(shù)作為參數(shù)以外,還可以將函數(shù)作為結(jié)果值返回
  • 實現(xiàn)對一個數(shù)組的求和
function sum(arr) {
    return arr.reduce((a, b) => a+b) 
}
console.log(sum([1,2,3,4,5,6,7,8,9,10])  55
  • 但是如果不需要立刻取值,在后續(xù)的需求中再去取值,怎么做,這個時候可以不要直接返回求和以后的值,而是返回求和的函數(shù)
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]) // 返回的是求和的函數(shù)
console.log(res()) // 15
  1. 迭代器(執(zhí)行一次函數(shù)往下取一個值)
var arr = ['aa', 'bb', 'cc']
function inter(arr) {
    var i = 0
    return function () {
        // 這個函數(shù)每次被執(zhí)行 都會返回 arr 對應(yīng)下標(biāo)的元素
        return arr[i++] || '數(shù)組值已遍歷完'
    }
}
var next = inter(arr)
console.log(next()) // 'aa'
console.log(next()) // 'bb'
console.log(next()) // 'cc'
console.log(next()) // '數(shù)組值已遍歷完'
  1. 緩存
    比如求和操作,如果沒有緩存,每次調(diào)用都要重新計算,采用緩存,已經(jīng)執(zhí)行過的去查找,查找到了直接返回,不需要重新計算
var fn = (function() {
    var cache = {} // 緩存對象
    var calc = function (arr) { // 計算函數(shù)
        return arr.reduce((a,b) => a+b)
    }
    return function() {
        var args = Array.prototype.slice.call(arguments, 0) // 將arguments轉(zhuǎn)化成數(shù)組
        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}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在前一篇《這些JS設(shè)計模式中的基礎(chǔ)知識點你都會了嗎?[https://mp.weixin.qq.com/s/HTd...
    DYBOY閱讀 430評論 0 1
  • 閉包向來給包括JavaScript程序員在內(nèi)的程序員以神秘,高深的感覺,事實上,閉包的概念在函數(shù)式編程語言中算不上...
    不算程序員閱讀 338評論 0 5
  • 一、理解 JavaScript 的作用域、作用域鏈和內(nèi)部原理 作用域 javascript 擁有一套設(shè)計良好的規(guī)則...
    旭哥_閱讀 384評論 0 1
  • 函數(shù) 聲明式函數(shù) 表達式函數(shù) 立即執(zhí)行函數(shù) 此類函數(shù)沒有聲明,在一次執(zhí)行后即釋放,瀏覽器再也找不到這個函數(shù)的引用,...
    涙_閱讀 254評論 0 0
  • 閉包 閉包指的是那些引用了另一個函數(shù)作用域中變量的函數(shù),通常是在嵌套函數(shù)中實現(xiàn)的。 概述:閉包是一種書寫代碼一種結(jié)...
    蒜泥搗莓閱讀 665評論 0 1

友情鏈接更多精彩內(nèi)容