JavaScript:对象

ECMAScript 的对象是一个无序的属性的集合,对象中的属性之间没有排列顺序。

在 ECMAScript 中,对象是一种基本的数据类型,即对象就是数据类型 Object ,数据类型 Object 就是对象。

由于对象本身就是一种数据类型,所以对象可以像其它数据类型一样,随时被创建、被修改。对象具有极大的动态性,并不是面向对象编程中被严格定义的对象实体。

严格来说,ECMAScript 的对象的行为不一定合适 JavaScript 中的其它对象,比如浏览器环境中的 BOM 对象和 DOM 对象,是由宿主环境定义和提供的宿主对象。而宿主对象不受 ECMAScript 约束,所以宿主对象不一定会继承 Object 。


属性

属性是对象存储的数据,是对象的组成部分。

属性 是一个键值对。

键为属性名,值为属性值。

属性都由一个名称作为键来标识,这个名称被称作 属性名 ,属性名会映射到一个值,这个值被称作 属性值


方法

方法 是属性值为函数对象的属性。

当属性的值为函数对象时,该属性被称为方法。

示例:

  • 在对象字面量中定义方法。
    const obj = {
    	func: function() {
    		return '2035'
    	}  // 属性值为函数
    }
    console.log(obj.func())
    
    // 输出:
    // 2035
    

当属性值是一个匿名函数可以简写方法,即省略冒号操作符 . 和关键字 function 。

示例:

  • 对象字面量的方法简写。
    const obj = {
    	func() {
    		return '2049'
    	}  // 方法简写
    }
    console.log(obj.func())
    
    // 输出:
    // 2049
    

属性的类型

属性有两种类型:数据属性和访问器属性。


数据属性

数据属性有 4 个内部特性,用于描述属性的行为:

  • [[Configurable]] ,表示属性是否是可配置的,默认值为 true 。

    属性是可配置的,指的是可以对属性进行以下的行为:

    • 可以重新定义属性。
    • 可以通过关键字 delete 删除属性。
    • 可以修改属性的内部特性。
    • 可以把属性修改为访问器属性。
  • [[Enumerable]] ,表示属性是否是可枚举的,默认值为 true 。

    属性是可枚举的,指的是属性可以通过 for-in 循环返回。

  • [[Writable]] ,表示属性的值是否可以被修改,默认值为 true 。

  • [[Value]] ,表示属性的值,默认值为 undefined 。


访问器属性

访问器属性有 4 个内部特性,用于描述属性的行为:

  • [[Configurable]] ,表示属性是否是可配置的,默认值为 true 。

    属性是可配置的,指的是可以对属性进行以下的行为:

    • 可以重新定义属性。
    • 可以通过关键字 delete 删除属性。
    • 可以修改属性的内部特性。
    • 可以把属性修改为数据属性。
  • [[Enumerable]] ,表示属性是否是可枚举的,默认值为 true 。

    属性是可枚举的,指的是属性可以通过 for-in 循环返回。

  • [[Get]] ,表示属性的获取函数,默认值为 undefined 。

    获取函数 ,在读取属性的值时被调用。

    • 返回值:
      任意值,向读取操作返回的值。
  • [[Set]] ,表示属性的设置函数,默认值为 undefined 。

    设置函数 ,在写入属性的值时被调用。

    • 提供一个参数:
      newValue,任意值,写入时提供的值。

可以使用字面量语法来定义访问器属性。

在属性名前面使用关键字 get 、set ,且属性值为函数对象。

访问器属性通常用于访问其他属性,比如对象自身的数据属性。

通常在属性名的前面或后面使用下划线 _ ,表示不希望被对象外部直接访问的属性。

示例:

  • 使用字面量语法来定义访问器属性。
    const obj = {
    	_attr: '2021',
    	get accessorAttr() {
    		console.log('get accessor attribute')
    		return this._attr
    	},  // 定义属性 accessorAttr 的获取函数
    	set accessorAttr(newValue) {
    		console.log('set accessor attribute')
    		this._attr = newValue + '-set'
    	}  // 定义属性 accessorAttr 的设置函数
    }
    
    console.log('obj.accessorAttr:', obj.accessorAttr)
    obj.accessorAttr = '2035'
    console.log('obj.accessorAttr:', obj.accessorAttr)
    
    // 输出:
    // get accessor attribute
    // obj.accessorAttr: 2021
    // set accessor attribute
    // get accessor attribute
    // obj.accessorAttr: 2035-set
    

相关 API


定义属性

ECMAScript 提供一些 API 来动态定义对象的属性。

前置知识:

  • 用于描述属性的、属性的内部特性,被称为 描述符

Object.defineProperty()

方法 Object.defineProperty() :

  • 功能:
    通过设置属性的内部属性,动态地为指定的对象定义一个新属性,或重新定义一个已有的属性。

  • 接收三个参数:

    1. 对象
      需要定义属性的对象。

    2. 字符串 | 符号
      需要定义的属性的属性名。

    3. 对象
      需要定义的属性的描述符对象。

  • 返回值:
    对象,定义属性后的原对象。

属性的描述符对象:

  • 数据属性的描述符对象

    const dataDescriptor = {
    	configurable: true,
    	enumerable: true,
    	writable: true,
    	value: 'value'
    }
    
  • 访问器属性的描述符对象

    const accessorDescriptor = {
    	configurable: true,
    	enumerable: true,
    	get() {},
    	set(newValue) {}
    }
    

在使用方法 Object.defineProperty() 定义属性时,如果不设置属性的内部特性 [[Configurable]]、[[Enumerable]]、[[Writable]] ,默认将这些内部特性设置为 false 。

示例:

  • 为对象定义一个数据属性。

    const obj = {}
    Object.defineProperty(
    	obj,
    	'attr',
    	{
    		configurable: true,
    		enumerable: true,
    		writable: true,
    		value: '1948'
    	}  // 数据属性的描述符对象
    )  // 为对象定义一个数据属性
    console.log('obj.attr:', obj.attr)
    
    // 输出:
    // obj.attr: 1948
    
  • 为对象定义一个访问器属性。

    let obj = {
    	_attr: '2091'
    }
    obj = Object.defineProperty(
    	obj,
    	'attr',
    	{
    		configurable: true,
    		enumerable: true,
    		get() {
    			return this._attr
    		},
    		set(value) {
    			this._attr = value + '-set'
    		}
    	}  // 访问器属性的描述符对象
    )  // 为对象定义一个访问器属性
    console.log('obj.attr:', obj.attr)
    obj.attr = '2108'
    console.log('obj.attr:', obj.attr)
    
    // 输出:
    // obj.attr: 2091
    // obj.attr: 2108-get
    

Object.defineProperties()

方法 Object.defineProperties() :

  • 功能:
    通过设置属性的内部属性,动态地为指定的对象(重新)定义多个属性。

  • 接收两个参数:

    1. 对象
      需要定义属性的对象。

    2. 对象
      属性定义对象。

  • 返回值:
    对象,定义属性后的原对象。

属性定义对象的属性的结构:

  • 属性名:
    需要定义的属性的属性名

  • 属性值:
    需要定义的属性的描述符对象。

属性定义对象:

const attributeDefining = {
	dataAttr: {
		configurable: true,
		enumerable: true,
		writable: true,
		value: 'dataAttr'
	},
	accessorAttr: {
		configurable: true,
		enumerable: true,
		get() {},
		set(newValue) {}
	}
}

在使用方法 Object.defineProperties() 定义属性时,如果不设置属性的内部特性 [[Configurable]]、[[Enumerable]]、[[Writable]] ,默认将这些内部特性设置为 false 。

示例:

  • 为对象定义多个属性。
    let obj = {
    	_innerAttr: '2035'
    }
    Object.defineProperties(
    	obj,
    	{
    		attr_01: {
    			configurable: true,
    			enumerable: true,
    			writable: true,
    			value: '2017'
    		},  // 定义数据属性
    		attr_02: {
    			configurable: true,
    			enumerable: true,
    			writable: true,
    			value: '2021'
    		},
    		outerAttr: {
    			configurable: true,
    			enumerable: true,
    			get() {
    				return this._innerAttr
    			},
    			set(value) {
    				this._innerAttr = value + '-set'
    			}
    		},
    	}  // 属性定义对象
    )  // 定义多个属性
    
    console.log('obj.attr_01:', obj.attr_01)
    console.log('obj.attr_02:', obj.attr_02)
    console.log('obj.outerAttr:', obj.outerAttr)
    
    // 输出:
    // obj.attr_01: 2017
    // obj.attr_02: 2021
    // obj.outerAttr: 2035
    

获取属性的内部特性

ECMAScript 提供一些 API 来获取属性的内部特性。


Object.getOwnPropertyDescriptor()

方法 Object.getOwnPropertyDescriptor() :

  • 功能:
    获取指定对象的某个属性的内部特性。

  • 接收两个参数:

    1. 对象
      目标对象。

    2. 字符串 | 符号
      属性名。

  • 返回值:
    对象,属性的描述符对象。

示例:

  • 获取指定对象的某个属性的内部特性。
    const obj = {
    	attr: '1948'
    }
    const descriptor = Object.getOwnPropertyDescriptor(obj, 'attr')
    
    console.log(descriptor)
    
    // 输出:
    // {value: '1948', writable: true, enumerable: true, configurable: true}
    

Object.getOwnPropertyDescriptors()

方法 Object.getOwnPropertyDescriptors() :

  • 功能:
    获取指定对象所有属性的内部特性。

  • 接收一个参数:
    对象,目标对象。

  • 返回值:
    对象,包含目标对象所有的属性的描述符对象的对象。

示例:

  • 获取指定对象的某个属性的内部特性。
    const descriptors = {
    	attr_01: '2017',
    	_innerAttr: '2021',
    	get accessorAttr() {
    		return this._innerAttr
    	},
    	set accessorAttr(value) {
    		this._innerAttr = value
    	}
    }
    
    const obj = Object.getOwnPropertyDescriptors(descriptors)
    
    console.log(obj)
    console.log(obj.attr_01)
    console.log(obj._innerAttr)
    console.log(obj.accessorAttr)
    
    // 输出:
    // {attr_01: {…}, _innerAttr: {…}, accessorAttr: {…}}
    // {value: '2017', writable: true, enumerable: true, configurable: true}
    // {value: '2021', writable: true, enumerable: true, configurable: true}
    // {enumerable: true, configurable: true, get: ƒ, set: ƒ}
    

获取属性名

ECMAScript 提供一些 API 来获取属性的属性名。


Object.keys()

方法 Object.keys() :

  • 功能:
    获取指定对象的所有可枚举的、属性名为字符串的属性的键(属性名)。

  • 接收一个参数:
    对象,目标对象。

  • 返回值:
    数组,包含目标对象的所有可枚举的、属性名为字符串的属性的键(属性名)的字符串数组。

示例:

  • 使用方法 Object.keys() ,获取指定对象的所有可枚举的、属性名为字符串的属性的键(属性名)。
    const obj = {
    	attrEnumerable_01: '1948',
    	attrEnumerable_02: '2017'
    }
    Object.defineProperty(
    	obj,
    	'attrNotEnumerable',
    	{
    		configurable: true,
    		enumerable: false,
    		writable: true,
    		value: '2019'
    	}
    )
    
    const keys = Object.keys(obj)  // 获取指定对象的所有可枚举的、属性名为字符串的属性的键(属性名)
    
    console.log('obj.attrEnumerable_01:', obj.attrEnumerable_01)
    console.log('obj.attrEnumerable_02:', obj.attrEnumerable_02)
    console.log('obj.attrNotEnumerable:', obj.attrNotEnumerable)
    
    console.log('# --- --- ---')
    console.log('keys:', keys)
    console.log('keys[0]:', keys[0])
    console.log('keys[1]:', keys[1])
    
    // 输出:
    // obj.attrEnumerable_01: 1948
    // obj.attrEnumerable_02: 2017
    // obj.attrNotEnumerable: 2019
    // # --- --- ---
    // keys: (2) ['attrEnumerable_01', 'attrEnumerable_02']
    // keys[0]: attrEnumerable_01
    // keys[1]: attrEnumerable_02
    

Object.getOwnPropertyNames()

方法 Object.getOwnPropertyNames() :

  • 功能:
    获取指定对象的所有属性名为字符串的属性的键(属性名)。

  • 接收一个参数:
    对象,目标对象。

  • 返回值:
    数组,包含目标对象的所有属性名为字符串的属性的键(属性名)的字符串数组。

示例:

  • 使用方法 Object.getOwnPropertyNames() ,获取指定对象的所有属性名为字符串的属性的键(属性名)。
    const obj = {
    	attrEnumerable_01: '2021',
    	attrEnumerable_02: '2034'
    }
    Object.defineProperty(
    	obj,
    	'attrNotEnumerable',
    	{
    		configurable: true,
    		enumerable: false,
    		writable: true,
    		value: '2035'
    	}
    )
    
    const names = Object.getOwnPropertyNames(obj)  // 获取指定对象的所有属性名为字符串的属性的键(属性名)
    
    console.log('obj.attrEnumerable_01:', obj.attrEnumerable_01)
    console.log('obj.attrEnumerable_02:', obj.attrEnumerable_02)
    console.log('obj.attrNotEnumerable:', obj.attrNotEnumerable)
    
    console.log('# --- --- ---')
    console.log('names:', names)
    console.log('names[0]:', names[0])
    console.log('names[1]:', names[1])
    console.log('names[2]:', names[2])
    
    // 输出:
    // obj.attrEnumerable_01: 2021
    // obj.attrEnumerable_02: 2034
    // obj.attrNotEnumerable: 2035
    // # --- --- ---
    // names: (3) ['attrEnumerable_01', 'attrEnumerable_02', 'attrNotEnumerable']
    // names[0]: attrEnumerable_01
    // names[1]: attrEnumerable_02
    // names[2]: attrNotEnumerable
    

Object.getOwnPropertySymbols()

方法 Object.getOwnPropertySymbols() :

  • 功能:
    获取指定对象的所有属性名为符号的属性的键(属性名)。

  • 接收一个参数:
    对象,目标对象。

  • 返回值:
    数组,包含目标对象的所有属性名为符号的属性的键(属性名)的符号数组。

示例:

  • 使用方法 Object.getOwnPropertySymbols() ,获取指定对象的所有属性名为符号的属性的键(属性名)。
    const symbolEnumerable = Symbol('symbolEnumerable'),
    	symbolNotEnumerable = Symbol('symbolNotEnumerable'),
    	obj = {
    		attrEnumerable: '2036',
    		[symbolEnumerable]: '2045'
    	}
    	
    Object.defineProperty(
    	obj,
    	symbolNotEnumerable,
    	{
    		configurable: true,
    		enumerable: false,
    		writable: true,
    		value: '2049'
    	}
    )
    
    const symbols = Object.getOwnPropertySymbols(obj)  // 获取指定对象的所有属性名为符号的属性的键(属性名)
    
    console.log('obj.attrEnumerable:', obj.attrEnumerable)
    console.log('obj[symbolEnumerable]:', obj[symbolEnumerable])
    console.log('obj[symbolNotEnumerable]:', obj[symbolNotEnumerable])
    
    console.log('# --- --- ---')
    console.log('symbols:', symbols)
    console.log('symbols[0]:', symbols[0])
    console.log('symbols[1]:', symbols[1])
    
    // 输出:
    // obj.attrEnumerable_01: 2021
    // obj.attrEnumerable_02: 2034
    // obj.attrNotEnumerable: 2035
    // # --- --- ---
    // symbols: (2) [Symbol(symbolEnumerable), Symbol(symbolNotEnumerable)]
    // symbols[0]: Symbol(symbolEnumerable)
    // symbols[1]: Symbol(symbolNotEnumerable)
    

主要参考资料:

  • 《JavaScript 高级程序设计(第4版)》- P232(257/931)

合并对象

JavaScript 开发者发现合并两个对象很有用,即把源对象所有的属性复制到目标对象中。

合并(merge)对象有时也被称为混入(mixin)对象。

ECMAScript 提供方法 Object.assign() 来合并对象(对象间的赋值)。


Object.assign()

方法 Object.assign() :

  • 功能:
    把源对象所有的属性复制到目标对象中,执行的复制是浅复制。

  • 接收任意个数的参数:

    1. 对象
      目标对象。

    2. 更多参数:
      对象,源对象。

  • 返回值:
    对象,合并后的目标对象。

如果在方法 Object.assign() 执行期间出错,就会中止并退出方法,并抛出错误。在出错前执行的合并对象的操作不会被撤销,即不会“回滚”。

示例:

  • 合并对象。
    let targetObj = {
    	key: 'targetObj'
    }
    const sourceObj_01 = {
    	attr_01: 'sourceObj_01 attr'
    }
    const sourceObj_02 = {
    	attr_02: 'sourceObj_02 attr'
    }
    Object.assign(targetObj, sourceObj_01, sourceObj_02)  // 合并对象
    
    console.log('targetObj:', targetObj)
    
    // 输出:
    // targetObj: {key: 'targetObj', attr_01: 'sourceObj_01 attr', attr_02: 'sourceObj_02 attr'}
    

相等判定

在一些情况下使用操作符 === 进行相等判定,可能得不到“预期”的结果。

示例:

console.log('+0 === -0 :', +0 === -0)
console.log('0 === -0 :', 0 === -0)
console.log('0 === +0 :', 0 === +0)
console.log('NaN === NaN :', NaN === NaN)

// 输出:
// +0 === -0 : true
// 0 === -0 : true
// 0 === +0 : true
// NaN === NaN : false

针对这些情况,ES6 新增方法 Object.is() 来提供与操作符 === 相同的功能,即判定两个值是否相等,但在一些情况下能得到与操作符 === 不同的、“预期”的结果。

Object.is()

方法 Object.is() :

  • 功能:
    判定两个值是否相等。

  • 接收两个参数:

    1. 任意值,将要进行判定的值。
    2. 任意值,将要进行判定的值。
  • 返回值:
    布尔值,两个值是否相等的判定结果。

示例:

  • 使用方法 Object.is() 进行相等判定。
    console.log('is +0 equal to -0 ? :', Object.is(+0, -0))  // 进行相等判定
    console.log('is 0 equal to -0 ? :', Object.is(0, -0))
    console.log('is 0 equal to +0 ? :', Object.is(0, +0))
    console.log('is NaN equal to NaN ? :', Object.is(NaN, NaN))
    
    // 输出:
    // is +0 equal to -0 ? : false
    // is 0 equal to -0 ? : false
    // is 0 equal to +0 ? : true
    // is NaN equal to NaN ? : true
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值