目录
2.Object.defineProperty在Vue2双向绑定的核心原理
3.Object.defineProperty在vue2中的应用
(1)Object.defineProperty进行数据劫持的缺点
本文主要讲解了Object.defineProperty方法的功能及在Vue中实现双向绑定的核心原理。强调了Object.defineProperty在Vue框架中用于数据劫持、属性定义和修改的重要性,以及如何通过这种方式实现数据与视图的自动同步更新。
1.Object.defineProperty方法
(1)介绍
Object.defineProperty()
方法是 JavaScript 中的一个非常重要的方法,它允许你精确地添加或修改对象的属性。与简单地使用赋值操作(如 obj.prop = value
)不同,Object.defineProperty()
允许你设置属性的多种特性,如是否可枚举(enumerable)、是否可配置(configurable)、是否可写(writable),以及为属性指定一个 getter 或 setter 函数。
(2)语法
Object.defineProperty(obj, prop, descriptor)
obj
:定义属性的对象。prop
:定义或修改的属性的名称。descriptor
:通常设置一个对象,去定义或修改的属性描述符。
(3)descriptor属性描述符
属性描述符对象具有以下属性:
- value:属性默认值。
- writable:设置属性是否能改修改(true|false)。
- enumerable:是否可以枚举,即是否允许遍历(true|false)。
- configurable:是否可以删除(true|false)。
- get:作为该属性的获取getter 函数,如果没有 getter 则为
undefined
。当访问该属性时,会调用此函数,执行时不传入任何参数,并返回该属性的值。 - set:作为该属性的设置setter 函数,如果没有 setter 则为
undefined
。当属性值被修改时,会调用此函数,该函数接受一个参数(被赋予的新值),并不返回任何值,使用return
语句是无效的。
示例 1:简单使用
javascript代码
// 定义一个空对象
let obj = {};
// 定义一个属性并使用Object.defineProperty方法定义其特性
Object.defineProperty(obj, 'name', {
value: 'John', // 属性的值
writable: false, // 该属性的值是否可以被修改
enumerable: true, // 该属性是否可以被枚举
configurable: false // 该属性是否可以被删除或修改特性
});
// 尝试修改属性值
obj.name = 'Jane'; //设置无效
// 枚举属性
for (let key in obj) {
console.log(key); // name
}
// 获取属性描述符
console.log(Object.getOwnPropertyDescriptor(obj, 'name')); // { value: 'John', writable: false, enumerable: true, configurable: false }
// 删除属性
delete obj.name; //删除无效
console.log(obj.name); // John
const obj1 = {};
Object.defineProperty(obj1, 'sex', {
get:function() {
console.log("正在获取属性");
},
set:function(value) {
console.log("正在设置属性");
}
});
示例 2:使用get和set
const myObj = {
__prop:'initial value'
};
Object.defineProperty(myObj,'prop',{
get:function(){
return this.__prop;
},
set:function(newValue){
this.__prop = newValue;
},
enumerable: true,
configurable: true,
})
console.log(myObj.prop); //initial value
myObj.prop = "new value";
console.log(myObj.prop); //new value
示例3:JS实现双向数据绑定原理
<body>
<div id="demo"></div>
<label for="inp">请输入文本:</label>
<input type="text" id="inp">
<!-- Object.defineProperty是JavaScript 中用于定义或修改对象的属性的方法,可以控制属性的特性(如可枚举性、可配置性、可写性等)。 -->
<!-- 语法: Object.defineProperty(obj,prop,descriptor)-->
<script>
// 实现双向数据绑定原理
let obj2 = {};
let demo = document.getElementById('demo');
let inp = document.getElementById('inp');
Object.defineProperty(obj2,"name",{
get:function(){
},
set:function(newVal){
console.log(newVal);
demo.innerHTML = newVal;
}
})
inp.addEventListener('input',function(e){
obj2.name = e.target.value;
})
</script>
</body>
注意:默认情况下,使用 Object.defineProperty()
添加的属性是不可枚举的,即不会出现在 for...in
循环和 Object.keys()
方法中,除非明确将 enumerable
设置为 true
。
2.Object.defineProperty在Vue2双向绑定的核心原理
在Vue的双向绑定中,Object.defineProperty
方法是核心。
Vue.js的Vue 2.x版本通过Object.defineProperty
方法实现了数据的双向绑定。这一方法允许开发者直接在一个对象上定义新属性,或者修改一个对象的现有属性,并返回这个对象。具体到Vue的双向绑定中,Object.defineProperty
被用来劫持或监听对象属性的getter和setter方法。
数据劫持:当Vue实例初始化时,它会对data
选项中的每个属性使用Object.defineProperty
方法进行数据劫持。当数据发生变化时,就会触发setter函数,通知依赖该属性的视图进行更新。
依赖收集:Vue内部维护了一个依赖收集系统,通常是通过Watcher对象实现的。当组件渲染时,会触发getter方法,Vue会将当前Watcher对象添加到该属性的依赖列表中。
更新视图:当数据变化时,setter方法被触发,Vue会遍历该属性的依赖列表,通知所有依赖的Watcher对象进行更新。Watcher对象随后会触发对应的视图更新。
3.Object.defineProperty在vue2中的应用
在Vue的双向绑定中,Object.defineProperty
的应用主要体现在以下几个方面:
(1)v-model指令
v-model
是Vue中实现双向绑定的主要指令。当在表单元素上使用v-model
时,Vue会自动为该元素创建一个数据绑定,并监听其input事件来更新数据。这背后就是Object.defineProperty
在起作用,它确保了数据模型(Model)和视图(View)之间的同步,非常方便。
注:CDN引入的vue2
示例:
<body>
<div id="app">
<p>{{name}}</p>
<input type="text" v-model="name" placeholder="请输入名字">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
// v-model实现双向数据绑定
new Vue({
el: '#app',
data: {
name: '哈哈'
}
})
</script>
</body>
(2)计算属性(Computed Properties)
计算属性是基于它们的依赖进行缓存的响应式属性。Vue在内部也是通过Object.defineProperty
来定义这些计算属性的getter和setter。尽管setter在大多数情况下是不必要的,因为计算属性通常是只读的。
示例:
<body>
<div id="app">
<p>原始字符串: "{{ message }}"</p>
<p>处理后的: "{{ reversedMessage }}"</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
message: '123456'
},
computed: {
reversedMessage: function () {
return this.message.split('').reverse();
}
}
})
</script>
</body>
(3)侦听器(Watchers)
Vue允许开发者使用watch
选项来观察和响应Vue实例上数据的变动。这同样依赖于Object.defineProperty
来实现对数据的监听和响应。
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>问题: {{ question }}</p>
<input v-model="answer" placeholder="输入答案">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
question: '1 + 1 等于多少?',
answer: ''
},
watch: {
// 当answer发生变化时,这个匿名函数就会被调用
answer: function (newVal, oldVal) {
console.log(`新答案: ${newVal}, 旧答案: ${oldVal}`);
// 可以添加更复杂的逻辑,比如异步请求等
}
}
})
</script>
</body>
</html>
4.Vue 3.x中的变化
(1)Object.defineProperty进行数据劫持的缺点
Object.defineProperty
主要是用来定义对象的属性,它不能拦截到数组的方法调用(如 push
, pop
, shift
, unshift
, splice
, sort
, reverse
等),这些方法会改变数组的内容但不会触发 Object.defineProperty
设置的 getter/setter。Vue.js 通过覆盖这些数组方法来解决这个问题,
(2)Vue3的Proxy
在Vue 3.x中,双向绑定的实现方式有所变化。Vue 3.x引入了Proxy对象来替代Object.defineProperty
进行响应式系统的实现。Proxy提供了一种更强大的方式来拦截和定义对象上的基本操作(如属性查找、赋值、枚举、函数调用等),可以完美监听到任何方式的数据改变。
总结:
Object.defineProperty
在Vue 2.x的双向绑定中起核心作用,它通过数据劫持和依赖收集/派发更新的机制实现了数据模型与视图之间的自动同步。而在Vue 3.x中,采用了不同的实现方式(Proxy),但双向绑定的核心原理仍然相同。
如果对你有帮助,给个赞行嘛~~~