前一段时间学习了一下阮一峰大佬写的python教程,感受本身就是井底之蛙,函数式编程☹、返回函数☹、装饰器☹、偏函数☹,这些都是些什么东西?不过,在看过这些以后,有一种感受就是,部分知识和javascript中的闭包很是类似(也能够说思想如出一辙),经过python与JS,认认真真的去理解一下Javascript中的闭包。javascript
我的理解:函数 A 返回函数 B、函数 B 引用了函数 A 的变量。java
百度百科:闭包就是可以读取其余函数内部变量的函数
。例如在javascript中,只有函数内部的子函数才能读取局部变量,因此闭包能够理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。python
示例代码:面试
function makeFunc() {
var name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc(); // Mozilla
复制代码
闭包最经常使用于实现对象私有数据,将模块的公有属性、方法暴露出来。下面一段代码'return'关键字将对象导出赋值给myModule,从而应用到闭包。编程
var myModule = (function (window, undefined) {
let name = "echo";
function getName() {
return name;
}
return {
name,
getName
}
})(window);
console.log( myModule.name ); // echo
console.log( myModule.getName() ); // echo
复制代码
上次面试现时,遇到了定时器这道面试题。题目以下:浏览器
// 问这段代码输出什么?
for( var i = 0; i < 10; i++ ) {
setTimeout(() => {
console.log(i);
}, 0);
}
// 答案是输出 10个 10
复制代码
考察点:
var变量提高,以及setTimeout。执行到setTimeout会往浏览器的定时器线程推个任务,而后当达到时间了会经过轮询线程将回调推到宏任务队列中,若是那个时候主线程不忙就会去宏任务队列执行这个回调。因此定时器同步执行,回调是异步!闭包
详细请参考 javascript的宏任务和微任务app
回归正轨,咱们来说闭包: 上面代码如何作到输出0,1,2,3,4,5, 6,7,8,9,10呢?(固然可使用let,但咱们经过闭包来实现一下)异步
for( var i = 0; i < 10; i++ ) {
((j) => {
setTimeout(() => {
console.log(j);
}, 0);
})(i)
}
复制代码
"setTimeout"方法里应用了闭包,使其内部可以记住每次循环所在的词法做用域和做用域链。函数式编程
var oDiv = document.querySeletor("#div");
oDiv.onclick = function() {
console.log( oDiv.id );
}
复制代码
在函数式编程中,闭包常常被用于偏函数应用和柯里化。
偏函数应用: 是传给某个函数其中一部分参数,而后返回一个新的函数,该函数等待接收后续参数的过程。英文是partial application,也能够译做“局部应用”、“部分应用”、“偏应用”。
话句话讲偏函数应用是一个函数,它接受另外一个函数为参数,这个做为参数的函数自己接收多个参数,它返回一个函数,这个函数与它的参数相比接收更少的参数。偏函数应用提早给出一部分参数,而返回的函数则会等待调用时传入剩余的参数。
// 给一段代码理解理解
// Relatively flexible, more specific function generator.
function bindFirstArg(fn, a) {
return function(b) {
return fn(a, b);
};
}
// More general functions.
function add(a, b) {
return a + b;
}
add(1, 2); // 3
function multiply(a, b) {
return a * b;
}
multiply(10, 2); // 20
// More specific functions.
var addOne = bindFirstArg(add, 1);
addOne(2); // 3
addOne(3); // 4
addOne(10); // 11
addOne(9000); // 9001
var multiplyByTen = bindFirstArg(multiply, 10);
multiplyByTen(2); // 20
multiplyByTen(3); // 30
multiplyByTen(10); // 100
multiplyByTen(9000); // 90000
复制代码
上面这段代码,亮点不在于它能够将某个参数绑定到任意的function,而且这个参数做为绑定的function的第一个参数,它还能将方法绑定它本身身上做为第一个参数,所以建立了一个可绑定的function。
python中偏函数案例:
# functools.partial就是帮助咱们建立一个偏函数的,不须要咱们本身定义int2(),
# 能够直接使用下面的代码建立一个新的函数int2
import functools
int2 = functools.partial(int, base=2)
int2('1000000') # 64
int2('1010101') # 85
复制代码
简单总结functools.partial的做用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
是否是和上面JS代码思想很相似?
闭包是JS中又一必须掌握的知识点,写到最后,想到了之前回答闭包知识点的问题时,本身回答的也不是很好,记住一句函数 A 返回函数 B、函数 B 引用了函数 A 的变量
,在想一想应用场景,就能大体掌握闭包知识点了,顺带提一句,若是学过python,装饰器这一章节就是很典型的闭包,这也是学Python要跨过去的一道门。
来看看python装饰器代码:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
@log('execute')
def now():
print '2013-12-25'
now()
# 输出
# execute now():
# 2013-12-25
# 首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。
复制代码