什么是閉包
能夠讀取其他函數(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)用
- 回調(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)
})
- 手寫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歲");
- 防抖節(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))
- 單例模式是閉包
// 單例模式也稱為單體模式,保證一個類僅有一個實例,并提供一個訪問它的全局訪問點
// 比如:一個班級只有一個班主任,只有一個太陽,一個國家只有一個主席這些 “唯一” “便于訪問(全局訪問)” 的行為對象便稱作是單例
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
- 定時器穿參是閉包
function aa(a) {
return function() {
console.log(a)
}
}
setTimeout(aa(11), 1000)
- 利用閉包判斷數(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
- 封裝私有變量和函數(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
- 高階函數(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
- 迭代器(執(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ù)組值已遍歷完'
- 緩存
比如求和操作,如果沒有緩存,每次調(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}