可枚举属性、可迭代对象、迭代器(iterator)、for-in、for-of

可枚举属性

可枚举对象的一个定义特征是,当我们通过赋值运算符将属性赋值给对象时,我们将内部可枚举标志(enumerable)设置为 true。这是默认值。

但是,我们可以通过将其设置为 false 来更改此行为。

经验法则是,可枚举属性总是出现在 for...in 循环中。

可枚举属性和不可枚举属性是什么

所谓的可枚举就是可遍历的意思,也就是说对象的属性是否能够通过遍历得到。即通过for...in循环遍历到。

怎么判断属性是否可枚举

对象的属性是否具有可枚举属性是由enumerable值决定;
可以通过obj.propertyIsEnumerable(prop);来判断obj对象的prop属性是否能够枚举,该方法返回的是一个布尔值

哪些对象的属性是不可枚举的

js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number

属性是否可枚举有什么用

引入可枚举性这个概念的最初目的是为了让某些属性可以规避掉for...in操作,不然内部属性和方法都会遍历到

那些方法可遍历到可枚举属性

  • for...in;遍历自身和继承的可枚举属性;(for i in obj),console.log(i)//返回数组组成的键名
  • Object.keys(obj);返回一个包括对象自身可枚举属性的健名的数组

Object.keys()   (ES6对象的拓展)

用于获取对象自身所有的可枚举的属性值,但不包括原型中的属性,然后返回一个由属性名组成的数组。注意它同for..in一样不能保证属性按对象原来的顺序输出。

// 遍历数组
var colors = ['red', 'green', 'blue'];
colors.length = 10;
colors.push('yellow');
Array.prototype.demo = function () {};

Object.keys(colors); // ["0", "1", "2", "10"]

// 遍历对象
function Person(name, age) {
this.name = name;
this.age = age;
}

Person.prototype.demo = function() {};

var jenemy = new Person('jenemy', 25);

Object.keys(jenemy); // ["name", "age"]

可迭代对象

如果一个对象定义了它的迭代行为,那么它是可迭代的。在本例中,将在 for...of 构造中循环的值将定义其迭代行为。可迭代的内置类型包括 Array、String、Set 和 Map、特殊类数组对象(arguments、dom节点等), 对象不可迭代,因为它没有指定 iterator 方法。可以为其对象添加迭代方法,对象才可迭代。有迭代行为才可使用for...of

可迭代对象的含义:

  • 可迭代(Iterable) 对象是数组的泛化,几乎所有对象可以作为在for…of 循环中的对象。
  • 可迭代对象必须有迭代器 iterator
  • 迭代器中必须有next()方法
// 获取迭代对象
let arr=[1,2];
let i=arr.keys()  //因为keys()返回的是数组,所以获取迭代器对象; 
//由于set集合没有key,所以与values⽅法返回结果⼀致,set的keys与values键值一样
console.log(i)//Object [Array Iterator] {}  返回迭代器对象
// console.log(i.next())//{ value: 0, done: false }
// console.log(i.next())//{ value: 1, done: false }
// console.log(i.next())//{ value: undefined, done: true }
let item;
// 对迭代器 键  值的遍历,与使用for-in结果一样
while(!(item=i.next()).done){
  // done为true时不执行
  // console.log(item.value);//0 1 
  var key=item.value;
  console.log(key,arr[key])//0 1  1 2
}

// Object.keys(obj);返回一个包括对象自身可枚举属性的健名的数组
let w=Object.keys(arr) //keys获取键
console.log(w)//[ '0', '1']
let obt={name:'we',age:13}
let w2=Object.keys(obt)
console.log(w2)//[ 'name', 'age' ]
let obj={name:'ww'}
let obj2={age:14}
// console.log(...obj)  //报错,obj不是迭代对象
//正确写法 
console.log({...obj})//{ name: 'ww' }   ...扩展运算符
console.log({...obj,...obj2})//{ name: 'ww', age: 14 }
let arr=[1,2,4]
let arr2=[3,4,5]
// 合并,...与concat区别
console.log(...arr,...arr2);//1 2 4 3 4 5
console.log(...arr)//1 2 4
console.log(arr.concat(arr2))//[ 1, 2, 4, 3, 4, 5 ]
console.log(arr)//[1 2 4]

基本上,在 JavaScript 中,所有可迭代对象都是可枚举对象,但并非所有可枚举对象都是可迭代对象。

Array.from() 我们可以对可迭代对象和类数组对象进行数组化,进行数组化后就可以使用原生数组的方法进行操作。

类数组对象和可迭代对象的相似点:都可以进行迭代操作。如字符串就是类数组对象,当然数组也可以进行迭代操作(可以用for...of进行迭代)。

类数组对象定义:只包含使用从零开始,且自然递增的整数做键名,并且定义了length表示元素个数的对象,我们就认为他是类数组对象!


判断是否拥有可迭代能力

  • 当一个数据具备Symbol.iterator属性的时候,才可以用for...of进行迭代。
// hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性
console.log(Array.prototype.hasOwnProperty(Symbol.iterator));//true
console.log(Set.prototype.hasOwnProperty(Symbol.iterator));//true
  • Symbol.iterator

可迭代对象具有Symbol.iterator属性,即具有Symbol.iterator属性的对象都有默认迭代器

 为什么数据是可迭代对象,却不能使用next()

 可迭代对象不是迭代器,迭代器才有next()方法。  


迭代器 (Iterator)

JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了MapSet

定义:遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。

Iterator 的作用有三个

一是为各种数据结构,提供一个统一的、简便的访问接口;

二是使得数据结构的成员能够按某种次序排列;

三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

Iterator 的遍历过程是这样的

(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

有迭代属性的基础用法:

  • (字符串,数组,set,map、Array,大多数类数组对象(DOM ,节点对象(NodeList)arguments)等有迭代属性。
  • 类数组对象、普通对象并没有迭代属性。
  • 可以让有迭代的元素赋值使类数组对象拥有迭代属性(对象不能赋值拥有)。对象需要自定义添加构造迭代方法才拥有迭代属性,或者使用generator生成器函数生成迭代对象。
let arr=[1,2,3] 
console.log(arr[Symbol.iterator])//获取迭代器方法  [Function: values]
console.log(arr[Symbol.iterator]())//获取迭代器对象  Object [Array Iterator] {}
// console.log(arr[Symbol.iterator]().next())//迭代器对象  { value: 1, done: false }
// console.log(arr[Symbol.iterator]().next())//迭代器对象 { value: 1, done: false }
let i=arr[Symbol.iterator]()
console.log(i.next())// {value:1,done:false}
console.log(i.next())// {value:2,done:false}
console.log(i.next())// {value:3,done:false}
console.log(i.next())// { value: undefined, done: true }
​
let str='he';
// for of 用于可迭代元素     字符串,数组,set,map、Array、大多数类数组对象(DOM获取到的类数组对象 ,节点对象(NodeList),arguments)等都可用,有迭代对象
for (let item of str){
  console.log(item)
}
//设置内置symbol  Symbol.iterator
let r=str[Symbol.iterator]//获取迭代器方法
console.log(r)//[Function: [Symbol.iterator]]
let r2=str[Symbol.iterator]()//获取迭代对象
console.log(r2,r2.next())//Object [String Iterator] {}    { value: 'h', done: false }

​

将一个类数组对象转化为可迭代对象: 

// 将一个类数组对象转化为可迭代对象  类数组对象有内置的arguments有迭代属性,本身并没有
let typeObj={
  "0":"tom",
  "1":"terry",
  length:2,
}
console.log(typeObj[Symbol.iterator])//undefined,没有迭代属性
typeObj[Symbol.iterator]=[][Symbol.iterator] //获取迭代属性
let tt=new Set(typeObj)//有迭代属性才可以用set获取属性值
console.log(tt)//Set(2) { 'tom', 'terry' }
// 或者用for of获取属性值
for(let i of typeObj){
  console.log(i);//tom  terry
}

 将一个对象转化为可迭代对象: 

let typeObj2={
  "0":'tom',
  "1":'terry',
  "2":'lerry',
}//对象  非迭代器对象
// 使用generator函数方式添加迭代器  让一个对象变为可迭代对象
typeObj2[Symbol.iterator]=function * gen(){
  // yield 'terry'
  // yield 'lerry'
  // yield 'tom'
  console.log(this)
  // 遍历
  for( let key in this){
    let v=this[key];
    yield v
  }
}
// console.log(typeObj[Symbol.iterator]);//[GeneratorFunction: gen]
// let r=typeObj[Symbol.iterator]();//迭代器对象
// console.log(r.next())//{ value: 'tom', done: false }

for(let i of typeObj2){
  console.log(i)//tom  terry lerry
}

构造迭代器的实例:

let range ={
	from:0;
	to:5;
}
// 运行for...of时吗,首先执行的就是Symbol.iterator
range[Symbol.iterator] = function() {
	return {
	// 返回当前元素,和目标元素
		current:this.from,
		last:this.to, // 当last = infinity 时,迭代器将永远执行下去,我们可以使用break跳出循环
	// 必须有next方法,迭代器才能继续下去
		next(){
		// done 为true 时迭代结束
			if (this.current <= this.last){
				return {done:flase,value:this.current++};
			else return {done:true};
			}
		}
	}
}

for-in

for-in循环用来遍历数据-------例如数组中的键名。

  • 1.一般用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。
  • 2.不建议使用 for in 遍历数组,因为输出的顺序是不固定的。
  • 3.如果迭代的对象的变量值是 null 或者 undefined, for in 不执行循环体,建议在使用 for in 循环之前,先检查该对象的值是不是 null 或者 undefined

for-of

for-of循环用来遍历数据-------例如数组中的元素值。

一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator (迭代器)接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。

for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。

let str=' hello world ';
// for of => 对字符串的遍历操作
for(let s of str){
  console.log(s)
}

let obj={
  name:'ww',
  age:13
}
// 对象的遍历
for(let s in obj){
  console.log(s,obj[s]);//name ww,age 13
}
// JavaScript 原有的for...in循环,只能获得对象的键名,不能直接获取键值。
// ES6 提供for...of循环,允许遍历获得键值。但for...of不能访问对象,需要和迭代器配用

// for(let s2 of obj){
//   console.log(s2) //报错
// }

var arr = ['a', 'b', 'c', 'd'];
// 键名
for (let a in arr) {
  console.log(a); // 0 1 2 3  
}
// 键值
for (let a of arr) {
  console.log(a); // a b c d
}

for-of循环不仅支持数组,还支持大多数类数组对象,例如DOM ,节点对象(NodeList)arguments。(因为这种类数组对象拥有迭代属性

for-of循环也支持字符串遍历,它将字符串视为一系列的Unicode字符来进行遍历。

for-of循环同样支持Map和Set对象遍历。

for-of循环不支持普通对象,但如果你想迭代一个对象的属性,你可以用for-in循环(这也是它的本职工作)或内建的Object.keys()方法, 或设置对象拥有Symbol内置属性 symbol.iterator(迭代器)

// for in  与for of对对象的操作
var obj={
  name:'ewew',
  age:14,
}
console.log(obj.hasOwnProperty(Symbol.iterator))//false
// for (var key of obj) {
//   console.log(key );//报错,对象中没有Symbol.iterator,没有迭代能力,不能直接遍历对象
// }

// 对对象的正确用法
for (var key of Object.keys(obj)) {
  console.log(key + ": " + obj[key]);//name: ewew,age: 14
}
// for in
for(var key in obj){
  console.log(key+":"+obj[key]);//name: ewew,age: 14
}

 Object.keys(obj)方法返回一个由给定对象的自身可枚举属性组成的属性名的数组。与for...in遍历返回的顺序一样。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值