我怎样才能将闭包从外部函数中分解出来,以便在不同的上下文中重用所述闭包?
How can I factor a closure out of an outer function to reuse said closure in different contexts?
假设我有这段处理事件处理的代码。
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
}
点击 btn1,"hello" 显示在 result1.
点击 btn2,"YO" 显示在 result2.
现在,您可能已经注意到,两个 handleEvent 函数完全相同。我想要实现的是这样的。
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return handleEvent;
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return handleEvent;
}
function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
}
但这当然不会起作用,因为 handleEvent 函数未在 say 和 shout[ 中声明=58=]函数;因此,saying 和 container 将不会被定义。
我尝试使用 bind() 并声明 saying 和 container this 在 say 和 shout 函数中:
function say(word) {
this.saying = word;
this.container = document.getElementById('result1');
return handleEvent.bind(this);
}
function shout(word) {
this.saying = word.toUpperCase();
this.container = document.getElementById('result2');
return handleEvent.bind(this);
}
function handleEvent() {
var text = document.createTextNode(this.saying);
this.container.innerHTML = '';
this.container.appendChild(text);
}
但这也没有用。
如何将 handleEvent 函数从 say 和 shout 函数中分解出来?
谢谢!
您不能在不同的上下文中重用闭包,因为根据 javascript 中的定义,闭包是绑定到其父上下文的内部函数。
但是您可以提取函数体以便在不同的上下文中重用它:
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function saySomething(context, saying) {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return function handleEvent() {
saySomething(context, saying);
};
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return function handleEvent() {
saySomething(context, saying);
};
}
或者如果你想使用绑定:
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function saySomething(context, saying) {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return saySomething.bind(undefined, context, saying);
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return saySomething.bind(undefined, context, saying);
}
如果您创建了要绑定的新对象而不是使用 this
:
,则绑定应该有效
function say(word) {
return handleEvent.bind({
saying: word,
container: document.getElementById('result1')
});
}
function shout(word) {
return handleEvent.bind({
saying: word.toUpperCase(),
container: document.getElementById('result2')
});
}
但是,您仍然可以通过正常关闭来解决此问题:
function say(word) {
return makeHandleEvent(word, 'result1');
}
function shout(word) {
return makeHandleEvent(word.toUpperCase(), 'result2');
}
function makeHandleEvent(saying, id) {
var container = document.getElementById(id);
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
}
}
假设我有这段处理事件处理的代码。
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
}
点击 btn1,"hello" 显示在 result1.
点击 btn2,"YO" 显示在 result2.
现在,您可能已经注意到,两个 handleEvent 函数完全相同。我想要实现的是这样的。
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return handleEvent;
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return handleEvent;
}
function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
}
但这当然不会起作用,因为 handleEvent 函数未在 say 和 shout[ 中声明=58=]函数;因此,saying 和 container 将不会被定义。
我尝试使用 bind() 并声明 saying 和 container this 在 say 和 shout 函数中:
function say(word) {
this.saying = word;
this.container = document.getElementById('result1');
return handleEvent.bind(this);
}
function shout(word) {
this.saying = word.toUpperCase();
this.container = document.getElementById('result2');
return handleEvent.bind(this);
}
function handleEvent() {
var text = document.createTextNode(this.saying);
this.container.innerHTML = '';
this.container.appendChild(text);
}
但这也没有用。
如何将 handleEvent 函数从 say 和 shout 函数中分解出来?
谢谢!
您不能在不同的上下文中重用闭包,因为根据 javascript 中的定义,闭包是绑定到其父上下文的内部函数。
但是您可以提取函数体以便在不同的上下文中重用它:
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function saySomething(context, saying) {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return function handleEvent() {
saySomething(context, saying);
};
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return function handleEvent() {
saySomething(context, saying);
};
}
或者如果你想使用绑定:
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
btn.addEventListener('click', say('hello'));
btn2.addEventListener('click', shout('yo'));
function saySomething(context, saying) {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
};
function say(word) {
var saying = word;
var container = document.getElementById('result1');
return saySomething.bind(undefined, context, saying);
}
function shout(word) {
var saying = word.toUpperCase();
var container = document.getElementById('result2');
return saySomething.bind(undefined, context, saying);
}
如果您创建了要绑定的新对象而不是使用 this
:
function say(word) {
return handleEvent.bind({
saying: word,
container: document.getElementById('result1')
});
}
function shout(word) {
return handleEvent.bind({
saying: word.toUpperCase(),
container: document.getElementById('result2')
});
}
但是,您仍然可以通过正常关闭来解决此问题:
function say(word) {
return makeHandleEvent(word, 'result1');
}
function shout(word) {
return makeHandleEvent(word.toUpperCase(), 'result2');
}
function makeHandleEvent(saying, id) {
var container = document.getElementById(id);
return function handleEvent() {
var text = document.createTextNode(saying);
container.innerHTML = '';
container.appendChild(text);
}
}