Object.defineProperty和Proxy区别

Object.defineProperty和Proxy区别Object defineProper defineProper 方法会直接在一个对象上定义一个新属性 或者修改一个对象的现有属性 并返回此对象 IE8 不兼容 Object defineProper obj prop descriptor 参数 obj 要定义属性的对象 prop 要定义或修改的属性的名称或 Symbol descriptor 要定义或修改的属性描述符 返回值被传递给函数的对象 Object defineProper obj

Object.defineProperty

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

Object.defineProperty(obj, prop, descriptor)

Object.defineProperty(obj, 'name', { 
    // configurable: false,//默认为false // enumerable: false,//默认为false value: 'kongzhi', // writable: false,/默认为false // get(){}, // set(v){} }); 

定义了 valuewritable , 一定不能有 getset, 反之亦然, 否则报错

对象里目前存在的属性描述符有两种主要形式:数据描述符存取描述符
数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。
存取描述符是由 getter 函数和 setter 函数所描述的属性。
一个描述符只能是这两者其中之一;不能同时是两者






这两种描述符都是对象。它们共享以下可选键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

默认值:

configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false。




enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false。




数据描述符还具有以下可选键值:

value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined。




writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
默认为 false。




存取描述符还具有以下可选键值:

get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为 undefined。




set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认为 undefined。




描述符默认值汇总

描述符可拥有的键值

configurable enumerable value writable get set
数据描述符 可以 可以 可以 可以 不可以 不可以
存取描述符 可以 可以 不可以 不可以 可以 可以
let obj={ 
   a:2,b:{ 
   c:3}}; Object.defineProperty(obj,'a',{ 
    configurable:true, enumerable:true, get(){ 
    return obj['a'] }, set(value){ 
    return obj['a']=value; } }) 
let obj={ 
   a:2,b:{ 
   c:3}}; Object.defineProperty(obj,'b',{ 
    writable:false, configurable:false }) obj.b=3; obj.b.c=4; console.log(obj)//{a:2,b:{c:4}} 
const obj = { 
   }; Object.defineProperty(obj, 'name', { 
    // configurable: false,//默认为false // enumerable: false,//默认为false value: 'kongzhi', // writable: false,/默认为false // get(){}, // set(v){} }); console.log(obj.name); // 输出 kongzhi // 改写obj.name 的值 obj.name = 111; console.log(obj.name); // 还是打印出 kongzhi,因为writable默认为false 
var o = { 
   }; o.a = 1; // 等同于: Object.defineProperty(o, "a", { 
    value: 1, writable: true, configurable: true, enumerable: true }); // 另一方面, Object.defineProperty(o, "a", { 
    value : 1 }); // 等同于: Object.defineProperty(o, "a", { 
    value: 1, writable: false, configurable: false, enumerable: false }); 

全局变量Date不可修改,为了安全性考虑

Object.defineProperty(window,'Date',{ 
    writable:false, configurable:false }) 

Object.defineProperties

Object.defineProperties本质上定义了obj 对象上props的可枚举属性相对应的所有属性。

var obj = { 
   }; Object.defineProperties(obj, { 
    'property1': { 
    value: true, writable: true }, 'property2': { 
    value: 'Hello', writable: false } // etc. etc. }); 

Proxy

Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。IE不兼容

const p = new Proxy(target, handler)

handler 对象的方法

handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。

所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

handler.getPrototypeOf() handler.setPrototypeOf() handler.isExtensible() handler.preventExtensions() handler.getOwnPropertyDescriptor() handler.defineProperty() handler.has()//in 操作符的捕捉器。 handler.get(target, property) handler.set(target, property, value) handler.deleteProperty()//delete 操作符的捕捉器。 handler.ownKeys() handler.apply() handler.construct()//new 操作符的捕捉器。 

基本操作

const handler = { 
    get: function(obj, prop) { 
    return prop in obj ? obj[prop] : 37; } }; const p = new Proxy({ 
   }, handler); p.a = 1; p.b = undefined; console.log(p.a, p.b); // 1, undefined console.log('c' in p, p.c); // false, 37 

Proxy只代理对象外层属性

let obj={ 
   a:1,b:{ 
   c:2}}; let handler={ 
    get:function(obj,prop){ 
    const v = Reflect.get(obj,prop); return v; // 返回obj[prop] }, set(obj,prop,value){ 
    return Reflect.set(obj,prop,value);//设置成功返回true } }; let p=new Proxy(obj,handler); p.a//会触发get方法 p.b.c//会触发get方法获取p.b,不会触发.c的set,因为c没被代理。 

递归代理对象内部对象

let obj={ 
   a:1,b:{ 
   c:2}}; let handler={ 
    get:function(obj,prop){ 
    const v = Reflect.get(obj,prop); if(v !== null && typeof v === 'object'){ 
    return new Proxy(v,handler);//代理内层 }else{ 
    return v; // 返回obj[prop] } }, set(obj,prop,value){ 
    return Reflect.set(obj,prop,value);//设置成功返回true } }; let p=new Proxy(obj,handler); p.a//会触发get方法 p.b.c//会先触发get方法获取p.b,然后触发返回的新代理对象的.c的set。 

可以看出Proxy代理对象时只会在调用时递归,不会一开始就全部递归,优化了性能。

Proxy对象和原始对象

let target = { 
   }; let p = new Proxy(target, { 
   }); p.a = 37; // 操作转发到目标 console.log(target.a); // 37. 操作已经被正确地转发 target.a=4; console.log(p.a)//4 console.log(target==p)//false 

总结

  1. Proxy使用上比Object.defineProperty方便的多。
  2. Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
    3. 如果对象内部要全部递归代理,则Proxy可以只在调用时递归,而Object.defineProperty需要在一开始就全部递归,Proxy性能优于Object.defineProperty。

  3. vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty。
  4. 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
  5. 数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
  6. Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/208794.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午10:45
下一篇 2026年3月19日 上午10:45


相关推荐

  • MSFCONSOLE COMMANDS「建议收藏」

    MSFCONSOLE COMMANDS「建议收藏」MSFCONSOLECORECOMMANDSTUTORIALTheMSFconsolehasmanydifferentcommandoptionstochoosefrom.ThefollowingareacoresetofMetasploitcommandswithreferencetotheiroutput.back…

    2025年9月27日
    2
  • HTML5期末大作业:节日网站设计——中国传统节日-春节(8个页面) HTML+CSS+JavaScript 中国传统节日春节网页HTML代码 学生网页课程设计期末作业下载 春节大学生网页设计制作成

    HTML5期末大作业:节日网站设计——中国传统节日-春节(8个页面) HTML+CSS+JavaScript 中国传统节日春节网页HTML代码 学生网页课程设计期末作业下载 春节大学生网页设计制作成HTML5 期末大作业 节日网站设计 中国传统节日 春节 8 个页面 HTML CSS JavaScript 临近期末 你还在为 HTML 网页设计结课作业 老师的作业要求感到头大 HTML 网页作业无从下手 网页要求的总数量太多 没有合适的模板 等等一系列问题 你想要解决的问题 在这篇博文中基本都能满足你的需求 原始 HTML CSS JS 页面设计 web 大学生网页设计作业源码 这是一个不错的网页制作 画面精明 非常适合初学者学习使用 作品介绍 1 网页作品简介方面 HTML 期末大学生网页设计作业 喜

    2026年1月31日
    3
  • 几种经典常用的滤波算法

    几种经典常用的滤波算法几种经典的滤波算法1、限幅滤波法(又称程序判断滤波法)A、方法:根据经验判断,确定两次采样允许的最大偏差值(设为A)每次检测到新值时判断:如果本次值与上次值之差<=A,则本次值有效如果本次值与上次值之差>A,则本次值无效,放弃本次值,用上次值代替本次值B、优点:能有效克服因…

    2022年5月24日
    40
  • 【react】子组件向父组件传值

    【react】子组件向父组件传值react 类组件 hooks 组件如何向父子间传值

    2026年3月17日
    2
  • Object与json字符串的相互转换[通俗易懂]

    Object与json字符串的相互转换[通俗易懂]第一步:引入fastjson的依赖jar包注:maven项目,直接在pom.xml中进行配置即可。注:如果引入此版本的依赖,导致项目不能启动(报错:找不到启动类);那么可以换一个版本的fastjson即可。给出文字版:<!–fastjson–><dependency><groupId>com.alibaba</…

    2022年10月10日
    6
  • [转]AVALONDOCK 2.0入门指南第一部分

    [转]AVALONDOCK 2.0入门指南第一部分AvalonDock2.0可以用来为WPF创建一个类似VisualStudio的界面,深入理解如何使用AvalonDock进行开发是很重要的。在这个入门指南里,我将演示如何开始使用AvalonDock,下面的文章都是基于2.0版本的。并且不能用于早期的版本。AvalonDock是一个组合的布局模型,很多的控件都在视图上显示,一个DockingManager类也显示在停靠…

    2022年7月20日
    14

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号