我正在尽最大努力理解JavaScript闭包。
通过返回一个内部函数,它可以访问直接父函数中定义的任何变量。
这对我有什么用?也许我还没完全搞清楚。我在网上看到的大多数示例都没有提供任何真实的代码,只是一些模糊的示例。
有人能告诉我一个闭包的真实用法吗?
比如这个吗?
var warnUser = function (msg) {
var calledCount = 0;
return function() {
calledCount++;
alert(msg + '\nYou have been warned ' + calledCount + ' times.');
};
};
var warnForTamper = warnUser('You can not tamper with our HTML.');
warnForTamper();
warnForTamper();
JavaScript闭包可用于在应用程序中实现节流和反弹功能。
节流
节流限制了一个函数在一段时间内可以被调用的最大次数。就像“最多每100毫秒执行一次这个函数。”
代码:
const throttle = (func, limit) => {
let isThrottling
return function() {
const args = arguments
const context = this
if (!isThrottling) {
func.apply(context, args)
isThrottling = true
setTimeout(() => isThrottling = false, limit)
}
}
}
消除抖动
deboundation限制了函数在经过一段时间后才会被再次调用。就像“仅在100毫秒后未被调用时才执行该函数。”
代码:
const debounce = (func, delay) => {
let debouncing
return function() {
const context = this
const args = arguments
clearTimeout(debouncing)
debouncing = setTimeout(() => func.apply(context, args), delay)
}
}
正如你所看到的,闭包帮助实现了两个漂亮的特性,每个web应用程序都应该提供流畅的UI体验功能。
JavaScript闭包可用于在应用程序中实现节流和反弹功能。
节流
节流限制了一个函数在一段时间内可以被调用的最大次数。就像“最多每100毫秒执行一次这个函数。”
代码:
const throttle = (func, limit) => {
let isThrottling
return function() {
const args = arguments
const context = this
if (!isThrottling) {
func.apply(context, args)
isThrottling = true
setTimeout(() => isThrottling = false, limit)
}
}
}
消除抖动
deboundation限制了函数在经过一段时间后才会被再次调用。就像“仅在100毫秒后未被调用时才执行该函数。”
代码:
const debounce = (func, delay) => {
let debouncing
return function() {
const context = this
const args = arguments
clearTimeout(debouncing)
debouncing = setTimeout(() => func.apply(context, args), delay)
}
}
正如你所看到的,闭包帮助实现了两个漂亮的特性,每个web应用程序都应该提供流畅的UI体验功能。
闭包的另一个常见用途是将方法中的this绑定到特定对象,允许在其他地方调用它(例如作为事件处理程序)。
function bind(obj, method) {
if (typeof method == 'string') {
method = obj[method];
}
return function () {
method.apply(obj, arguments);
}
}
...
document.body.addEventListener('mousemove', bind(watcher, 'follow'), true);
每当鼠标移动事件触发时,都会调用watch .follow(evt)。
闭包也是高阶函数的重要组成部分,通过参数化不同部分,可以将多个相似函数重写为一个高阶函数,这是非常常见的模式。举个抽象的例子,
foo_a = function (...) {A a B}
foo_b = function (...) {A b B}
foo_c = function (...) {A c B}
就变成了
fooer = function (x) {
return function (...) {A x B}
}
其中A和B不是语法单位,而是源代码字符串(不是字符串字面量)。
具体示例请参见“用函数简化我的javascript”。
在这里,我有一句想说好几遍的问候语。如果我创建一个闭包,我可以简单地调用该函数来记录问候语。如果我不创建闭包,我必须每次都传递我的名字。
没有闭包(https://jsfiddle.net/lukeschlangen/pw61qrow/3/):
function greeting(firstName, lastName) {
var message = "Hello " + firstName + " " + lastName + "!";
console.log(message);
}
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Billy", "Bob");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
greeting("Luke", "Schlangen");
使用闭包(https://jsfiddle.net/lukeschlangen/Lb5cfve9/3/):
function greeting(firstName, lastName) {
var message = "Hello " + firstName + " " + lastName + "!";
return function() {
console.log(message);
}
}
var greetingBilly = greeting("Billy", "Bob");
var greetingLuke = greeting("Luke", "Schlangen");
greetingBilly();
greetingBilly();
greetingBilly();
greetingLuke();
greetingLuke();
greetingLuke();