对象遍历问题及解决方案

268 阅读3分钟

对象遍历问题及解决方案

1. 检测某个成员(属性/键)是否属于这个对象?

in:检测成员是否属于这个对象「特点:不论是私有属性,还是公有的属性,只要有则检测结果就是 true」

function Fn() {
  /*
   * EC(FN)
   *   初始创建Fn找个类的一个实例对象  0x000
   *   初始THIS:this->0x000
   */
  let total = 0; //上下文的私有变量  和实例对象没有必然的联系
  this.x = 10; //this.xxx=xxx 都是给实例对象设置的私有属性和方法
  this.y = 20;
  this.say = function () {
    //0x000.say=0x100   0x001.say=0x101
    console.log("SAY");
  };
  /* 如果不设置返回值,或者返回值是一个基本类型值,默认都会把实例对象 0x000 返回;如果手动返回的是一个引用数据类型值,则以自己返回的为主; */
  // return {
  //     name: 'zhufeng'
  // };
}
let f1 = new Fn(); //->0x000

console.log("say" in f1); //->true


console.log'hasOwnProperty' in f1)//->true

hasOwnProperty 在 f1 的公有属性上

2. 检测是否属于这个对象的私有属性

hasOwnProperty:用来检测当前成员是否为对象的私有属性「特点:只有是私有属性,结果才是 ture,哪怕有这个属性,但是属于公有的属性,结果也是 false」

function Fn() {
  /*
   * EC(FN)
   *   初始创建Fn找个类的一个实例对象  0x000
   *   初始THIS:this->0x000
   */
  let total = 0; //上下文的私有变量  和实例对象没有必然的联系
  this.x = 10; //this.xxx=xxx 都是给实例对象设置的私有属性和方法
  this.y = 20;
  this.say = function () {
    //0x000.say=0x100   0x001.say=0x101
    console.log("SAY");
  };
  /* 如果不设置返回值,或者返回值是一个基本类型值,默认都会把实例对象 0x000 返回;如果手动返回的是一个引用数据类型值,则以自己返回的为主; */
  // return {
  //     name: 'zhufeng'
  // };
}
let f1 = new Fn(); //->0x000

console.log(f1.hasOwnProperty("say")); //->true

f1.hasOwnProperty('hasOwnProperty')` `//->false` 

说明‘hasOwnProperty’不是它的私有属性,也就是它的公有属性「前提基于 in 检测出来的结果是 true」

3. 编写检测一个属性是对象的共有属性

function hasPubProperty(attr, obj) {
  //方案一:
  return attr in obj && !obj.hasOwnProperty(attr);

  //方案二:共有属性实在obj所属类的原型上,我们去获得这个obj的原型即可。如果没有共有属性,则遍历到Object的原型是null
  let proto = Object.getPrototypeOf(obj);
  if (proto !== null) {
    if (proto.hasOwnProperty(attr)) {
      return true;
    }
    proto = Object.getPrototypeOf(proto);
  }
  return false;
}
let obj = {
  name: "hahha",
  age: "hahaha",
};
console.log(hasPubProperty("name", obj));
console.log(hasPubProperty("age", obj));

4. 如何遍历对象

for in

let sy = Symbol();
let obj = {
  name: "zhufeng",
  age: 12,
  3: "哈哈哈",
  0: "zhouxiaotian",
  [sy]: 100,
};
Object.prototype.AAA = 100;
for (let key in obj) {
  console.log(key);
}

for in 遍历的特点:

  1. 不能遍历 symbol 的私有属性
  2. 可以遍历原型上扩展的共有属性「内置的公共属性是不可枚举的(就是无法遍历到的)」
  3. 数字属性优先遍历,并且从小到大遍历(不会严格按照属性书写的顺序)

需求1:避免遍历公共的

for (let key in obj) {
  if (!obj.hasOwnProperty(key)) break; //已经遍历到公共的,则私有已经遍历完,结束循环
  console.log(key); //->'name'
}

需求2:只想遍历私有的,包含 Symbol 的

let keys = [
  ...Object.getOwnPropertyNames(obj),
  ...Object.getOwnPropertySymbols(obj),
];
keys.forEach((key) => {
  console.log(key, obj[key]);
});