Object.defineproperty

Object.defineproperty 的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性.。并返回此对象。

Object.defineproperty 参数

    Object.defineproperty方法需要传递3个参数

    Object.defineproperty(obj, prop, desc  )   

    参数1:obj     需要定义属性的当前对象

    参数2:prop    当前需要定义的属性名

    参数3:desc    描述符 一般是一个对象{

            value:18, // 属性值
            enumerable:true, //控制属性是否可以枚举,默认值是false
            writable:true, //控制属性是否可以被修改,默认值是false
            configurable:true //控制属性是否可以被删除,默认值是false

    }

set和get(即存取器描述:定义属性如何被存取)

get 是获取值的时候的方法,类型为 function ,获取值的时候会被调用,不设置时为 undefined

set 是设置值的时候的方法,类型为 function ,设置值的时候会被调用,undefined

get或set不是必须成对出现,任写其一就可以

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Object.defineproperty方法</title>
	</head>
	<body>
		<script type="text/javascript" >
			let number = 18
			let person = {
				name:'张三',
				sex:'男',
			}
 
			Object.defineProperty(person,'age',{
				// value:18,
				// enumerable:true, //控制属性是否可以枚举,默认值是false
				// writable:true, //控制属性是否可以被修改,默认值是false
				// configurable:true //控制属性是否可以被删除,默认值是false
 
				//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
				get(){
					console.log('有人读取age属性了')
					return number
				},
 
				//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
				set(value){
					console.log('有人修改了age属性,且值是',value)
					number = value
				}
 
			})
 
			// console.log(Object.keys(person))
 
			console.log(person)
		</script>
	</body>
</html>

在这里插入图片描述
vue2.0是如何监听双向绑定的?

function updateView() {
    console.log('视图更新');
    dom.innerHtml=data.name;//将data的name属性值渲染在dom元素中.
}
 
function defineReactive(target, key, value) {
    Object.defineProperty(target, key, {
    	get() {
        	return value
    	},
        set(newValue) {
            if (newValue !== value) {
                value = newValue
                updateView()
            }
        }
    })
}
 
function observe(target) {
    if (target === null || typeof target !== 'object') {
        return target
     }
    for(let key in target) {
        defineReactive(target, key, target[key])
    }
}
 
const data = {
    name: '张三',  
    age: 21
}
 
observer(data)
 
data.name = 'lisi'

oberve函数判断源数据是否是对象,然后遍历,将源数据、键值、属性值传入defineReactive函数中

​ defineReactive函数中通过Object.defineProperty对对象的每一项进行监听,如果修改了对象就触发了updateView函数。

Object.defineProperty如何深度监听data变化 ?

如果data是一个复杂对象,应该如何监听呢?我们将data替换成下面代码,再将children进行修改,看是否会触发updateView。

const data = {
    name: '张三',  
    age: 21,
    children: {
        name: '李四'
    }
}
 
data.children.name = 'lisi'

打开控制台可以看到,并未输出内容,因此,Object.defineProperty不能够深度监听对象。

​ 想到深度监听,我们就可以使用递归转换成监听普通对象,

​ ① 在defineReactive函数中Object.defineProperty调用之前调用oberserv函数,将传过来的属性值进行再次判断

function defineReactive(target, key, value) {
    // 深度监听
    observe(value)
    Object.defineProperty(target, key, {
        get() {
            return value
        },
        set(newValue) {
            if (newValue !== value) {
                value = newValue
                updateView()
            }
        }
    })
}

Object.defineProperty监听新增、删除属性

​ 如果我们给data新增属性或者删除属性,我们还能够监听的到吗?


data.sex = 'man'
delete data.name

加入以上代码,如果能监听的到的话,控制台会打印两次“视图更新”,但是我们看控制台并未打印任何内容

​ 因此,Object.defineProperty无法监听新增、删除属性,于是vue2.x通过Vue.set和Vue.delete来进行新增和删除属性

监听数组变化

const arrProto = Object.create(Array.property)
// 数组的方法名称
let arrFn = [
    'push',
    'pop',
    'shift',
    'unshift',
    ...
]
arrFn.forEach(method => {
	arrProto[method] = function() {
        // 视图更新
        updateView()
        Array.propery[method].call(this, ..arguments)
    }    
})

在observe函数中进行数组判断,并将源数据的原型指向arrProto

function observe(target) {
    if (target === null || typeof target !== 'object') {
        return target
     }
    if (Array.isArray(target)) }{
        target.__proto__ = arrProto
    }
    for(let key in target) {
        defineReactive(target, key, target[key])
    }
}

注: 当data中的某一项是数组时,在observe函数中遍历进入defineReactive中,然后进行深度监听,如果是数组的话,就会将此数组的原型指向为arrProto,此时当前数组调用的数组方法,就会执行updateView()和数组原型的方法。

例如,执行data.nums.push(4),

① 进入observe函数

② for…in…循环

③ 进入defineReactive

④ 深度监听,进入observe

⑤ 判断是否是数组

⑥ 将数组的原型指向arrProto

⑦ 执行updateView

⑧ 执行Array.prototype的push方法

Object.defineProperty的缺点

如果data的层级过深,就会一次性递归到底,计算量很大。
Object.defineProperty无法监听新增、删除属性。 (vue中需使用$set();方法新增双向绑定属性)
Object.defineProperty不具备监听原生数组。

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Object.defineProperty是一个用来在一个对象上定义新属性或者修改已存在属性的方法。[2]它可以通过设置属性的描述符来控制属性的行为,包括属性的可枚举性、可配置性、可写性以及属性的值等。通过使用Object.defineProperty,我们可以实现对对象属性的监听和控制,从而实现双向数据绑定。 举个简单的例子,假设我们有一个名为person的对象,其中包含name和age两个属性,我们可以通过使用Object.defineProperty来添加一个新的属性sex,并设置它的值为男。代码如下: let person = { name:"码农", age: 18 } Object.defineProperty(person,'sex',{ value:"男" }) console.log(person) 运行以上代码,我们可以在控制台中看到person对象中已经添加了一个名为sex的属性,其值为男。这就是Object.defineProperty的基本用法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue源码学习之Object.defineProperty对象属性监听](https://download.csdn.net/download/weixin_38663151/14904644)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Object.defineproperty方法(详解)](https://blog.csdn.net/weixin_57677300/article/details/126278467)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ok060

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

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

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

打赏作者

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

抵扣说明:

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

余额充值