defineProperty的基本认识

defineProperty这个方法大家多多少少都有所耳闻。vue更是让他“声名远播”,今天就来好好总结下这个vue2版本里,不可或缺的defineProperty方法。

1.定义

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

备注:应当直接在 Object 构造器对象上调用此方法,而不是在任意一个 Object 类型的实例上调用。

2.语法

Object.defineProperty(obj, prop, descriptor)

2.1 参数
  • obj
    要定义属性的对象。
  • prop
    要定义或修改的属性的名称或Symbol

在ES6中,由于 Symbol类型的特殊性,用Symbol类型的值来做对象的key与常规的定义或修改不同,而Object.defineProperty 是定义key为Symbol的属性的方法之一。

  • descriptor
    要定义或修改的属性描述符。

而最需要注意的就是这属性描述符了。对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。这也就导致一个描述符不能同时拥有 valuewritablegetset 键,否则会产生一个异常。

2.1.1 属性描述符

2.1.1.1数据描述符

Writable
能否修改属性的值,如果直接使用字面量定义对象,默认值为true
Value
该属性对应的值,默认为undefined

2.1.1.2存取描述符

Get
一个给属性提供 getter 的方法(访问对象属性时调用的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined
Set
一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined

2.1.1.3公共描述符
还有两个描述符是存取与数据描述符都共有的。

Configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
Enumerable
表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true

3. 简单使用

writable控制是否可修改

let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	writable: false
})
console.log(obj.name);  // fufu
obj.name = 'dandan'
console.log(obj.name);  // fufu
--------------------------------------------------------------------
let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	writable: true
})
console.log(obj.name);  // fufu
obj.name = 'dandan'
console.log(obj.name);  // dandan

configurable控制是否允许被删除

let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	configurable: false,
})
delete obj.name
console.log(obj); // {name: 'fufu'}
-------------------------------------------------------------------
let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	configurable: true,
})
delete obj.name
console.log(obj); // {}

enumerable控制属性可否被枚举,例如被keys或for…in…遍历。

let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	enumerable: false,
})
Object.defineProperty(obj, 'age', {
	value: 20,
	enumerable: true,
})
console.log(Object.keys(obj));  //["age"]

注意一下代码的区别:

let obj = {}
obj.name = 'fufu'
// 等价于
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	enumerable: true,
	configurable: true,
	writable: true
})
-------------------------------------------------------------
let obj = {}
Object.defineProperty(obj, 'name', {
	value: 'fufu'
})
// 等价于
Object.defineProperty(obj, 'name', {
	value: 'fufu',
	enumerable: false,
	configurable: false,
	writable: false
})

get和set可以算是最关键的描述符了,vue3.0之前的observe就是靠他实现

let obj = {name: 'fufu'}
let val = undefined
Object.defineProperty(obj, 'age', {
	get() {
		console.log('获取')
		return val
	},
	set(newValue) {
		console.log('设置')
		val = newValue + '岁'
	}
})
obj.age = 18 //设置
// 获取
console.log(obj.age);  //18岁
4.实际作用
4.1创建一个常量属性。
function notEdit(obj, attr, value) {
	return Object.defineProperty(obj, attr, {
		value,
		configurable: false,
		writable: false
	})
}
let obj = notEdit({}, 'name', 'fufu')
delete obj.name
console.log(obj); //{name: "fufu"}
obj.name = 'dandan'
console.log(obj); //{name: "fufu"}
obj.age = 20
console.log(obj); //{age: 20, name: "fufu"}
4.2禁止拓展属性

想要让对象禁止添加属性,可以使用preventExtensions()方法。

let obj = {}
Object.preventExtensions(obj)
obj.name = 'fufu'
console.log(obj)  //{}
4.3 对象封密

Object.seal()会创建一个密封的对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。该对象这个方法实际上会在一个现有对象上调用object.preventExtensions(…)并把所有现有属性标记为configurable:false。

由此可以自己封装出seal方法:

function seal(obj) {
	for(let key in obj) {
		let val = obj[key]
		Object.defineProperty(obj, key, {
			value: val,
			configurable: false,
		})
	}
	return Object.preventExtensions(obj)
}
let obj = seal({name: 'fufu', age: 20})
obj.name = 'dandan'
obj.age = '100'
obj.love = 'sing'
console.log(obj); //{name: "dandan", age: "100"}
4.4 冻结对象

Object.freeze()方法可以冻结一个对象。该对象不能添加新的属性,不能修改原有属性的值,不能进行属性删除。(只会冻结第一层,若属性为对象或数组,则冻结不了内部属性值的修改)
根据上面的方面,可以自己手写一个冻结对象方法:

function freeze(obj) {
	for(let key in obj) {
		let val = obj[key]
		Object.defineProperty(obj, key, {
			value: val,
			configurable: false,
			writable: false
		})
	}
	return Object.preventExtensions(obj)
}
let obj = freeze({name: 'fufu', height: 170, arr: [1]})
obj.name = 'dandan'
obj.age = 20
obj.arr.push(2)
delete obj.height
// 若属性值为对象或数组这种非基本数据类型,那么属性值是可以被修改的。
console.log(obj);  //{name: 'fufu', height: 170, arr: [1, 2]}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值