ES6中对象的新增方法(二)

Object.getOwnPropertyDescriptors()

ES5中Object.getOwnPropertyDescriptor 返回对象中某个属性的详细描述对象,ES6引入Object.getOwnPropertyDescriptors 返回对象中所有属性(非继承)的详细描述对象

	let obj = {
		foo : '123',
		get bar () {
			return 'abc'
		}
	}

	Object.getOwnPropertyDescriptors(obj)
	// { foo:
	//    { value: 123,
	//      writable: true,
	//      enumerable: true,
	//      configurable: true },
	//   bar:
	//    { get: [Function: get bar],
	//      set: undefined,
	//      enumerable: true,
	//      configurable: true } }

上面代码返回了obj所有属性的详细描述

该方法的实现也是很简单

	function getOwnPropertyDescriptors (obj) {
		// 放置对象属性的描述对象的容器
		const result = {}
		for (let key of Reflect.ownKeys(obj)) {
			// key 代表每一次循环时调用完拿到的对象键值
			// Reflect.ownKeys 除了继承属性纤细描述都会返回
			// 拿出每个属性的详细描述,放到之前准备好的容器中
			result[key] = Object.getOwnPropertyDescriptor(obj, key)
		}
		// 把这个对象全部的描述抛出
		return result
	}

该方法的目的,主要用于解决Object.assign 无法正确拷贝set 和 get方法 ,因为 assign 总是拷贝值, 而不会管对象内容里是函数

	let source = {
		set foo (value) {
			console.log(value)
		}	
	}
	let target = {}
	Object.assign(target, source);

	Object.getOwnPropertyDescriptor(target, 'foo')
	// { value: undefined,
	//   writable: true,
	//   enumerable: true,
	//   configurable: true }

上面的foo 属性描述对象中value之所以是undefined,是因为 Object.assign() 总是返回值,而不会考虑对象中是函数

这时,使用Object.defineProperties 和 Object.getOwnPropertyDescriptors 就能达到理想结果

	let source = {
		set foo (value) {
			console.log(value)
		}
	}

	let target = {}
	// 重新使用Object.getOwnPropertyDescriptors 定义属性描述
	Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
	// getOwnPropertyDescriptors定义的描述对象中 有着set get详细描述
	Object.getOwnPropertyDescriptor(target, 'foo')

	// { get: undefined,
	//   set: [Function: set foo],
	//   enumerable: true,
	//   configurable: true }

上面代码中,两个对象合并的逻辑可以写成一个函数

	let source = (target, origin) => {
		Object.defineProperties(
			target,
			Object.getOwnPropertyDescriptors(origin)
		)
	}

Object.getOwnPropertyDescriptors 方法的另一个用处就是配合 Object.create 方法, 将对象克隆到另一个对象,这属于浅拷贝

	let clone = 
	// 创建一个对象,拿到obj的原型,再拿到obj的属性详细描述对象
	Object.create(Object.getPrototypeOf(obj), 
	// 然后返回这个对象,但这是一个浅拷贝
	Object.getOwnPropertyDescriptors(obj))

另外,Object.getOwnPropertyDescriptors 可以实现继承

以前的写法

	let obj = {
		__proto__ : obj1,
		foo : 123
	}

ES6 规定__proto__只有浏览器要部署,其他环境不用部署。如果去除__proto__,上面代码就要改成下面这样。

	let obj = Object.create(obj1);
	obj.foo = 123;

	// 或
	let obj = Object.assign(
		Object.create(obj1),
		{
			foo : 123
		}
	)

有了 Object. getOwnPropertyDescriptors 就可以这样写

	let obj = Object.create(
		obj1,
		Object.getOwnPropertyDescriptors({
			foo : 123
		})
	)
	

__proto__属性,Object.setPrototypeOf(), Object.getPrototypeOf()

__proto__属性
用来读取当前对象的原型对象

	// ES5
	let obj = {
		method () {
			//...
		}
	}
	// 设置原型对象指向
	obj.__proto__ = newObj

	// ES6
	// 创建原型对象
	let obj = Object.create(newObj);
	obj.method = function () {}

ES6规定,严格意义上没有必要使用__proto__ ,因为它是一个内部属性,并且不是一个对外的API。

只有浏览器必须部署这个属性,其他环境不需要。
所以读取操作,使用getPrototypeOf, setPrototypeOf
创建使用 Object.create

如果一个对象本身部署了__proto__ ,该属性指向的就是原型对象

	Object.getPrototypeOf({__proto__: null})
	// null

Object.setPrototypeOf()

Object.setPrototypeOf() 与 proto 作用一样,都可以用来设置原型对象,它是ES6推荐的

	// 格式
	Object.setPrototypeOf(object, prototype)

	// 写法
	let o = Object.setPrototypeOf({}, null)

模拟源码

	function setPrototypeOf (obj, proto) {
		obj.__proto__ = proto;
		return obj
	}

写一个例子

	let object = {
		name : 'wei'
	}
	let proto = {}
	Object.setPrototypeOf(object, proto)
	proto.sex = 'male';
	proto.car = 'BMW';

	object.name // 'wei'
	object.sex  // 'male'
	object.car  // 'BMW'

上面的object对象可以访问到proto里的属性,因为proto是祖先

如果第一个参数不是对象,会转为对象,但是返回的还是第一个参数的值,这么做毫无意义,了解就好

	Object.setPrototypeOf(1, {}) === 1 // true
	Object.setPrototypeOf(false, {}) === false // true
	Object.setPrototypeOf('foo', {}) === 'foo' // true

由于undefined和null 无法转为对象,所以第一个参数是undefined或者null 就会报错。

	Object.setPrototypeOf(undefined, proto)
	// error
	Object.setPrototypeOf(null, proto)
	// error

Object.getPrototypeOf()
该方法与Object.setPrototypeOf 方法配套,用于读取原型对象

	Object.getPrototypeOf(object)

例子

	function Person () {}
	let person = new Person()

	Object.getPrototypeOf(person) === Person.prototype 
	// true

	// 修改原型指向
	Object.setPrototypeOf(person, Object.prototype)
	Object.getPrototypeOf(person) === Person.prototype
	// false
	Object.getPrototypeOf(person) === Object.prototype
	// true
	

如果参数不是对象,会把自动转为对象,转不了的就报错(undefined, null)

	Object.getPrototypeOf(1);
	// Number  {[[PrimitiveValue]]: 0}
	Object.getPrototypeOf(false);
	// Boolean {[[PrimitiveValue]]: false}
	Object.getPrototypeOf('str');
	// String  {length: 0, [[PrimitiveValue]]: ""}

	Object.getPrototypeOf(1) === Number.prototype
	// true
	Object.getPrototypeOf('STR') == String.prototype 
	// true
	Object.getPrototypeOf(false) === Boolean.prototype
	// true
	
	Object.getPrototypeOf(undefined) 
	// error
	Object.getPrototypeOf(null)
	// error

上面代码都会返回自己对象的类型原型对象,只有null和undefined会报错, 因为它们压根就没原型,且转不了对象。

	null.prototype 
	// TypeError: Cannot read property 'prototype' of null at
	undefined.prototype
	// TypeError: Cannot read property 'prototype' of undefined at
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值