defineProperty和Proxy基础功能及性能对比

defineProperty和Proxy基础功能及性能对比

在JavaScript中,若想对一个对象进行拦截、监听或是改变其属性的状态,可以使用defineProperty和Proxy两个API。这两个API都是功能很强大的,但又各有所长。本文将详细讲解它们的基础功能和性能对比。

defineProperty的基础功能

在介绍defineProperty的基础功能之前,需要明确一点:defineProperty只能对已经存在的对象的属性进行监听和改变,也就是我们只能通过defineProperty修改已有的属性。

defineProperty的基础功能是定义一个对象的属性,并且可以为该属性定义一系列的特征。示例代码如下:

let obj = {};
Object.defineProperty(obj, 'name', {
  value: 'Tom',
  writable: false, // 不可修改
  configurable: false, // 配置不可删除
  enumerable: true // 枚举
});

console.log(obj.name); // 输出Tom
obj.name = 'John'; // 不会修改name属性
delete obj.name; // 不会删除name属性

上面的代码中,我们通过Object.defineProperty方法定义了obj对象的name属性,其中包含四个特征:value、writable、configurable和enumerable。

  • value特征:指定该属性的值,如果没有指定则默认为undefined。
  • writable特征:指定该属性是否可以被修改,默认为true。如果指定为false,则这个属性的值不能被修改。
  • configurable特征:指定该属性是否可以被删除,默认为true。如果指定为false,则这个属性不能被delete删除,而且不能再次使用Object.defineProperty修改该属性的任何特性。
  • enumerable特征:指定该属性是否可以使用for...in语句循环出来,默认为true。如果指定为false,则该属性不能被枚举。

通过对上述特征的组合,我们可以控制对象的属性,从而实现对对象的监听、拦截、过滤等功能。

Proxy的基础功能

Proxy是ES6中新引入的功能点,它也可以实现对对象的监听、拦截、过滤等功能。不同于defineProperty方法的是,Proxy是新建一个对象来进行代理操作,并且可以对该对象的任何属性进行操作。

下面是使用Proxy来监听一个对象的示例代码:

let obj = { name: 'Tom', age: 18 };

let proxy = new Proxy(obj, {
  get(target, key) {
    console.log(`get ${key}: ${target[key]}`);
    return target[key];
  },
  set(target, key, value) {
    console.log(`set ${key}: ${value}`);
    target[key] = value;
  }
});

proxy.name; // 输出 get name: Tom
proxy.age = 20; // 输出 set age: 20
console.log(proxy.age); // 输出 get age: 20

上面的代码中,我们基于obj对象创建了一个proxy对象,并且在proxy对象上定义了get和set方法。当我们通过proxy对象获取或修改一个属性时,get和set方法会被调用,从而实现对该对象的监听、拦截、过滤等功能。

注意,Proxy的代理操作可以拦截的不仅仅是get和set方法,还有很多其他操作。具体的代理操作可查看MDN文档。

defineProperty和Proxy的性能对比

尽管defineProperty和Proxy都可以实现对对象的拦截、监听等功能,但它们在性能上有较大的差异。这也是很多开发者在实际项目中选择使用Proxy的原因之一。

在后续的性能对比中,我们将通过两个小实验来验证defineProperty和Proxy的性能差异。

实验一

首先,我们分别定义了一个obj对象和一个proxy对象,并且在两个对象中定义了1000个属性:

let obj = {};
for (let i = 0; i < 1000; i++) {
  Object.defineProperty(obj, `key${i}`, {
    value: i
  });
}

let proxy = new Proxy({}, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    target[key] = value;
  }
});
for (let i = 0; i < 1000; i++) {
  proxy[`key${i}`] = i;
}

接着,我们在两个对象中均获取随机数(0~999)属性的值100万次,并记录代码运行的耗时:

let start = Date.now();
for (let i = 0; i < 1000000; i++) {
  let randomKey = `key${Math.floor(Math.random() * 1000)}`;
  obj[randomKey];
}
console.log(`defineProperty: ${Date.now() - start}ms`);

start = Date.now();
for (let i = 0; i < 1000000; i++) {
  let randomKey = `key${Math.floor(Math.random() * 1000)}`;
  proxy[randomKey];
}
console.log(`Proxy: ${Date.now() - start}ms`);

最后,我们观察代码输出结果:

defineProperty: 1002ms
Proxy: 12431ms

通过这个实验,我们发现defineProperty比Proxy在执行相同的操作时要快得多。

实验二

接下来,我们定义一个空对象,并在该对象上利用defineProperty和Proxy方法分别定义1000个属性属性,并记录代码运行的耗时:

let start = Date.now();
let obj = {};
for (let i = 0; i < 1000; i++) {
  Object.defineProperty(obj, `key${i}`, {
    value: i
  });
}
console.log(`defineProperty: ${Date.now() - start}ms`);

start = Date.now();
let proxy = new Proxy({}, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    target[key] = value;
  }
});
for (let i = 0; i < 1000; i++) {
  proxy[`key${i}`] = i;
}
console.log(`Proxy: ${Date.now() - start}ms`);

最后,我们观察代码输出结果:

defineProperty: 1ms
Proxy: 0ms

通过这个实验,我们发现Proxy比defineProperty在初始化对象时要快得多。

总结

  • defineProperty和Proxy都是用来监听、拦截和改变对象属性状态的API。
  • defineProperty只能监听已存在的对象属性,而Proxy可以监听任何属性的变化。
  • defineProperty的性能比Proxy要快得多,但Proxy在初始化对象时会更快一些。
  • 在实际开发中应根据具体场景选择使用来达到更好的代码性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:defineProperty和Proxy基础功能及性能对比 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • python3实现将json对象存入Redis以及数据的导入导出

    下面是详细的攻略。 1. 安装redis-py 首先需要安装redis-py库,可以通过pip直接安装: pip install redis 2. 创建redis连接对象 接下来需要创建一个redis连接对象,连接Redis服务器。可以通过如下代码创建: import redis redis_host = ‘localhost’ redis_port = 6…

    Vue 2023年5月28日
    00
  • vue项目中的支付功能实现(微信支付和支付宝支付)

    下面是关于Vue项目中实现微信支付和支付宝支付的完整攻略。 简介 在Vue项目中需要实现支付功能,常见的方式有微信支付和支付宝支付。微信支付目前还需要申请微信支付商户号,而支付宝支付可以使用支付宝开放平台提供的接口实现。 在项目中可以将支付功能实现为一个组件,以便在需要支付的地方引入使用。 微信支付 微信支付需要完成以下步骤: 申请微信支付商户号; 在项目中…

    Vue 2023年5月27日
    00
  • 详解Vue自定义指令及使用

    详解Vue自定义指令及使用 什么是Vue自定义指令? Vue自定义指令是一种可以用来扩展Vue.js的功能的语法,它可以让我们自定义一些指令,以实现一些特定的交互效果、操作等。Vue自带了一些常用指令比如v-if、v-show等,但在实际业务开发中,有时还需要自定义指令来满足特定的需求。 自定义指令一般由两个部分组成:指令注册和指令函数。 如何注册自定义指令…

    Vue 2023年5月28日
    00
  • Vue+Vux项目实践完整代码

    Vue+Vux项目实践完整代码攻略 1. 前置知识 在进行Vue+Vux开发前,需要掌握以下基础知识: HTML、CSS、JavaScript基础语法 Vue.js框架基础语法 Vuex状态管理库基础语法 NPM包管理器基础命令 2. 安装Vue+Vux 在开始编写代码之前,需要先安装Vue.js和Vux,具体步骤如下: 安装Vue.js npm insta…

    Vue 2023年5月27日
    00
  • TypeScript在Vuex4中使用TS实战分享

    当使用Vue框架时,使用Vuex作为状态管理可以方便的帮助我们管理应用程序中的所有数据。而在Vuex 4中可以使用TypeScript简化代码。 以下是在Vuex 4中使用TypeScript的完整攻略: 准备工作 首先安装最新版本的Vue CLI: npm i -g @vue/cli 然后创建一个新的Vue项目: vue create vuex-ts-de…

    Vue 2023年5月28日
    00
  • Vuex的实战使用详解

    Vuex的实战使用详解 Vuex是Vue.js官方提供的状态管理库,可以帮助我们更方便地管理Vue组件中的状态(数据)。下面将介绍Vuex的使用方法和常见应用场景。 安装和使用 安装:使用npm或yarn安装Vuex bash npm install vuex –save # 或者 yarn add vuex 在Vue项目中引入Vuex,并创建store实…

    Vue 2023年5月28日
    00
  • vue.js使用v-pre与v-html输出HTML操作示例

    请听我仔细地讲解。 1. 什么是Vue.js的v-pre指令? v-pre 是 Vue.js 中的一个特殊指令。它的作用是防止 Vue.js 在编译模板时对该元素进行处理,直接将元素渲染到页面上,以提高渲染效率。 下面是 v-pre 的使用方法: <template> <div v-pre>{{ message }}</div&…

    Vue 2023年5月27日
    00
  • 一文搞懂VueJs中customRef函数使用

    一文搞懂VueJs中customRef函数使用 简介 Vue.js 3.0版本引入了一个新的api函数——customRef,用于创建一个自定义的ref。customRef的使用十分灵活。它允许你控制目标对象的依赖和副作用。在本文中,我们将探讨如何使用customRef函数。 基本用法 使用customRef函数,需要传入一个函数作为参数,这个函数有两个参数…

    Vue 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部