Skip to content

一文搞懂js对于obj的操作及遍历方法

1.JS获取obj属性值的方法大全(遍历、获取长度)

注意:对于对象而言,获取属性值 = 获取长度 = 遍历,三者是练习在一起的!

判断obj长度的方法:

要判断一个对象 obj 的长度(即包含的属性数量),可以使用 Object.keys() 方法获取对象的所有属性键,然后使用 length 属性获取键的数量。下面是一个示例:

js
const obj = {
  key1: 'value1',
  key2: 'value2',
  key3: 'value3'
};

const length = Object.keys(obj).length;
console.log(length);
// 输出: 3

在上述示例中,我们使用 Object.keys() 方法获取 obj 对象的所有属性键,并使用 length 属性获取键的数量。这样就能得到 obj 对象的长度,即包含的属性数量。

需要注意的是,Object.keys() 方法只返回对象自身可枚举的属性键,不包括继承的属性。如果你需要包含继承的属性,可以使用 for...in 循环或 Object.getOwnPropertyNames() 方法获取所有属性键(即自身的和原型链上的)。

for (let key in) Object.keys()Object.getOwnPropertyNames()Reflect.ownKeys()的区别:

1.for...in会遍历自身的属性和原型链上的所有属性,但是只包括可枚举的属性!

注意:在使用 for...in 循环遍历对象属性键时,你可以通过 hasOwnProperty() 方法来过滤掉原型链上的属性键,只获取对象自身的属性键。

js
const obj = { a: 1, b: 2, c: 3 };

for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key);
  }
}

2.Object.keys() 只返回对象自身属性,只包括可枚举的属性!

3.Object.getOwnPropertyNames() 只返回对象自身属性,但是包括所有可枚举和不可枚举的属性键!

——> keys()和getOwnPropertyNames()仅仅是是否返回可枚举属性的区别!

4.使用Reflect.ownKeys方法可以获取对象的所有属性,包括可枚举和不可枚举的属性,包括原型链上继承的属性!——> 获取属性最全面的方法!

获取对象属性的方法和其性态的总结:

所有可以获取对象属性集的方法是否包括原型链上的属性是否包括不可枚举属性范围性(1为最小)备注
for...in3因为会遍历原型链,所以这是一种不推荐的遍历方法
Object.keys()1
Object.getOwnPropertyNames()2
Reflect.ownKeys()4

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

可枚举属性和不可枚举属性的区别在于它们是否会出现在对象的属性枚举中,例如在 for...in 循环或 Object.keys() 方法中。

下面是可枚举属性和不可枚举属性之间的区别:

  1. 可枚举属性:
    • 可枚举属性是那些可以通过 for...in 循环枚举到的属性。
    • 可枚举属性会出现在对象的属性枚举中。
    • 当使用 Object.keys() 方法获取对象的属性键时,只会返回可枚举属性的键。
  2. 不可枚举属性:
    • 不可枚举属性是那些无法通过 for...in 循环枚举到的属性。
    • 不可枚举属性不会出现在对象的属性枚举中。
    • 当使用 Object.keys() 方法获取对象的属性键时,不会返回不可枚举属性的键。

在 JavaScript 中,默认情况下,大多数自定义属性是可枚举的。但是,某些内置属性和方法通常是不可枚举的。你可以使用 Object.defineProperty()Object.defineProperties() 方法显式地定义属性的可枚举性。

下面是一个示例,展示了Object.defineProperty() 或 Object.defineProperties()的区别:

js
//使用 Object.defineProperty() 方法定义或修改单个属性:
const obj = {};

Object.defineProperty(obj, 'name', {
  value: 'John',
  writable: true,
  enumerable: false, //不可枚举
  configurable: true
});

console.log(obj.name); // 输出:'John'
const obj = {};

//使用 Object.defineProperties() 方法定义或修改多个属性:
Object.defineProperties(obj, {
  name: {
    value: 'John',
    writable: true,
    enumerable: false, //不可枚举
    configurable: true
  },
  age: {
    value: 30,
    writable: false,
    enumerable: true, //可枚举
    configurable: true
  }
});

console.log(obj.name); // 输出:'John'
console.log(obj.age); // 输出:30

总结起来,可枚举属性可以通过枚举方法和操作获取,而不可枚举属性在枚举方法和操作中被忽略。默认情况下,大多数自定义属性是可枚举的,而一些内置属性和方法通常是不可枚举的。

对于对象继承的属性的理解:(以及对象继承对象的方法)

继承的属性:继承是指一个对象通过原型链从其他对象或构造函数继承属性和方法。当**一个对象继承另一个对象或构造函数时,它会获得父对象或构造函数的属性和方法。这些被继承的属性和方法可以通过原型链访问。**继承的属性包括从原型对象继承的属性,以及可能来自其他原型链上的属性。

使用Reflect.ownKeys方法获取对象的所有属性,包括可枚举和不可枚举的属性,包括原型链上继承的属性!——>获取属性最全面的方法

js
function getAllPropertyKeys(obj) {
  const keys = Reflect.ownKeys(obj);
  return keys;
}

const obj = { a: 1, b: 2 };
const inheritedObj = Object.create(obj);
inheritedObj.c = 3;

const allKeys = getAllPropertyKeys(inheritedObj);
console.log(allKeys); // 输出:["c", "a", "b"]

如果属性在原型链上某个对象上找到,那么该属性就被继承到了当前对象。

以下是一个示例,展示了继承的属性:

js
const parent = { a: 1 };
const child = Object.create(parent); //Object.create() 方法以 parent 对象为原型创建了一个新对象 child。(如果是构造函数,那么就直接 new 就可以了)

console.log(child.a); // 输出:1,child 继承了 parent 的属性 "a"

在上述示例中,我们创建了一个 parent 对象,它包含属性 "a"。然后,我们使用 Object.create() 方法以 parent 对象为原型创建了一个新对象 child。由于 child 对象通过原型链继承了 parent 对象,因此它可以访问并继承 parent 对象的属性。

对象继承(原型继承)和类继承的区别?

Object.create(obj) 和类的继承之间有一些区别。

  1. 原型继承:Object.create(obj) 使用原型继承,它创建一个新对象,并将 obj 对象设置为新对象的原型。这意味着新对象可以访问 obj 对象的属性和方法。这种继承方式基于原型链,使得对象之间可以共享属性和方法。
  2. 类的继承:类的继承是基于类与实例之间的关系。在类的继承中,使用关键字 extends 可以创建一个新的类,并继承自另一个类。子类继承了父类的属性和方法,并可以添加自己的属性和方法。类继承通过类的构造函数、super 关键字和原型链来实现。

总结起来,Object.create(obj) 使用原型继承创建一个继承自 obj 对象的新对象,而类的继承是基于类与实例之间的关系,通过 extends 关键字创建一个新的类,并继承自另一个类。它们在语法、原型链、构造函数、多重继承和特性等方面有所不同。

2.for in和for of的区别和详解

for in 遍历key

for...in 是 JavaScript 中的一种循环语句,用于遍历对象的可枚举属性。它会遍历对象自身的属性以及继承自原型链的可枚举属性。for...in 循环的基本语法如下:

js
for (const key in object) {
  // 在这里对每个属性执行操作
}

其中,key 表示对象的属性名(键),object 是要遍历的对象。

for of 遍历value

for...of 是 JavaScript 中的一种循环语句,用于遍历可迭代对象的元素。它提供了一种简洁的方式来遍历数组、字符串、Set、Map、NodeList 等可迭代对象中的元素。相对于传统的 for 循环或 for...in 循环,for...of 更适合遍历值而不是键。

for...of 循环的基本语法如下:

js
for (const element of iterable) {
  // 在这里对每个元素执行操作
}

其中,element 表示迭代过程中的当前元素,iterable 是要遍历的可迭代对象。

for in 与 for of的区别

  • for...in 循环用于遍历对象的可枚举属性,包括对象自身的属性和继承的属性,但并不适用于直接遍历数组。在数组上使用 for...in 时,它会遍历数组的索引数组对象上的所有可枚举属性,并且还会遍历原型链上面的可枚举属性,这可能会导致意外的结果。——> 这也是for in不适合遍历数组的原因,重点!

    怎么理解它会遍历数组的索引数组对象上的所有可枚举属性

    因为数组也是一个对象,本质上数组只有索引,但是也可以显示地给一个数组设置属性,这个属性就会像对象的属性一样存在于数组之上,那么就会造成出现意外的索引!

  • for...of 循环用于遍历可迭代对象(如数组、字符串、Set、Map 等),它只遍历对象的可迭代元素,而不会遍历对象的属性名。因此,for...of 循环可以很方便地用于遍历数组的元素,但不适用于直接遍历普通对象。

示例:

for...in 遍历数组:

js
const arr = [1, 2, 3];
arr.foo = 'bar'; // 在数组上添加一个属性,会被当做索引遍历出来!

for (let index in arr) { //得到的是key,也就是索引
  console.log(index); // 输出 0, 1, 2, foo(会出现意外的索引)
  console.log(arr[index]); // 输出 1, 2, 3, 'bar'(需要通过key才能获取数组的值)
}

for...of 遍历数组:(注意:for of无法遍历对象!)

js
const arr = [1, 2, 3];

for (let value of arr) {
  console.log(value); // 输出 1, 2, 3
}

for...in 遍历对象:

js
const obj = {
  name: 'John',
  age: 30
};

for (let key in obj) {
  console.log(key); // 输出 name, age
  console.log(obj[key]); // 输出 John, 30
}

注意:for...in 可以用于遍历对象,而 for...of 只适用于遍历数组、字符串、Set、Map 等可迭代对象,不适用于直接遍历普通对象的属性。

注意:for...of 是用来遍历可迭代对象的(数组等),这个方法循环不会遍历原型链上的属性或方法。它只会遍历对象自身的可迭代属性。

要和 for…in 进行区别:for...in 循环会遍历对象(只要是对象都可以遍历,包括可迭代和不可迭代的)的可枚举属性,包括自身属性和继承自原型链的属性。在遍历数组时,它会遍历数组的索引(键),而不是数组的元素值。因此,在遍历数组时,可能会遍历到不期望的属性。

还有一个很重要的点:虽然for in会遍历原型链,但是只要不是在继承的类上专门添加了新的可枚举属性,也是不会意外输出结果的!

因为 Object、Array这种基类的默认属性都是不可枚举的!

例子:

js
let obj = new Object(
    {
     a: 1,
     b: 2
    }
);
for(let key in obj2){
    console.log(key) //a b,没有多余的属性了!
};
image-20230820062734768