- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有更好的方法吗?
我有一个函数element.getFormData
,如果使用表单中的任何元素(例如提交按钮)调用,它会构建参数化字符串。这只是一个收集表单中所有输入值的简单循环。我喜欢它的是,如果它检测到文件上传,它也会硬返回,无论如何你都必须这样做,以便适当的替代方法可以处理这种情况。我不喜欢它的是循环中的冗余。我会告诉你我的意思。
element.getFormData =
function(_R)
{ var vars="";var form=this,i=0,n,o,en=encodeURIComponent;
while(form){if('FORM'===form.tagName)break;form=form.parentNode}
form=form.getElementsByTagName('*');
while(n=form[i++])
{ switch((n.type||'').toLowerCase())
{ case'file':
if(_R)
return false;
case'radio':
case'checkbox':
if(n.checked)
vars+= "&" + en(n.name||n.id)
+ "=" + en(n.value);
break;
break;
case'select-multiple':
for(var k=0;o=n.options[k++];)
if(o.selected)
vars+= "&" + en(n.name||n.id)
+ "=" + en(o.value||o.text);
break;
default:
switch(n.tagName)
{ case'INPUT':
case'TEXTAREA':
vars+= "&" + en(n.name||n.id)
+ "=" + en(n.value);
break;
break;
case'SELECT':
vars+= "&" + en(n.name||n.id)
+ "=" + en((o=n.options[n.selectedIndex]).value||o.text);
}
}
}
return vars
};
因此,它基本上对每种输入类型执行相同的操作,只是将键值对作为字符串附加。这让我感觉它应该得到巩固。我们甚至可以看到,至少关键部分 vars+= "&"+ en(n.name||n.id)
对于每一个都是完全相同的。
这样的情况似乎是语言的限制:我们在循环内使用开关来共享逻辑指令,但每种情况的具体变化足以导致冗余。有时,我们只是略有不同,有时,我们有其他区别因素,有时我们必须将该逻辑放入另一个循环中。然而,无论如何,它本质上是相同的逻辑,并且应该在方法论和/或语言的构造中进行简化。
那么,在我进一步讨论之前,有人有更好的方法吗?
因为,现在我有另一个函数 element.getFormDataObject
因为,虽然该函数返回了我的所有数据,但它是在字符串中,但是如果我需要修改该数据怎么办?所以这个函数基本上做同样的事情,但返回一个对象。对我来说,总是返回一个对象,然后将其转换为字符串是没有意义的,因为当您只需要一个字符串时,这将是不必要的开销。我用功能开销换取了 Assets 开销。 (如果它检测到文件上传,则无法执行硬返回,因为它假设您调用它时需要数据。)
element.getFormDataObject =
function( )
{ var data={};var form=this,i=0,n,o;
while(form=form.parentNode){if('FORM'===form.tagName)break}
form=form.getElementsByTagName('*');
while(n=form[i++])
{ switch((n.type||'').toLowerCase())
{ case 'radio':
case 'checkbox':
if(n.checked)
data[n.name||n.id]=n.value;
break;
break;
case 'select-multiple':
for(var k=0;o=n.options[k++];)
if(o.selected)
(data[n.name||n.id]=data[n.name||n.id]||[]).push(o.value||o.text);
break;
default:
switch(n.tagName)
{ case'INPUT':
case'TEXTAREA':
data[n.name||n.id]=n.value;
break;
break;
case'SELECT':
data[n.name||n.id]=(o=n.options[n.selectedIndex]).value||o.text
}
}
}
return data
};
这又是一个冗余的情况。这就像我们需要能够为每种情况和数据类型指定模板,并且只需在一个循环内发出一个简单的逻辑指令。
此外,实际上我仍然需要 element.toFormData
将对象转换为字符串。
element.toFormData =
function( )
{ var text="",en=encodeURIComponent;
for(var k in this)
{ if(typeof this[k]==='string')
text+= "&" + en(k)
+ "=" + en(this[k])
else
for(var i in this[k])
text+= "&" + en(k)+"["+i+"]"
+ "=" + en(this[k][i])
}
return text
};
因此,我们在整个实现过程中有很多冗余逻辑。
非常感谢任何想法!!!
最佳答案
在 JS 中减少重复代码的一个好方法是通过创建函数。
第二种是通过功能技术,这限制了您需要的循环管理样板的数量。
在下面的示例中,您将看到我创建的两个函数(getFormData
和 buildFormEncodedString
)的大小都相当小。
当然,他们还委托(delegate)给许多命名帮助程序,通常长 1-5 行,并且总文件大小也增加了。
许多帮助器本身可以使用高阶函数删除
// instead of
function isSelected (option) { return option.selected; }
function isChecked (input) { return input.checked; }
function isDisabled (input) { return input.disabled; }
inputs.filter(isChecked).filter(isDisabled);
// higher-order function
function is (trait) {
return function (obj) { return obj[trait]; };
}
// implementation of "not" should be straightforward, once "is" is understood
inputs.filter(not(is("disabled"))).filter(is("checked"));
即使切换到 ES6 语法,并且仅使用解构和箭头 lambda 也可以增加清晰度并减少过多的阅读:
// instead of
function appendKeyValueToObject (object, pair) {
var key = pair[0];
var value = pair[1];
object[key] = value;
return object;
}
// ES6 allows
function appendKeyValueToObject (object, [key, value]) {
object[key] = value;
return object;
}
// instead of
inputs
.filter(function (input) {
return input.type !== "file";
})
.map(function (input) {
return [input.name, input.value];
});
// ES6 allows
inputs.filter(input => input.type !== "file").map(input => [input.name, input.value]);
无论如何,现在已经完成了很多工作,需要担心的移动部件越来越少。
您提到您不想通过让函数解析表单并让另一个函数转换数据来产生“开销”......但是您所谈论的开销(从性能 Angular 来看)是非常小的(与使用 Canvas 以 60fps 运行 OpenGL 游戏相比)。它还具有额外的好处,即能够出于任何原因(多部分表单上传、JSON 上传等)将数据弹出到您想要的任何转换中。通过强制你的函数做多项事情(抓取元素,找到最近的表单祖先,找到所有元素,无论它们是用于输入还是布局,拉出所有键/值对,将它们插入字符串中),你已经完全排除了这种能力编写您最初想要的可重用函数。
看一下包含的示例,希望这种级别的分离的好处以及更多基于集合的技术将变得显而易见。
initializePageListeners();
function initializePageListeners () {
var trigger = query("#trigger-collection");
var jsonArea = query("#print-data");
var uriArea = query("#print-uri");
trigger.onclick = function () {
var form = query("#PersonForm");
var data = getFormData(form);
jsonArea.value = JSON.stringify(data);
uriArea.value = buildFormEncodedString(data);
};
}
function getFormData (form, keepFiles) {
var inputs = queryAll("input", form);
var scalarInputs = inputs.filter(isInputActive).filter(isNotFile);
var textareas = queryAll("textarea", form);
var selects = queryAll("select", form);
var inputValues = concat(scalarInputs, textareas).map(extractInputNameValuePair);
var inputFiles = !keepFiles ? [] : inputs.filter(isFile).map(extractInputFiles);
var selectValues = selects.map(extractNameValueSets);
var formData = buildFormData([inputValues, inputFiles, selectValues]);
return formData;
}
function buildFormData (inputs) {
return inputs.reduce(concat, []).reduce(appendKeyValueToObject, {});
}
function buildFormEncodedString (data) {
var encodedString = Object.keys(data)
.map(function (key) { return [ key, data[key] ]; })
.map(function (pair) {
var key = pair[0];
var value = pair[1];
return Array.isArray(value) ? formEncodePairs(key, value) : formEncodePair(key, value);
}).join("&");
return encodedString;
}
function formEncodePair (key, value) {
return [key, value].map(encodeURIComponent).join("=");
}
function formEncodePairs (key, values) {
return values.map(function (value) { return formEncodePair(key, value); }).join("&");
}
function appendKeyValueToObject (obj, pair) {
var key = pair[0];
var value = pair[1];
var keyExists = (key in obj);
if (keyExists) {
obj[key] = concat(obj[key], value);
} else {
obj[key] = value;
}
return obj;
}
function extractNameValueSets (select) {
var multiple = select.type === "select-multiple";
var name = select.name;
var options = slice(select.options);
var selectedOptions = options.filter(isSelected).map(function (option) { return option.value || option.text; });
return [ name, multiple ? selectedOptions : selectedOptions[0] ];
}
function extractInputFiles (input) {
var key = input.name || input.id;
var files = input.files;
return [key, files];
}
function extractInputNameValuePair (input) {
var value = input.value;
var key = input.name || input.id;
return [key, value];
}
function isSelected (option) { return option.selected; }
function isFile (input) { return input.type === "file"; }
function isNotFile (input) { return !isFile(input); }
function isInputActive (input) {
var canCheck = /radio|checkbox/i.test(input.type);
return canCheck ? input.checked : true;
}
function query (selector, node) {
var root = node || document;
return root.querySelector(selector);
}
function queryAll (selector, node) {
var root = node || document;
return slice(root.querySelectorAll(selector));
}
function concat (a, b) {
return [].concat(a).concat(b);
}
function slice (arrLike, start, end) {
return [].slice.call(arrLike, start, end);
}
* { box-sizing: border-box; }
#print-data, #print-uri {
display: block;
width: 100%;
}
<form id="PersonForm">
<fieldset >
<legend >Name</legend>
<label >first: <input name="firstName"></label>
<label >last: <input name="lastName"></label>
</fieldset>
<fieldset >
<legend >Gender</legend>
<label >male: <input name="gender" value="male" type="radio"></label>
<label >female: <input name="gender" value="female" type="radio"></label>
</fieldset>
<fieldset >
<legend >Language Experience</legend>
<label >JavaScript
<select name="jsExperience">
<option>Amateur</option>
<option selected>Apprentice</option>
<option>Journeyman</option>
<option>Expert</option>
<option>Master</option>
</select>
</label>
<label >CSS
<select name="cssExperience">
<option>Amateur</option>
<option selected>Apprentice</option>
<option>Journeyman</option>
<option>Expert</option>
<option>Master</option>
</select>
</label>
</fieldset>
<fieldset >
<legend >Paradigm Experience</legend>
<label >Select all that apply
<select name="paradigms" multiple>
<option value="Object Oriented" selected>OO</option>
<option selected>Functional</option>
<option >Aspect Oriented</option>
<option >Behaviour Driven Design</option>
</select>
</fieldset>
</form>
<button id="trigger-collection">get data</button>
<textarea id="print-data" style="display:block"></textarea>
<textarea id="print-uri" style="display:block"></textarea>
关于JavaScript:针对冗余进行优化(循环 + 开关 + 键/值),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33663211/
我是 PHP 新手。我一直在脚本中使用 for 循环、while 循环、foreach 循环。我想知道 哪个性能更好? 选择循环的标准是什么? 当我们在另一个循环中循环时应该使用哪个? 我一直想知道要
我在高中的编程课上,我的作业是制作一个基本的小计和顶级计算器,但我在一家餐馆工作,所以制作一个只能让你在一种食物中读到。因此,我尝试让它能够接收多种食品并将它们添加到一个价格变量中。抱歉,如果某些代码
这是我正在学习的一本教科书。 var ingredients = ["eggs", "milk", "flour", "sugar", "baking soda", "baking powder",
我正在从字符串中提取数字并将其传递给函数。我想给它加 1,然后返回字符串,同时保留前导零。我可以使用 while 循环来完成此操作,但不能使用 for 循环。 for 循环只是跳过零。 var add
编辑:我已经在程序的输出中进行了编辑。 该程序要求估计给定值 mu。用户给出一个值 mu,同时还提供了四个不等于 1 的不同数字(称为 w、x、y、z)。然后,程序尝试使用 de Jaeger 公式找
我正在编写一个算法,该算法对一个整数数组从末尾到开头执行一个大循环,其中包含一个 if 条件。第一次条件为假时,循环可以终止。 因此,对于 for 循环,如果条件为假,它会继续迭代并进行简单的变量更改
现在我已经习惯了在内存非常有限的情况下进行编程,但我没有答案的一个问题是:哪个内存效率更高;- for(;;) 或 while() ?还是它们可以平等互换?如果有的话,还要对效率问题发表评论! 最佳答
这个问题已经有答案了: How do I compare strings in Java? (23 个回答) 已关闭 8 年前。 我正在尝试创建一个小程序,我可以在其中读取该程序的单词。如果单词有 6
这个问题在这里已经有了答案: python : list index out of range error while iteratively popping elements (12 个答案) 关
我正在尝试向用户请求 4 到 10 之间的整数。如果他们回答超出该范围,它将进入循环。当用户第一次正确输入数字时,它不会中断并继续执行 else 语句。如果用户在 else 语句中正确输入数字,它将正
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我想要做的事情是使用循环创建一个数组,然后在另一个类中调用该数组,这不会做,也可能永远不会做。解决这个问题最好的方法是什么?我已经寻找了所有解决方案,但它们无法编译。感谢您的帮助。 import ja
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我正在模拟一家快餐店三个多小时。这三个小时分为 18 个间隔,每个间隔 600 秒。每个间隔都会输出有关这 600 秒内发生的情况的统计信息。 我原来的结构是这样的: int i; for (i=0;
这个问题已经有答案了: IE8 for...in enumerator (3 个回答) How do I check if an object has a specific property in J
哪个对性能更好?这可能与其他编程语言不一致,所以如果它们不同,或者如果你能用你对特定语言的知识回答我的问题,请解释。 我将使用 c++ 作为示例,但我想知道它在 java、c 或任何其他主流语言中的工
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我是 C 编程和编写代码的新手,以确定 M 测试用例的质因数分解。如果我一次只扫描一次,该功能本身就可以工作,但是当我尝试执行 M 次时却惨遭失败。 我不知道为什么 scanf() 循环有问题。 in
这个问题已经有答案了: JavaScript by reference vs. by value [duplicate] (4 个回答) 已关闭 3 年前。 我在使用 TSlint 时遇到问题,并且理
我尝试在下面的代码中添加 foreach 或 for 循环,以便为 Charts.js 创建多个数据集。这将允许我在此折线图上创建多条线。 我有一个 PHP 对象,我可以对其进行编码以稍后填充变量,但
我是一名优秀的程序员,十分优秀!