详解js中的遍历

实例属性和原型属性

  • JavaScript中对象的属性分为两种: 数据属性接见器属性
  • 依据细致的上下文环境的差别,又能够将属性分为: 原型属性实例属性
  • 原型属性 是定义在对象的原型prototype 中的属性,
  • 实例属性 一方面来自组织的函数中,然后就是组织函数实例化后增加的新属性。

js的罗列

JavaScript中遍历一个对象的属性并不太简朴,重要有两个缘由:

  • JavaScript中的对象一般都处在某个原型链中,它会从一个或多个的上层原型上继续一些属性
  • JavaScript中的属性不光有值,它还有一些除了值之外的其他特征,个中一个影响属性遍历的特征就是Enumerable(一个属性形貌符) ,假如该值为 true ,则这个属性是可罗列的,不然反之
属性形貌符
  • 属性形貌符 重要有两种情势:数据形貌符存取形貌符
  • 运用Object.getOwnPropertyDescriptorObject.getOwnPropertyDescriptors两个要领猎取对象的属性形貌符
var obj = {
  name: '10',
  _age: 25,
  get age(){
    return this._age;
  },
  set age(age){
    if(age<1){
      throw new Error('Age must be more than 0');
    }else{
      this._age = age;
    }
  }
};

var des = Object.getOwnPropertyDescriptors(obj);
console.log(des);
/**
 * des: {
 *  name: {
 *    configurable: true,
 *    enumerable: true,
 *    value: "10",
 *    writable: true,
 *    __proto__: Object
 *  },
 *  _age: {
 *    configurable: true,
 *    enumerable: true,
 *    value: 25,
 *    writable: true,
 *    __proto__: Object
 *  },
 *  age: {
 *    configurable: true,
 *    enumerable: true,
 *    get: f age(),
 *    set: f age(age),
 *    __proto__: Object
 *  },
 *  __proto__: Object
 * }
*/
value

该属性的值(仅针对数据属性形貌符有用)

writable

writable属性设置为false时,该属性被称为“不可写”。它不能被重新分配。

get

猎取该属性的接见器函数(getter)。假如没有接见器, 该值为undefined。(仅针对包含接见器或设置器的属性形貌有用)

set

猎取该属性的设置器函数(setter)。 假如没有设置器, 该值为undefined。(仅针对包含接见器或设置器的属性形貌有用)

configurable

configurable特征示意对象的属性是不是能够被删除,以及除writable特征外的其他特征是不是能够被修正。

enumerable

enumerable定义了对象的属性是不是能够在 for...in 轮回和 Object.keys() 中被罗列。

  • name、_age具有 'configurable''enumerable''value''writable'四个属性形貌符,统称数据形貌符
  • age具有'configurable''enumerable''get''set'四个属性形貌符,统称存取形貌符
分类‘configurable’‘enumerable’‘value’‘writable’‘get’‘set’
数据形貌符yesyesyesyesnono
存取形貌符yesyesnonoyesyes

对象的属性形貌符,能够经由过程Object.definePropertyObject.defineProperties来修正(configurabletrue的条件下)

经常使用的遍历要领

for...in...遍历

  • 遍历本身及原型链上一切可罗列的属性
  • 运用 for…in 轮回遍历对象属性时返回的属性会因为各个 浏览器差别 致使对象属性遍历的递次有能够不是当初构建时的递次。

Chrome Opera 的 JavaScript 剖析引擎遵照的是新版 ECMA-262 第五版范例。因而,运用 for-in 语句遍历对象属性时遍历书序并不是属性构建递次。而 IE6 IE7 IE8 Firefox Safari 的 JavaScript 剖析引擎遵照的是较老的 ECMA-262 第三版范例,属性遍历递次由属性构建的递次决议。

for-in 语句没法保证遍历递次,应只管防止编写依靠对象属性递次的代码。假如想递次遍历一组数据,请运用数组并运用 for 语句遍历。

var Animal = function({name='none', age=3, weight=80}={}){
  this.name = name;
  this.age = age;
  this.weight = weight;
}

Animal.prototype = {
  color: 'red'
}

var dog = new Animal()

// 将weight属性设置为 不可罗列
Object.defineProperty(dog, 'weight', {
  enumerable: false
})

for(let i in dog){
  console.log(n);
}

//原型链上的color一样被遍历出来了,而且因为weight属性被设置成了enumerable:false,所以不可被遍历
//name 
//age 
//color

for...of遍历

一个数据构造只需布置了Symbol.iterator属性,就被视为具有 iterator 接口,就能够用for...of轮回遍历它的成员。也就是说,for...of轮回内部挪用的是数据构造的Symbol.iterator要领。

for...of轮回能够运用的局限包含数组、SetMap 构造、某些相似数组的对象(比方arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。

假如不太清晰iterator,请去看看阮一峰大神的这篇文章,内里关于for...of以及iterator都讲的异常细致!

实在for...offor...in都是迭代一些东西,它们之间的重要区分在于它们的迭代体式格局。

  • for...in语句以原始插进去递次迭代对象的可罗列属性。
  • for...of 语句遍历可迭代对象定义要迭代的数据。

请仔细看以下实例,明白个中的区分

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  console.log(i); //  0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); //  0, 1, 2, "foo"
  }
}

for (let i of iterable) {
  console.log(i); //  3, 5, 7
}
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {}; 

let iterable = [3, 5, 7]; 
iterable.foo = 'hello';

在这段代码内里,因为继续和原型链,对象iterable继续属性objCustomarrCustom

for (let i in iterable) {
  console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom" 
}

在这段代码内里,此轮回仅以原始插进去递次纪录iterable 对象的可罗列属性。它不纪录数组元素3, 5, 7hello,因为这些不是罗列属性。然则它纪录了数组索引以及arrCustomobjCustom(为什么纪录arrCustomobjCustom在本文for...in内里有讲过)。

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); //  0, 1, 2, "foo"
  }
}

hasOwnProperty()用来搜检找到的罗列属性是不是是对象本身的(等于不是是继续的)

for (let i of iterable) {
  console.log(i); //  3, 5, 7 
}

该轮回迭代并纪录iterable作为可迭代对象定义的迭代值,这些是数组元素 3, 5, 7,而不是任何对象的属性。

Object.keys遍历

Object.keys() 要领会返回一个由一个给定对象的本身可罗列属性构成的数组,数组中属性名的分列递次和运用 for...in 轮回遍历该对象时返回的递次一致 (二者的重要区分是 一个 for-in 轮回还会罗列其原型链上的属性)。

Object.getOwnPropertyNames()遍历

Object.getOwnPropertyNames()要领返回一个由指定对象的一切本身属性的属性名(包含不可罗列属性但不包含Symbol值作为称号的属性)构成的数组,此要领不会猎取原型链上的属性。

var Animal = function({name='', age=1, weight=70}={}){
  this.name = name;
  this.age = age;
  this.weight = weight;
}

Animal.prototype = {
  type: 'Animal'
}

var dog = new Animal()

// 将height属性设置为 不可罗列
Object.defineProperty(dog, 'weight', {
  enumerable: false
})

var keys = Object.getOwnPropertyNames(dog);
console.log(keys)
// ['name', 'age', 'weight']

结语

这篇文章愿望能让人人越发明白js中的遍历,写的不好多多包涵并指出!

    原文作者:John
    原文地址: https://segmentfault.com/a/1190000014281498
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞