虽然已知for...in会遍历对象原型链上的属性,但心想用于字面量建立的对象应该没有什么大问题,因而便弃hasOwnProperty于不顾,最终被工单教作人了。在修复中总结了几个可让遍历对象更加优雅的方法。数组
hasOwnProperty
?for...in
经常使用于遍历对象或者数组,好比bash
const obj = { a: 1, b: 2 }; for (const key in obj) { console.log(key, obj[key]); } // 输出 // a 1 // b 2 复制代码
咱们都知道for...in
会遍历原型链上的属性,因此通常会结合hasOwnProperty
来判断属性是否在对象自身上,而不是在原型链上。markdown
for (const key in obj) { if (obj.hasOwnProperty(key)) { console.log(key, obj[key]); } } 复制代码
可每次都要多增长一行代码,多一个缩进,实在麻烦,能不能偷懒不加hasOwnProperty? 因而我动起了当心思,使用字面量建立的对象或者数组,不是类的实例,原型链上干干净净的,那遍历的时候也不必判断了吧。因而就在遍历字面量对象时放心大胆地把hasOwnProperty
抛弃了。函数
我负责的产品是API,用户在本身的页面应用中引入使用。某天,有用户反馈若同时引入我家API和另外一个脚本库就会引起报错:工具
调试发现报错发生在:this
for (const key in renderLayers) { const layer = renderLayers[key]; if (!layer.isHidden()) { // ... } } 复制代码
renderLayers
是一个数组,这里本来是遍历可渲染图层进行操做,而图层对象都有isHidden
方法,为什么报错呢?缘由是用户另引入的脚本对Object
、Array
、String
等基础引用类型的原型链作了扩展,加入了一些方法。因此在for...in
遍历renderLayers
时,也遍历到了addRange
、clear
这些属性,layer
则赋值为一个function
,而不是图层对象。spa
Object.extend = function(dest, source, replace) { for(var prop in source) { if(replace == false && dest[prop] != null) { continue; } dest[prop] = source[prop]; } return dest; }; Object.extend(Array.prototype, { addRange: function(items) { if(items.length > 0) { for(var i=0; i < items.length; i++) { this.push(items[i]); } } }, clear: function() { this.length = 0; return this; }, // ... }, false); 复制代码
如上所述,只能开始内部大清理,全部使用for...in
而没有带hasOwnProperty
的地方都须要进行改造。除了加上hasOwnProperty
进行判断以外,视具体状况还可使用如下方法,让你的代码更加优雅:prototype
forEach
进行遍历好比引起报错的这一段,renderLayers
是一个数组,直接使用forEach
进行遍历便可:调试
renderLayers.filter(layer => !layer.isHidden()).forEach(layer => {
// ...
});
复制代码
for...in
可遍历对象属性实现一一赋值完成简单的对象深拷贝,这种操做能够用解构赋值来实现,更简单。code
function copy(obj) { return {...obj}; } const obj = { a: 1 }; const objCopy = copy(obj); console.log(objCopy); // 输出:{a: 1} 复制代码
Object.entries()
和forEach
Object.entries()
返回对象全部键值对组成的数组,再结合forEach
便可完成遍历。若只是遍历对象的键或者值,可使用Object.keys()
和Object.values()
。 在改造过程当中,能够抽象出一个forIn
方法做为工具函数,这样多处调用就能够省掉很多冗余代码啦~
function forIn(obj, callback) { Object.entries(obj).forEach(entry => { callback(...entry); }); } const obj = { a: 1 }; forIn(obj, (key, value) => { console.log(key, value); }); // 输出:a 1 复制代码
break
、return
提早结束循环,需结合for...of
方法3虽好,但使用forEach
没办法中断循环,这时候可使用for...of
,也是很是简洁的。
const obj = { a: 1, b: 2 }; for (let [key, value] of Object.entries(obj)) { if (value > 1) { break; } console.log(key, value); } // 输出:a 1 复制代码