例如:
let arr = [11, 22, 33, 44, 55, 66, 77, 88, 99]
function liFor(arr, callback) {
for (let i = 0i <arr.lengthi++) {
if (callback(arr[i])) {
console.log(arr[i])
}
}
}
console.log('---------遍历数组----------')
liFor(arr, val =>true)
console.log('---------输出奇数----------')
liFor(arr, val =>val % 2 !== 0)
console.log('---------输出被3整除----------')
liFor(arr, val =>val % 3 === 0)
console.log('---------输出被3和6整除----------')
liFor(arr, val =>val % 3 === 0 &&val % 6 === 0)
闭包函数概念:定义一个a方法,在a方法中定义一个b方法,并且b方法里面用到了a方法里面定义的变量,那么此时就形成了闭包函数,由于内部方法里面,用到外部方法里面的变量,外部方法里面的那个变量会一直在内存中存保存着。两个方法嵌套定义,里面的方法,用到了外面方法里面定义的变量,此时这两个方法就形成了闭包。
例如:
function a() {
console.log('a函数被调用了...')
let num1 = 100
let num2 = 200
function b() {
console.log('b函数被调用了...')
console.log(num1 + num2)
}
//返回的返回值也是一个函数,那么a函数就是高阶函数。
return b
}
// 通常情况下,函数执行完成后,函数里面定义的变量,会被销毁。
// a函数,已经调用完毕了,但是a函数里面定义变量,始终在内存中,因为b函数中用到了a函数中定义的变量。
// 那么此时这两个函数,就称之为:闭包函数。
let c = a()
c()
console.log('------------------------------------------')
// 闭包函数的实际案例
function calc(num1, num2, type) {
switch (type) {
case '+':
console.log(`${num1}+${num2}=${num1 + num2}`)
break
case '-':
console.log(`${num1}-${num2}=${num1 - num2}`)
break
}
}
// 在实际开发中,我们在做num1和num2的计算之前,可能需要先做其他事情
let num1 = 100
let num2 = 50
// 在做其他事情的过程中,我们的数据很有可能会被篡改。
console.log('查看用户是否登录')
num1 = 555
num2 = 145
console.log('检查用户的权限')
calc(num1, num2, '+') //运行结果不对,因为变量的值被篡改了。
console.log('------------------------------------------')
// 定义一个闭包函数,实现计算器功能
function myCalc(num1, num2, type) {
switch (type) {
case '+':
return function() {
return num1 + num2
}
case '-':
return function() {
return num1 - num2
}
}
}
//先准备好你的数据
let n1 = 100
let n2 = 50
//将你的数据传给计算器方法,由计算器方法,返回一个计算方法。
let js = myCalc(n1, n2, '+')
//在做具体的计算之前,还先做些其他的事情
console.log('查看用户是否登录')
n1 = 555
n2 = 145
console.log('检查用户的权限')
//其他事件准备好了后,执行计算方法
console.log(js())
在A函数中嵌套B函数,B函数访问A函数中的变量。将A函数复制给C函数并执行。
那么在大多数的理解中,包括许多著名的书籍,文章里都以函数C的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。
而我的理解是:闭包更准确的说是一项技术或者一个特性:只要运用具备阻止垃圾回收机制回收和突破作用域链限制的技术,就是闭包。像是《JavaScript权威指南》打的比方,像是把变量包裹了起来,形象的称为“闭包”。
如果非要指明哪个函数是闭包的话,我愿意将A函数称为定义闭包的函数,C函数为执行闭包的函数。
a. 在函数内部创建新的函数;
b. 新的函数在执行时,访问了函数的变量对象。
c. 闭包是在函数被调用执行的时候才被确认创建的。
一句话总结:==函数中闭包判定的准则,即执行时是否在内部定义的函数中访问了上层作用域的变量。==
闭包,阻止垃圾回收机制。
闭包,突破作用域链接。
《你不知道的JS中》的示例:
模块模式需要具备两个必要条件:
1.必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)。
2.封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。
什么时候使用模块模式?
如果必须创建一个对象并一某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。
哪些地方有用到模块模式?
最典型的就是JQuery库,jQuery和$标识符就是JQuery模块的公共API,但它们本身都是函数(由于函数也是对象,它们本身也可以拥有属性)
以后单独拿一个章节,来具体讲讲现在的模块化和未来的模块化机制。
具体的内容在函数的柯里化的章节中详细分析。
戳此传送门
输出6的原因是:被封闭在一个共享的全局作用域中,实际上只有一个i。
依次输出1-5的原因是:在迭代内部使用IIFE(立即表达函数)为每个迭代生成一个新的作用域,将外部变量的值传递进去并被引用(阻止垃圾回收机制回收),使得每个回调函数都能访问到正确值的变量。
戳此传送门
闭包是:指有有访问另一个函数作用域中的变量的函数。
创建闭包的常用方式:在一个函数内部创建一个函数。例子:
functioncreateFunction(name){return function(obj1, obj2){
var value1 = obj1[name]
var value2 = obj2[name]
return value1 + ", " +value2
}
}
了解创建作用域以及作用域有什么作用的细节,对彻底理解闭包到头重要。当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后,使用arguments和其他参数的值来初始化函数的活动对象。
一、闭包
1、createFunction()创建时,它(compare)的作用域包含createFunction()函数的活动对象和全局对象。
//创建函数var compare = createFunction("name")
console.log(typeofcompare) //function
2、匿名函数被执行时,创建自己的活动对象和可以访问createFunction()的执行环境。
//调用函数var result =compare({name: "jjaiy"}, {name:"ascy"}) //jjaiyy, ascy
3、createFunction()函数执行完后,其执行环境的作用域不会被销毁。原因在于它的活动对象还在内存中,直到匿名函数被销毁。
//解除对匿名函数的引用(以便释放内存)compare = null
原因在于:
浏览器的垃圾收集方式有:
标记清除(主要针对变量)
引用计数(跟踪记录每个值被引用的次数)
二、实例运行
封装功能
var route = {routes: {},
for: function(path, handler){ //闭包
this.routes[path] = handler //引用回调函数
}
}
//执行二个匿名函数
route.for("/start",function(request, response){
response.writeHead(200,{"Content-Type": "text/plain"})
response.write("Hello")
response.end()
})
route.for("/finish",function(request, response){
response.writeHead(200,{"Content-Type": "text/plain"})
response.write("Goodbye")
response.end()
})
//先判断argument中的path变量是否一致,能否调用其函数中的回调函数。
if(typeof route.routes["/finish"] === 'function'){
route.routes["/finish"](request, response)
}