合并类似功能 DRY
Consolidate Similar Functions DRY
我有这两个非常相似的功能。我考虑过使用字符串和 eval('Man')
,但如果可能的话,我很想避免这种情况。怎么把两者抽象出来,就只有一个功能?
function showMan() {
widget.classList.add(toggle);
fx.wipeOut({
node: calWoman
}).play();
fx.wipeOut({
node: pointsWoman
}).play();
pointsMan.classList.remove(toggle);
fx.wipeIn({
node: calMan
}).play();
fx.wipeIn({
node: pointsMan
}).play();
mtFields();
inputMan.focus();
}
function showWoman() {
widget.classList.add(toggle);
fx.wipeOut({
node: calMan
}).play();
fx.wipeOut({
node: pointsMan
}).play();
pointsWoman.classList.remove(toggle);
fx.wipeIn({
node: calWoman
}).play();
fx.wipeIn({
node: pointsWoman
}).play();
mtFields();
inputWoman.focus();
}
/** @todo abstract and create one function - showPerson('Man') */
function showPerson(calPerson, pointsPerson, inputPerson) {
//replace calWoman and calMan with calPerson
//replace pointsMan and pointsWoman with pointsPerson
//replace inputMan and inputWoman with inputPerson
}
如果您不能传入它,您可以使用闭包来初始化带有这些引用的函数。
function showPerson(calPerson, pointsPerson, inputPerson) {
function showingPersonWithReferences() {
//replace calWoman and calMan with calPerson
//replace pointsMan and pointsWoman with pointsPerson
//replace inputMan and inputWoman with inputPerson
}
return showingPersonWithReferences;
}
这是javascript中的一点函数式编程。
创建函数 showPerson
,它接受 gender
作为参数。
从那里,您可以创建一个对象,在其中封装特定性别的函数,然后引用它的相反函数:
function showPerson(gender) {
var optionsObj = {
man: {
cal: calMan,
points: pointsMan,
input: inputMan.focus,
},
woman: {
cal: calWoman,
points: pointsWoman,
input: inputWoman.focus,
}
}
gender === 'man' ? optionsObj[gender].opposite = optionsObj.woman : optionsObj[gender].opposite = optionsObj.man;
widget.classList.add(toggle)
fx.wipeOut({
node: optionsObj[gender].cal,
}).play();
fx.wipeOut({
node: optionsObj[gender].points
}).play();
optionsObj[gender].points.classList.remove(toggle);
fx.wipeIn({
node: optionsObj[gender].opposite.cal
}).play();
fx.wipeIn({
node: optionsObj[gender].opposite.points
}).play();
mtFields();
optionsObj[gender].input()
}
如果将所有变量合并到一个对象中会更容易。
function showPerson(sex) {
var people = {
woman: {
cal: calWoman,
points: pointsWoman,
input: inputWoman
},
man: {
cal: calMan,
points: pointsMan,
input: inputMan
}
};
sex = sex.toLowerCase();
var otherSex = sex === 'man' ? 'woman' : 'man';
var show = people[sex];
var hide = people[otherSex]
widget.classList.add(toggle);
fx.wipeOut({
node: hide.cal
}).play();
fx.wipeOut({
node: hide.points
}).play();
show.points.classList.remove(toggle);
fx.wipeIn({
node: show.cal
}).play();
fx.wipeIn({
node: show.points
}).play();
mtFields();
show.input.focus();
}
// usage
showPerson('man');
showPerson('woman');
考虑这里所有内容的顺序有点令人困惑,但诀窍不是将两个巨大的功能分解为一个,而是将您的系统分解为可以更好地组合的更小部分。
function hideNode ( node ) { fx.wipeOut({ node: node }).play(); }
function revealNode ( node ) { fx.wipeIn({ node: node }).play(); }
function showPerson (removalList, revealList, points, input) {
widget.classList.add(toggle);
removalList.forEach(hideNode);
points.classList.remove(toggle);
revealList.forEach(revealNode);
input.focus();
}
// somewhere NORTH of your current function
var womanList = [calWoman, pointsWoman];
var manList = [calMan, pointsMan];
var revealList, removalList, input, points;
if (man) {
removalList = womanList;
revealList = manList;
input = inputMan;
points = pointsMan;
} else {
removalList = manList;
revealList = womanList;
input = inputWoman;
points = pointsWoman;
}
// alternatively, these can be stored in an object this way, and pulled by a flag, rather than by an if statement...
showPerson( removalList, revealList, points, input );
如果您注意到,逻辑非常简单,依靠将参数传递到我的函数中。
选择值的逻辑也很简单,但我已经将选择的需要移到了函数之外;那是其他人关心的问题(即使它是一个新函数,除了选择并传递适当的值外什么都不做)。
我已经在函数中执行了重复步骤,并将它们分解为更小的函数,并且我正在使用列表(甚至只是两个列表),这样我就可以忽略某件事重复了多少次的细节被调用... ...它被调用的次数与你派给我的人一样多。
我还没有解决 "Who calls showPerson, with what and what access...",但这是解决更具体问题的方法;总结使用 if () { }
和值 setting/passing 的人非常快,从这里开始。
这远非干净的成品,但它所做的 提供的是了解如何在更大的项目中处理这些移动部分。
编辑
为了更进一步,并表明您不需要在重写方面做太多事情,在这里(至少一开始不需要),我将进一步添加:
function getPersonConfig ( type ) {
var config = {
man: { /* ... */ },
woman: { /* ... */ }
};
return config[type];
}
function showMan () {
var config = getPersonConfig( "man" );
showPerson( config );
}
function showWoman () {
var config = getPersonConfig( "woman" );
showPerson( config );
}
我正在使用稍微我的showPerson
功能的不同版本...
在其中,我传递了一个对象(而不是单独的变量),但这就是我需要更改的全部内容。
看看这些可组合的小函数给我买了什么...
您根本不需要更改 showMan
或 showWoman
。
相反,您正在劫持它们过去的样子,并使用它们来调用更小的函数,这些函数执行相同的工作,但现在更可分离和可重用。
这是一个 "facade" 或 "veneer",通常在工程中,它是一个 API 或正在谈论的服务,但它的基本意思是当你想要要更新代码,如果您可以保持方法名称、输入和输出以及所有结果相同(从外界可以看出),那么您可以随心所欲地更改代码的内部结构。
showMan
仍在调用,它正在做的事情现在仍在做,没有添加或删除任何内容。
与 showWoman
.
相同
所以你已经成功地保留了外观,同时更换了内部结构。
外立面也可以反过来;按照您希望它向外界展示的方式编写新的 service/API,并以将旧代码挂钩到新结构所需的最低限度将其发布给世界,然后将新功能填充为你去吧。
希望对您有所帮助。
尽管上面提供了出色的解决方案和建议,但这是我最终所做的,它最适合我的情况(最少重写,最干燥)。非常感谢您回答问题。
function showPerson() {
/**
* the element being hidden should be placed in the first parameter
* @param {object} woman - HTMLFormElement (pointsWoman)
* @param {object} man - HTMLFormElement (pointsMan)
* @example showPerson(pointsWoman, pointsMan);
*/
if (arguments[0] instanceof HTMLFormElement && arguments[1] instanceof HTMLFormElement) {
widget.classList.add(toggle);
fx.wipeOut({
node: arguments[0]
}).play();
arguments[1].classList.remove(toggle);
fx.wipeIn({
node: arguments[1]
}).play();
mtFields();
arguments[1][0].focus();
}
else {
throw new Error('You need to provide the forms to show/hide');
}
}
我有这两个非常相似的功能。我考虑过使用字符串和 eval('Man')
,但如果可能的话,我很想避免这种情况。怎么把两者抽象出来,就只有一个功能?
function showMan() {
widget.classList.add(toggle);
fx.wipeOut({
node: calWoman
}).play();
fx.wipeOut({
node: pointsWoman
}).play();
pointsMan.classList.remove(toggle);
fx.wipeIn({
node: calMan
}).play();
fx.wipeIn({
node: pointsMan
}).play();
mtFields();
inputMan.focus();
}
function showWoman() {
widget.classList.add(toggle);
fx.wipeOut({
node: calMan
}).play();
fx.wipeOut({
node: pointsMan
}).play();
pointsWoman.classList.remove(toggle);
fx.wipeIn({
node: calWoman
}).play();
fx.wipeIn({
node: pointsWoman
}).play();
mtFields();
inputWoman.focus();
}
/** @todo abstract and create one function - showPerson('Man') */
function showPerson(calPerson, pointsPerson, inputPerson) {
//replace calWoman and calMan with calPerson
//replace pointsMan and pointsWoman with pointsPerson
//replace inputMan and inputWoman with inputPerson
}
如果您不能传入它,您可以使用闭包来初始化带有这些引用的函数。
function showPerson(calPerson, pointsPerson, inputPerson) {
function showingPersonWithReferences() {
//replace calWoman and calMan with calPerson
//replace pointsMan and pointsWoman with pointsPerson
//replace inputMan and inputWoman with inputPerson
}
return showingPersonWithReferences;
}
这是javascript中的一点函数式编程。
创建函数 showPerson
,它接受 gender
作为参数。
从那里,您可以创建一个对象,在其中封装特定性别的函数,然后引用它的相反函数:
function showPerson(gender) {
var optionsObj = {
man: {
cal: calMan,
points: pointsMan,
input: inputMan.focus,
},
woman: {
cal: calWoman,
points: pointsWoman,
input: inputWoman.focus,
}
}
gender === 'man' ? optionsObj[gender].opposite = optionsObj.woman : optionsObj[gender].opposite = optionsObj.man;
widget.classList.add(toggle)
fx.wipeOut({
node: optionsObj[gender].cal,
}).play();
fx.wipeOut({
node: optionsObj[gender].points
}).play();
optionsObj[gender].points.classList.remove(toggle);
fx.wipeIn({
node: optionsObj[gender].opposite.cal
}).play();
fx.wipeIn({
node: optionsObj[gender].opposite.points
}).play();
mtFields();
optionsObj[gender].input()
}
如果将所有变量合并到一个对象中会更容易。
function showPerson(sex) {
var people = {
woman: {
cal: calWoman,
points: pointsWoman,
input: inputWoman
},
man: {
cal: calMan,
points: pointsMan,
input: inputMan
}
};
sex = sex.toLowerCase();
var otherSex = sex === 'man' ? 'woman' : 'man';
var show = people[sex];
var hide = people[otherSex]
widget.classList.add(toggle);
fx.wipeOut({
node: hide.cal
}).play();
fx.wipeOut({
node: hide.points
}).play();
show.points.classList.remove(toggle);
fx.wipeIn({
node: show.cal
}).play();
fx.wipeIn({
node: show.points
}).play();
mtFields();
show.input.focus();
}
// usage
showPerson('man');
showPerson('woman');
考虑这里所有内容的顺序有点令人困惑,但诀窍不是将两个巨大的功能分解为一个,而是将您的系统分解为可以更好地组合的更小部分。
function hideNode ( node ) { fx.wipeOut({ node: node }).play(); }
function revealNode ( node ) { fx.wipeIn({ node: node }).play(); }
function showPerson (removalList, revealList, points, input) {
widget.classList.add(toggle);
removalList.forEach(hideNode);
points.classList.remove(toggle);
revealList.forEach(revealNode);
input.focus();
}
// somewhere NORTH of your current function
var womanList = [calWoman, pointsWoman];
var manList = [calMan, pointsMan];
var revealList, removalList, input, points;
if (man) {
removalList = womanList;
revealList = manList;
input = inputMan;
points = pointsMan;
} else {
removalList = manList;
revealList = womanList;
input = inputWoman;
points = pointsWoman;
}
// alternatively, these can be stored in an object this way, and pulled by a flag, rather than by an if statement...
showPerson( removalList, revealList, points, input );
如果您注意到,逻辑非常简单,依靠将参数传递到我的函数中。
选择值的逻辑也很简单,但我已经将选择的需要移到了函数之外;那是其他人关心的问题(即使它是一个新函数,除了选择并传递适当的值外什么都不做)。
我已经在函数中执行了重复步骤,并将它们分解为更小的函数,并且我正在使用列表(甚至只是两个列表),这样我就可以忽略某件事重复了多少次的细节被调用... ...它被调用的次数与你派给我的人一样多。
我还没有解决 "Who calls showPerson, with what and what access...",但这是解决更具体问题的方法;总结使用 if () { }
和值 setting/passing 的人非常快,从这里开始。
这远非干净的成品,但它所做的 提供的是了解如何在更大的项目中处理这些移动部分。
编辑
为了更进一步,并表明您不需要在重写方面做太多事情,在这里(至少一开始不需要),我将进一步添加:
function getPersonConfig ( type ) {
var config = {
man: { /* ... */ },
woman: { /* ... */ }
};
return config[type];
}
function showMan () {
var config = getPersonConfig( "man" );
showPerson( config );
}
function showWoman () {
var config = getPersonConfig( "woman" );
showPerson( config );
}
我正在使用稍微我的showPerson
功能的不同版本...
在其中,我传递了一个对象(而不是单独的变量),但这就是我需要更改的全部内容。
看看这些可组合的小函数给我买了什么...
您根本不需要更改 showMan
或 showWoman
。
相反,您正在劫持它们过去的样子,并使用它们来调用更小的函数,这些函数执行相同的工作,但现在更可分离和可重用。
这是一个 "facade" 或 "veneer",通常在工程中,它是一个 API 或正在谈论的服务,但它的基本意思是当你想要要更新代码,如果您可以保持方法名称、输入和输出以及所有结果相同(从外界可以看出),那么您可以随心所欲地更改代码的内部结构。
showMan
仍在调用,它正在做的事情现在仍在做,没有添加或删除任何内容。
与 showWoman
.
相同
所以你已经成功地保留了外观,同时更换了内部结构。
外立面也可以反过来;按照您希望它向外界展示的方式编写新的 service/API,并以将旧代码挂钩到新结构所需的最低限度将其发布给世界,然后将新功能填充为你去吧。
希望对您有所帮助。
尽管上面提供了出色的解决方案和建议,但这是我最终所做的,它最适合我的情况(最少重写,最干燥)。非常感谢您回答问题。
function showPerson() {
/**
* the element being hidden should be placed in the first parameter
* @param {object} woman - HTMLFormElement (pointsWoman)
* @param {object} man - HTMLFormElement (pointsMan)
* @example showPerson(pointsWoman, pointsMan);
*/
if (arguments[0] instanceof HTMLFormElement && arguments[1] instanceof HTMLFormElement) {
widget.classList.add(toggle);
fx.wipeOut({
node: arguments[0]
}).play();
arguments[1].classList.remove(toggle);
fx.wipeIn({
node: arguments[1]
}).play();
mtFields();
arguments[1][0].focus();
}
else {
throw new Error('You need to provide the forms to show/hide');
}
}