gpt4 book ai didi

JavaScript:针对冗余进行优化(循环 + 开关 + 键/值)

转载 作者:行者123 更新时间:2023-12-03 08:23:09 25 4
gpt4 key购买 nike

有更好的方法吗?

我有一个函数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 中减少重复代码的一个好方法是通过创建函数。
第二种是通过功能技术,这限制了您需要的循环管理样板的数量。

在下面的示例中,您将看到我创建的两个函数(getFormDatabuildFormEncodedString)的大小都相当小。
当然,他们还委托(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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com