下面,我将介绍ES 5中5个特别有用的链表方法,可以提高开发者的工作效率。
1.索引OF
indexOf方法返回链表中某个元素的索引值,如果链表中不存在该元素则返回-1
例如:检查“orange”在链表中的位置
(1)不要使用indexOf()
var arr = ['apple','orange','pear'], found = false; for(var i= 0, l = arr.length; i< l; i++){ if(arr[i] === 'orange'){ found = true; } } console.log("found:",found);
(2) 使用indexOf()
var arr = ['apple','orange','pear']; console.log("found:", arr.indexOf("orange") != -1);
代码就简单多了!
现在我有一个新的需求:我想知道一个字段中满足给定条件的所有元素。 该怎么办?
2.过滤
filter() 方法创建一个新的链表,其中包含指定字段中满足给定条件的所有元素
举个栗子:查找链表中所有名称为“orange”的元素
(1) 不带过滤器()
var arr = [ {"name":"apple", "count": 2}, {"name":"orange", "count": 5}, {"name":"pear", "count": 3}, {"name":"orange", "count": 16}, ]; var newArr = []; for(var i= 0, l = arr.length; i< l; i++){ if(arr[i].name === "orange" ){ newArr.push(arr[i]); } } console.log("Filter results:",newArr);
(2) 使用过滤器()
var arr = [ {"name":"apple", "count": 2}, {"name":"orange", "count": 5}, {"name":"pear", "count": 3}, {"name":"orange", "count": 16}, ]; var newArr = arr.filter(function(item){ return item.name === "orange"; }); console.log("Filter results:",newArr);
代码要简单得多。
3. foreach()
foreach() 方法对链表中的每个元素执行一次给定的方法
举个栗子:for循环和foreach()方法对比
function test(){ var arr = [1,2,3,4,5,6,7,8]; // Uses the usual "for" loop to iterate for(var i= 0, l = arr.length; i< l; i++){ console.log(arr[i]); } console.log("========================"); //Uses forEach to iterate arr.forEach(function(item,index){ console.log(item); }); }
foreach() 方法是编写 for 循环的升级方法。 我建议如果可以选择的话,应该尝试使用foreach()方法。
使用for循环时有一个很容易被忽视的问题:for循环中声明的变量(如上例中的var i=0)不是for循环中的局部变量,而是作用域内的局部变量for 循环的。 上面的例子中,for循环中声明的变量var i = 0实际上是test()范围内的局部变量,并且i特别容易被test()范围内的其他逻辑访问和重绘,造成一些问题。
事实上,jsperf的测试表明for循环的性能比foreach()要好得多。
不过我个人总觉得除非是处理百万级以上的大数据,否则我还是坚持使用foreach()方法。 节省毫秒量级的时间并不是提高产品性能的首要考虑因素。
4. 地图()
对链表的每个元素调用定义的回调函数,并返回包含结果的链表
举个栗子:解析一个链表,为链表中的每个元素添加fullname属性,并返回新的链表
(1)不要使用map()
var oldArr = [{first_name:"Colin",last_name:"Toh"},{first_name:"Addy",last_name:"Osmani"},{first_name:"Yehuda",last_name:"Katz"}]; function getNewArr(){ var newArr = []; for(var i= 0, l = oldArr.length; i< l; i++){ var item = oldArr[i]; item.full_name = [item.first_name,item.last_name].join(" "); newArr[i] = item; } return newArr; } console.log(getNewArr());
(2)使用map()
var oldArr = [{first_name:"Colin",last_name:"Toh"},{first_name:"Addy",last_name:"Osmani"},{first_name:"Yehuda",last_name:"Katz"}]; function getNewArr(){ return oldArr.map(function(item,index){ item.full_name = [item.first_name,item.last_name].join(" "); return item; }); } console.log(getNewArr());
map() 方法在涉及与服务器数据交互的轻量级 JavaScript 应用程序中非常有用。
5. 减少()
对链表中的所有元素调用指定的回调函数。该回调函数的返回值是累加结果,并且该返回值在下次调用回调函数时作为参数提供
说实话,在使用reduce()之前我权衡了很久。 reduce() 的概念对我来说非常具体,尤其是“累积”这个词。 直到我开始在nodeschool学习一系列JavaScript方法,我才逐渐掌握了reduce()的概念。 但直到 3 天前,当我构建自己的代码时,我仍然没有意识到它有多么有用,reduce() 真是太棒了!
举个栗子:解析一个字段,返回一个对象,其中包含链表中每个元素出现的次数
(1) 不使用reduce()
var arr = ["apple","orange","apple","orange","pear","orange"]; function getWordCnt(){ var obj = {}; for(var i= 0, l = arr.length; i< l; i++){ var item = arr[i]; obj[item] = (obj[item] +1 ) || 1; } return obj; } console.log(getWordCnt());
(2) 使用reduce()
var arr = ["apple","orange","apple","orange","pear","orange"]; function getWordCnt(){ return arr.reduce(function(prev,next){ prev[next] = (prev[next] + 1) || 1; return prev; },{}); } console.log(getWordCnt());
下面我阐述一下我个人对reduce()的理解。
reduce(callback,initialValue)有两个参数,回调函数和initialValue。 回调函数包含 4 个参数:prev、next、index 和 array。 我们通常只需要使用prev和next这两个参数即可。
prev 参数代表链表中的第一个元素,next 代表链表中的第二个元素。 注意:如果设置了initialValue参数,prev代表initialValue,next代表链表中的第一个元素。 比如上面的例子。 initialValue 设置为空白对象 {},则 prev 为 {}。
/* * Difference between not passing any parameters * and passing in a additional parameter into `reduce()` */ var arr = ["apple","orange"]; function noPassValue(){ return arr.reduce(function(prev,next){ console.log("prev:",prev); console.log("next:",next); return prev + " " +next; }); } function passValue(){ return arr.reduce(function(prev,next){ console.log("prev:",prev); console.log("next:",next); prev[next] = 1; return prev; },{}); } console.log("No Additional parameter:",noPassValue()); console.log("----------------"); console.log("With {} as an additional parameter:",passValue());
在上面的代码中,每次迭代都会返回一个值jquery创建元素节点,该值作为下一次迭代的 prev 参数传入。
下面的代码将更加清楚地展示reduce()的功能:
var arr = ["apple","orange","apple","pear"]; function getWordCnt(){ return arr.reduce(function(prev,next,index){ console.log("Iteration "+index+""); console.log("prev:",prev); console.log("next:",next); prev[next] = ++prev[next] || 1; console.log("Passing this to the 'prev' of the next iteration if any:",prev); console.log("---------------"); return prev; },{}); } console.log("Final Object:",getWordCnt());
去方法化
上面提到的方法实际上只针对字段jquery创建元素节点,但它也可以用于节点列表、Jquery 对象甚至字符串。 我们可以通过“去方法化”技术来扩展这个链表方法。
// Demethodizing the Array method, forEach(), into a generic "each" var each = Function.prototype.call.bind([].forEach); var nodeList = document.querySelectorAll("p"); each(nodeList,bold); function bold(node){ node.style.fontWeight ="bold"; }
我们通过Function.prototype.call.bind将foreach方法扩展为函数类的each方法,现在each方法可以被链表以外的对象使用。
浏览器支持
根据ECMAScript 5兼容性表,以上5种方法可以在所有移动浏览器和几乎所有桌面浏览器中使用(当我说“全部”时,请自觉离开IE9以下的浏览器)。