JavaScript对象(Object)研究_02_Object()构造函数_静态方法_assign、create、defineProperties、defineProperty、entries

JavaScript对象(Object)研究_02_Object()构造函数_静态方法_assign、create、defineProperties、defineProperty、entries

在JavaScript中,Object构造函数是所有对象的原型,是构建对象的基础。Object不仅可以作为构造函数来创建对象实例,还提供了一系列静态方法,帮助我们操作和管理对象属性。本篇博客将详细介绍Object的几个重要静态方法,包括:assigncreatedefinePropertiesdefinePropertyentries,并配以示例代码,帮助您深入理解它们的用法和注意事项。

一、Object() 构造函数概述

1. 基础介绍

Object构造函数用于创建一个新的对象。当以构造函数的方式调用时,它可以将传入的参数转换为对象。如果没有提供参数,则创建一个空对象。

// 使用Object构造函数创建对象
const obj1 = new Object();

// 等价于对象字面量
const obj2 = {};

2.示例

获取 BigInt 和 Symbol 的封装对象
当用 new 调用BigInt()Symbol()构造函数时会抛出一个错误,以阻止创建封装对象而不是基本类型值的常见错误。为这些类型创建封装对象的唯一方法是使用它们调用 Object()

const numberObj = new Number(1);
console.log(typeof numberObj); // "object"

const bigintObj = Object(1n);
console.log(typeof bigintObj); // "object"

const symbolObj = Object(Symbol("foo"));
console.log(typeof symbolObj); // "object"

二、Object.assign()

1. 基础介绍

Object.assign()方法用于将所有可枚举的自有属性(即对象自身的属性,不包括继承的属性)从一个或多个源对象复制到目标对象。该方法返回目标对象。

2. 语法

Object.assign(target, ...sources)
  • target:目标对象。
  • sources:一个或多个源对象。

3. 示例代码

示例1:简单对象合并
const target = { a: 1 };
const source = { b: 2 };
const returnedTarget = Object.assign(target, source);

console.log(target);          // 输出: { a: 1, b: 2 }
console.log(returnedTarget);  // 输出: { a: 1, b: 2 }
示例2:合并多个源对象
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
console.log(target); // 输出: { a: 1, b: 2, c: 3 }
示例3:属性覆盖
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };

Object.assign(target, source);
console.log(target); // 输出: { a: 1, b: 3, c: 4 }

4. 拷贝访问器

Object.assign()只能拷贝源对象的属性值,对于源对象的访问器属性(getter 和 setter),会被直接复制其返回值或undefined,而不会复制访问器本身。

const source = {
  get foo() {
    return 'bar';
  }
};

const target = {};
Object.assign(target, source);

console.log(target.foo); // 输出: 'bar'

在这个例子中,target对象的foo属性是一个普通的值属性,而不是访问器属性。

解决方法

要正确复制访问器属性,可以使用Object.getOwnPropertyDescriptors()Object.defineProperties()方法。

const source = {
  get foo() {
    return 'bar';
  }
};

const target = {};
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));

console.log(Object.getOwnPropertyDescriptor(target, 'foo'));
// 输出: { get: [Function: get foo], set: undefined, enumerable: true, configurable: true }

5. 注意事项

  • 浅拷贝Object.assign()执行的是浅拷贝,对于嵌套的对象和数组,复制的是引用。

    const target = { a: { b: 1 } };
    const source = { a: { c: 2 } };
    
    Object.assign(target, source);
    console.log(target); // 输出: { a: { c: 2 } }
    
  • 处理原始类型:如果源对象是原始类型(数字、字符串、布尔值等),会被包装为对象,但由于原始类型没有可枚举的自有属性,因此不会对目标对象产生影响。

    const target = {};
    const source = 'abc';
    
    Object.assign(target, source);
    console.log(target); // 输出: {}
    

6. 扩展知识点

  • 实现对象的克隆

    const obj = { a: 1, b: { c: 2 } };
    const clone = Object.assign({}, obj);
    
    console.log(clone); // 输出: { a: 1, b: { c: 2 } }
    
  • 合并默认配置

    const defaultConfig = { host: 'localhost', port: 80 };
    const userConfig = { port: 8080 };
    
    const finalConfig = Object.assign({}, defaultConfig, userConfig);
    console.log(finalConfig); // 输出: { host: 'localhost', port: 8080 }
    

三、Object.create()

1. 基础介绍

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。这对于实现原型继承非常有用。

2. 语法

Object.create(proto, [propertiesObject])
  • proto:新创建对象的原型对象。
  • propertiesObject(可选):要添加到新对象的属性,格式与Object.defineProperties()的第二个参数相同。

3. 示例代码

示例1:创建一个以某个对象为原型的新对象
const person = {
  isHuman: false,
  printIntroduction: function() {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);
me.name = 'Alice';
me.isHuman = true;

me.printIntroduction();
// 输出: My name is Alice. Am I human? true
示例2:不带原型的对象
const obj = Object.create(null);
console.log(Object.getPrototypeOf(obj)); // 输出: null
示例3:使用 propertiesObject 参数

propertiesObject参数允许在创建对象的同时定义属性的特性。

const obj = Object.create(Object.prototype, {
  a: {
    value: 1,
    writable: true,
    enumerable: true,
    configurable: true
  },
  b: {
    value: 2,
    writable: false,
    enumerable: true,
    configurable: true
  }
});

console.log(obj.a); // 输出: 1
console.log(obj.b); // 输出: 2

obj.a = 3;
console.log(obj.a); // 输出: 3

obj.b = 4;
console.log(obj.b); // 输出: 2(无法修改,因为writable为false)

4. 注意事项

  • 属性描述符propertiesObject参数中的每个属性都需要使用属性描述符来定义,包括valuewritableenumerableconfigurable等。

  • null原型对象:创建一个没有原型的对象,可以避免原型链带来的干扰,适用于创建纯粹的字典对象。

    const dictionary = Object.create(null);
    dictionary.apple = 'A fruit';
    dictionary.car = 'A vehicle';
    
    console.log(dictionary); // 输出: { apple: 'A fruit', car: 'A vehicle' }
    

四、Object.defineProperties()

1. 基础介绍

Object.defineProperties()方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。与Object.defineProperty()不同的是,它可以同时定义或修改多个属性。

2. 语法

Object.defineProperties(obj, props)
  • obj:要在其上定义属性的对象。
  • props:包含一个或多个属性描述符的对象。

3. 属性描述符的类型

在定义属性时,属性描述符分为两种类型:

1. 数据描述符(Data Descriptor)

用于描述具有值的属性,其属性包括:

  • value:属性的值。
  • writabletrue表示属性的值可被修改,false则不可修改。
  • enumerabletrue表示属性可枚举,false则不可枚举。
  • configurabletrue表示属性的特性(除了value外)可被修改,属性可被删除;false则不可。
2. 存取描述符(Accessor Descriptor)

用于描述通过gettersetter方法访问的属性,其属性包括:

  • get:获取属性值的函数,在读取属性时调用,无参数。
  • set:设置属性值的函数,在写入属性时调用,接收单个参数。
  • enumerable:同上。
  • configurable:同上。

注意:一个属性描述符要么是数据描述符,要么是存取描述符,不能同时存在valuewritablegetset

4. 示例代码

示例1:定义数据属性
const obj = {};

Object.defineProperties(obj, {
  property1: {
    value: 42,
    writable: true,
    enumerable: true,
    configurable: true
  },
  property2: {
    value: 'Hello',
    writable: false,
    enumerable: true,
    configurable: false
  }
});

console.log(obj.property1); // 输出: 42
console.log(obj.property2); // 输出: Hello

obj.property1 = 100;
console.log(obj.property1); // 输出: 100

obj.property2 = 'World';
console.log(obj.property2); // 输出: Hello(无法修改)
示例2:定义存取属性
let internalValue = 0;

Object.defineProperties(obj, {
  property3: {
    get() {
      return internalValue;
    },
    set(value) {
      console.log(`Setting property3 to ${value}`);
      internalValue = value;
    },
    enumerable: true,
    configurable: true
  }
});

obj.property3 = 10; // 输出: Setting property3 to 10
console.log(obj.property3); // 输出: 10

5. 注意事项

  • 默认值:如果不指定writableenumerableconfigurable,它们的默认值为false
  • 互斥性:数据描述符和存取描述符不能同时使用。
  • 属性特性:通过属性描述符,可以精确控制属性的行为,非常适合在需要严格控制属性访问和修改的情况下使用。

五、Object.defineProperty()

1. 基础介绍

Object.defineProperty()方法直接在对象上定义一个新属性,或者修改对象的现有属性,并返回该对象。

2. 语法

Object.defineProperty(obj, prop, descriptor)
  • obj:要在其上定义属性的对象。
  • prop:要定义或修改的属性的名称。
  • descriptor:属性描述符,格式同上。

3. 示例代码

示例1:定义数据属性
const obj = {};

Object.defineProperty(obj, 'a', {
  value: 1,
  writable: true,
  enumerable: true,
  configurable: true
});

console.log(obj.a); // 输出: 1
示例2:定义只读属性
Object.defineProperty(obj, 'b', {
  value: 2,
  writable: false,
  enumerable: true,
  configurable: true
});

obj.b = 3;
console.log(obj.b); // 输出: 2(无法修改)
示例3:定义存取属性
let value = 0;

Object.defineProperty(obj, 'c', {
  get() {
    return value;
  },
  set(newValue) {
    console.log(`Setting value to ${newValue}`);
    value = newValue;
  },
  enumerable: true,
  configurable: true
});

obj.c = 5; // 输出: Setting value to 5
console.log(obj.c); // 输出: 5

4. 注意事项

  • 不可枚举属性:如果enumerable设置为false,属性将不会出现在for...in循环和Object.keys()中。

    Object.defineProperty(obj, 'd', {
      value: 4,
      enumerable: false
    });
    
    console.log(Object.keys(obj)); // 输出: ['a', 'b', 'c']
    
  • 不可配置属性:如果configurable设置为false,无法删除属性或更改属性描述符。

    Object.defineProperty(obj, 'e', {
      value: 5,
      configurable: false
    });
    
    delete obj.e;
    console.log(obj.e); // 输出: 5(无法删除)
    

六、Object.entries()

1. 基础介绍

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用for...in循环遍历该对象时返回的顺序一致。

2. 语法

Object.entries(obj)
  • obj:要返回其可枚举属性的对象。

3. 示例代码

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

const entries = Object.entries(obj);
console.log(entries);
// 输出: [['a', 1], ['b', 2], ['c', 3]]
示例:遍历对象的键值对
for (const [key, value] of Object.entries(obj)) {
  console.log(`${key}: ${value}`);
}
// 输出:
// a: 1
// b: 2
// c: 3

4. 注意事项

  • 顺序问题Object.entries()的返回顺序与for...in循环一致,但for...in循环也会遍历原型链上的可枚举属性,而Object.entries()只返回对象自身的可枚举属性。

  • 非对象参数:如果传入的参数不是对象,则会被强制转换为对象。

    console.log(Object.entries('hi'));
    // 输出: [['0', 'h'], ['1', 'i']]
    

5. 扩展知识点

  • 将对象转换为Map

    const obj = { a: 1, b: 2 };
    const map = new Map(Object.entries(obj));
    
    console.log(map.get('a')); // 输出: 1
    
  • 从键值对数组创建对象

    const entries = [['a', 1], ['b', 2]];
    const objFromEntries = Object.fromEntries(entries);
    
    console.log(objFromEntries); // 输出: { a: 1, b: 2 }
    

七、总结

本文详细介绍了Object构造函数的几个重要静态方法:assigncreatedefinePropertiesdefinePropertyentries。通过这些方法,我们可以更灵活地操作对象的属性,实现对象的克隆、合并、继承以及属性的精细控制。

在使用这些方法时,需要注意:

  • Object.assign()进行的是浅拷贝,无法深度复制嵌套对象,对访问器属性会将其转换为普通的值属性。
  • 使用Object.create()时,如果要添加属性,需要使用propertiesObject参数,并使用属性描述符定义属性的特性。
  • Object.defineProperty()Object.defineProperties()允许精确控制属性的特性,如可写性、可枚举性等。在定义属性时,需要了解数据描述符和存取描述符的区别。
  • Object.entries()提供了一种方便的方法遍历对象的键值对,但只包括自身的可枚举属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

It'sMyGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值