• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
邹天得
博客园    首页    新随笔    联系   管理    订阅  订阅
javascript遍历介绍

一、判断对象中是否存在某个属性

先介绍一些方法,如下。

in:该操作会检查属性是否在对象及其[[Prototype]]原型链中,需要注意的是该操作检查的是属性名的存在性,而不是属性值;

  如果对象的某个属性的enumerable设置成false,则该属性不会出现在for...in遍历中;

  最好只在对象上运用for...in循环,遍历数组建议使用传统的for循环遍历来遍历数值索引,因为在数组上运用for...in时,不仅会包含所有数值索引,还会包括所有可枚举属性。
hasOwnProperty:只会检查属性是否在某个对象中,而不检查原型链。
propertyIsEnumerable:检查给定的属性名是否直接存在于对象中(而不是在原型链中)并且满足enumerable:true。
Object.keys:会返回一个数组,包括所有可枚举属性。
Object.getOwnPropertyNames:会返回一个数组,包括所有属性,无论属性是否可枚举。

 用法举例:

var myObject = { };
Object.defineProperty(
myObject,
"a",
// 让 a 像普通属性一样可以枚举
{ enumerable: true, value: 2 }
);
Object.defineProperty(
myObject,
"b",
// 让 b 不可枚举
{ enumerable: false, value: 3 }
);
myObject.b; // 3
("b" in myObject); // true
myObject.hasOwnProperty( "b" ); // true
// .......
for (var k in myObject) {
console.log( k, myObject[k] );
}

// "a" 2

var myObject = { };
Object.defineProperty(
myObject,
"a",
// 让 a 像普通属性一样可以枚举
{ enumerable: true, value: 2 }
);
Object.defineProperty(
myObject,
"b",
// 让 b 不可枚举
{ enumerable: false, value: 3 }
);
myObject.propertyIsEnumerable( "a" ); // true
myObject.propertyIsEnumerable( "b" ); // false
Object.keys( myObject ); // ["a"]
Object.getOwnPropertyNames( myObject ); // ["a", "b"]

 

二、遍历属性的值

1.传统for循环

对于数值索引的数组来说, 可以使用标准的 for 循环来遍历值:
var myArray = [1, 2, 3];
for (var i = 0; i < myArray.length; i++) {
  console.log( myArray[i] );
} /
/ 1 2 3
这实际上并不是在遍历值, 而是遍历下标来指向值, 如 myArray[i]。

2.ES5数组的辅助迭代器

ES5 中增加了一些数组的辅助迭代器, 包括 forEach(..)、 every(..) 和 some(..)。 每种辅助迭代器都可以接受一个回调函数并把它应用到数组的每个元素上, 唯一的区别就是它们对于回调函数返回值的处理方式不同。
forEach(..) 会遍历数组中的所有值并忽略回调函数的返回值。 every(..) 会一直运行直到
回调函数返回 false( 或者“ 假” 值), some(..) 会一直运行直到回调函数返回 true( 或者“ 真” 值)。

every(..) 和 some(..) 中特殊的返回值和普通 for 循环中的 break 语句类似, 它们会提前终止遍历。
使用 for..in 遍历对象是无法直接获取属性值的, 因为它实际上遍历的是对象中的所有可枚举属性, 你需要手动获取属性值。

遍历数组下标时采用的是数字顺序( for 循环或者其他迭代器), 但是遍历对象属性时的顺序是不确定的, 在不同的 JavaScript 引擎中可能不一样。 因此,在不同的环境中需要保证一致性时, 一定不要相信任何观察到的顺序, 它们是不可靠的。

用法示例:

var arryAll = [3, 5, 2];
arryAll.forEach(function(e){
console.log(e);
})

var arr = [ 1, 2, 3, 4, 5, 6 ];

console.log( arr.some( function( item, index, array ){
console.log( 'item=' + item + ',index='+index+',array='+array );
return item > 3;
}));

console.log( arr.every( function( item, index, array ){
console.log( 'item=' + item + ',index='+index+',array='+array );
return item > 3;
}));

 

3.ES6数组的for...of

var myArray = [ 1, 2, 3 ];
for (var v of myArray) {
console.log( v );
} /
/ 1
// 2
// 3

for..of 循环首先会向被访问对象请求一个迭代器对象, 然后通过调用迭代器对象的next() 方法来遍历所有返回值。
数组有内置的 @@iterator, 因此 for..of 可以直接应用在数组上。 我们使用内置的 @@iterator 来手动遍历数组, 看看它是怎么工作的:
var myArray = [ 1, 2, 3 ];
var it = myArray[Symbol.iterator]();
it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { done:true }

如你所见, 调用迭代器的 next() 方法会返回形式为 { value: .. , done: .. } 的值,value 是当前的遍历值, done 是一个布尔值, 表示是否还有可以遍历的值。
注意, 和值“ 3” 一起返回的是 done:false, 乍一看好像很奇怪, 你必须再调用一次next() 才能得到 done:true, 从而确定完成遍历。 这个机制和 ES6 中发生器函数的语义相关, 不过已经超出了我们的讨论范围。


和数组不同, 普通的对象没有内置的 @@iterator, 所以无法自动完成 for..of 遍历。 之所以要这样做, 有许多非常复杂的原因, 不过简单来说, 这样做是为了避免影响未来的对象类型。
当然, 你可以给任何想遍历的对象定义 @@iterator, 举例来说:

var myObject = {
a: 2,
b: 3
};
Object.defineProperty( myObject, Symbol.iterator, {
  enumerable: false,
  writable: false,
  configurable: true,
  value: function() {
    var o = this;
    var idx = 0;
    var ks = Object.keys( o );
    return {
      next: function() {
        return {
          value: o[ks[idx++]],
          done: (idx > ks.length)
        };
      }
  };
}
} );
// 手动遍历 myObject
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { value:undefned, done:true }
// 用 for..of 遍历 myObject
for (var v of myObject) {
console.log( v );
}

// 2
// 3

for..of 循环每次调用 myObject 迭代器对象的 next() 方法时, 内部的指针都会向前移动并返回对象属性列表的下一个值( 再次提醒, 需要注意遍历对象属性 / 值时的顺序)。

实际上, 你甚至可以定义一个“ 无限” 迭代器, 它永远不会“ 结束” 并且总会返回一个新
值( 比如随机数、 递增值、 唯一标识符, 等等)。 你可能永远不会在 for..of 循环中使用这
样的迭代器, 因为它永远不会结束, 你的程序会被挂起:
var randoms = {
  [Symbol.iterator]: function() {
    return {
      next: function() {
        return { value: Math.random() };
      }
    };
  }
};
var randoms_pool = [];
for (var n of randoms) {
  randoms_pool.push( n );
  // 防止无限运行!
  if (randoms_pool.length === 100) break;
}
这个迭代器会生成“ 无限个” 随机数, 因此我们添加了一条 break 语句, 防止程序被挂起。

posted on 2017-04-09 00:17  邹天得  阅读(110)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3