object.defineproperty方法解析/自己实现一个object.defineProperty/Vue3中的Proxy解析和实现

news/2024/11/14 15:33:30/
object.defineproperty

       首先说明一下 object.defineproperty不是Vue的方法,而是ES5中新增的方法。该方法可以用于定义对象属性的特性,包括可写性、可枚举、可配置性等。

该方法的代码如下:

Object.defineProperty(obj, prop, descriptor)

其中,obj表示要操作的目标对象,prop要定义或修改的属性名,descriptor是一个描述符对象,用来指定属性的特性。descriptor对象可以包含一下属性:

  • value:设置属性值,默认为undefined。
  • writable:设置属性是否可写(即是否可以被赋值),默认为false。
  • enumerable:设置属性是否可枚举(即是否可以通过for...in遍历循环得到),默认为false。
  • configurable:设置是否可配置(即是否可以使用delete属性删除或重新定义),默认为false。
  • get:定义属性的读取器函数,该函数会在读取属性值时被调用。
  • set:定义属性的设置器函数,该函数会在设置属性值时被调用。

比如如下我们创建一个对象:

const obj = {};
Object.defineProperty(obj, 'PI', {value: 3.14,writable: false,enumerable: true,configurable: false
});console.log(obj.PI); // 输出 3.14
obj.PI = 3.14159;     // 不允许修改
console.log(obj.PI); // 输出 3.14for (const key in obj) {console.log(key); // 输出 'PI'
}delete obj.PI;       // 不允许删除
console.log(obj.PI); // 输出 3.14

需要注意的是,Object.defineProperty() 方法只能定义或修改单个属性。这也就是说如果有多个的话,必然在Vue的源码中有一个循环遍历。一下为一段源码看一下即可 循环为while循环

  function initData(vm) {var data = vm.$options.data;data = vm._data = isFunction(data) ? getData(data, vm) : data || {};var keys = Object.keys(data);var props = vm.$options.props;var methods = vm.$options.methods;var i = keys.length;
//   --------------------------------------在这 在这--------------------------------while (i--) {var key = keys[i];{if (methods && hasOwn(methods, key)) {warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm);}}if (props && hasOwn(props, key)) {warn$2("The data property \"".concat(key, "\" is already declared as a prop. ") +"Use prop default value instead.", vm);}else if (!isReserved(key)) {proxy(vm, "_data", key);}}// observe datavar ob = observe(data);ob && ob.vmCount++;}// 给大家稍微解释一下这段源码内容0、 data = vm._data = isFunction(data) ? getData(data, vm) : data || {};判断传过来的是 对象还是 函数 因为我们data本身有data:{}data(){return{}}两种方法!1、isReserved(key) 用于判断当前字段是否为 _ 或者 $ 开头,以 _ 或 $ 开头的属性 不会 被 Vue 实例代理,因为它们可能和 Vue 内置的属性、API 方法冲突。可以理解为只可读不可用,是vue源码中自己使用的。2proxy(vm, "_data", key);function proxy(target, sourceKey, key) {sharedPropertyDefinition.get = function proxyGetter() {return this[sourceKey][key];};sharedPropertyDefinition.set = function proxySetter(val) {this[sourceKey][key] = val;};Object.defineProperty(target, key, sharedPropertyDefinition);}可以看出是进行了代理。简单了解一下,如果想学可以去看看。

那我们怎么按照Vue的思想自己实现一个数据劫持那?

  • 明确方向:Vue本身通过的是 new 进行了实例化。
  • 属性:含有一个内部可操作属性this._data属性。
  • 添加方法:自定义 get set 方法。
  • 遍历:循环遍历添加属性。
let vm = new Vue({data:{name:"屈小康"}
}) 
// 定义class
class Vue{
// 为什么叫 options 因为源码就是这样写的constructor(options){this._data = options.data;this.$options = options;this.initData();}initData(){let data = this._data;// 只针对于单层 data:{name:"屈小康" }Object.keys(data).forEach(item=>{Object.defineProperty(this,item,{enmuerable:true,configurable:true,get(){return data[item];},set(value){data[item] = value;    } })})}
}

那如果是 data:{name:"屈小康",person:{age:18}}怎么办? 显然我们需要递归的方法。

let vm = new Vue({data:{name:"屈小康"}
}) 
// 定义class
class Vue{
// 为什么叫 options 因为源码就是这样写的constructor(options){this._data = options.data;this.$options = options;this.initData();}initData(){let data = this._data;// 那如果是 data:{name:"屈小康",person:{age:18}}怎么办? 显然我们需要递归的方法。observe(data);}
}
// 添加 get 和 set 方法
function defineReactive(data,key,value){object(data[item]) //递归调用Object.defineProperty(data,key,{enumerable:trye,configurable:true,get(){return value },set(val){data[key] = val;  }})}
// 定义监听 class
class Observer{construct(data){this.work(data)}work(data){Object.keys(data).forEach(item=>{defineReactive(data,item,data[item]);})}
}
// 判断是否需要进行监听
function observe(data){function observe(data) {let type = Object.prototype.toString.call(data);if (type !== '[object Object]' && type !== '[object Array]') {return;}new Observer(data);}
}

http://www.ppmy.cn/news/274658.html

相关文章

platform驱动和pci驱动的区别

物理结构 platform驱动是虚拟总线,实际上硬件并不存在,可用于所有的硬件平台, pci驱动,是硬件上实际存在的(pci bus),pci bus主要用于x86规范。 设备注册 需要手动调用platform_device_regster()函数进行注册&#…

PCI设备驱动开发

PCI总线协议 PCI(外设部件互连标准)总线标准是一种将系统外部设备连接起来的总线标准,它是PC中最重要的总线。 其他总线如ISA总线、USB等总线都挂在PCI总线之上。 PCI ( Peripheral Component Interconnect) 总线是当前最流行的总线之一&am…

PCI驱动框架简单分析

一、PCI 概念介绍 PCI是CPU和外围设备通信的高速传输总线。PCI规范能够实现32位并行数据传输,工作频率为 33MHz 或 66MHz ,最大吞吐率高达266MB/s,PCI的衍生物包括 CardBus、mini-PCI、PCI-Express、cPCI等。 PCI总线体系结构是一种层次式的体系结构。在…

深入分析Linux PCI驱动框架分析(二)

说明: Kernel版本:4.14ARM64处理器使用工具:Source Insight 3.5, Visio 1. 概述 本文将分析Linux PCI子系统的框架,主要围绕Linux PCI子系统的初始化以及枚举过程分析;如果对具体的硬件缺乏了解&#xf…

Linux驱动学习--初识PCI驱动(一)

PCI是什么 PCI—Peripheral Component Interconnect,外围设备互联总线。是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总…

Linux驱动学习--PCI设备驱动

目录 一、引言 二、PCI总线介绍 三、PCI设备驱动组成 四、查看本机上的PCI设备 一、引言 PCI总线在linux中应用的十分广泛,本文就来简单介绍一下 二、PCI总线描述 1、PCI总线结构 PCI是CPU和外围设备通信的高速传输总线。普通PCI总线带宽一般为132MB/s(在3…

PCI驱动

一、PCI总线 1、PCI桥 Host/PCI桥:用于连接CPU与PCI根总线,即“北桥芯片组” PCI/ISA桥:用于连接PCI与旧的ISA总线,即“南桥芯片组” PCI-to-PCI桥:用于连接PCI主总线与次总线 2、pci_bus结构体(PCI总线结构…

pci驱动框架

PCI 总线架构主要被分成三部分: 1.PCI 设备。符合 PCI 总线标准的设备就被称为 PCI 设备,PCI 总线架构中可以包含多个 PCI 设备。图中的 Audio 、LAN 都是一个 PCI 设备。PCI 设备同时也分为主设备和目标设备两种,主设备是一次访问操作的发…