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

yizhihongxing

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日

相关文章

  • Vue不能检测到数据变化的几种情况说明

    Vue是一款前端框架,其特点之一就是数据驱动视图,即根据数据的变化自动更新视图。但是,在某些情况下,Vue不能检测到数据的变化,导致视图没有更新。那么Vue不能检测到数据变化的几种情况有哪些呢?本攻略将一一讲解。 直接修改数组下标无法触发更新 Vue能够监听到数组的变化,但不能监听到数组下标的变化。如果直接修改数组下标,Vue将无法检测到数据的变化,也就无法…

    Vue 2023年5月28日
    00
  • vue实现跨域的方法分析

    下面是“vue实现跨域的方法分析”的完整攻略: 1. 什么是跨域 跨域是指在浏览器端,当前页面的域名与所访问的服务器域名不一致时产生的安全限制。例如,在一个网站的前端代码中,我们不能直接访问另一个域名的接口,否则会产生跨域问题。 2. Vue实现跨域的方法 在Vue中,我们可以通过配置代理实现跨域访问,一般有两种方式: 方式1:在vue.config.js文…

    Vue 2023年5月28日
    00
  • 基于webpack4+vue-cli3项目实现换肤功能

    下面我来详细讲解一下“基于webpack4+vue-cli3项目实现换肤功能”的完整攻略。 背景 随着前端技术的不断发展,越来越多的网站和应用程序需要实现换肤功能,以适应不同用户的喜好和需求。本文将介绍如何在基于webpack4和vue-cli3的项目中实现换肤功能。 准备工作 在开始实现换肤功能之前,我们需要进行一些准备工作: 熟悉 webpack4 和 …

    Vue 2023年5月28日
    00
  • Vue基本使用之对象提供的属性功能

    Vue基本使用之对象提供的属性功能 Vue.js 是一款构建数据驱动的 Web 应用程序的前端框架,提供一系列的属性、指令和组件等功能,方便开发者进行页面开发和交互操作。 其中,Vue对象提供了一些常用的属性功能,本文将介绍Vue对象提供的属性功能的使用方法。 Vue实例中提供的属性 Vue提供了许多属性来控制实例中的数据和行为,以下是常用的一些属性: $d…

    Vue 2023年5月28日
    00
  • vue中使用Axios最佳实践方式

    下面就是关于”vue中使用Axios最佳实践方式”的完整攻略: 确定请求的方式 在使用Axios时,我们需要确定请求的方式,可以使用get、post、put、delete等方式,同一个接口的不同请求方式可以得到不同的数据。如需向后端发起请求,需要在axios对象中添加请求方式,具体操作如下: import axios from ‘axios’ // 设置请求…

    Vue 2023年5月28日
    00
  • 详解离线安装npm包的几种方法

    当我们需要使用npm包时,通常我们会使用npm命令在线安装。但是,某些情况下我们可能需要离线安装npm包,比如网络环境不佳或无法联网的情况下。 本文将为大家详细讲解“详解离线安装npm包的几种方法”。 方法一:使用npm install命令 在网络良好的情况下,可以使用npm install命令将需要的npm包从线上下载到本地文件系统,这样就可以在没有网络的…

    Vue 2023年5月28日
    00
  • vue项目实现文件下载进度条功能

    下面是“vue项目实现文件下载进度条功能”的完整攻略: 服务端实现文件下载接口 首先,在服务器端需要实现一个文件下载的接口,将需要下载的文件流返回给客户端。根据不同的后端语言和框架,具体实现会有所差异。这里以 Node.js 和 Express 框架为例,示例如下: // 下载文件接口 app.get(‘/download’, (req, res) =&gt…

    Vue 2023年5月28日
    00
  • vue项目中实现多文件上传功能实例代码

    下面是“vue项目中实现多文件上传功能实例代码”的完整攻略: 实现思路 在 Vue 项目中实现多文件上传功能,需要联合使用 HTML5 的 FileReader API 和 axios 来实现。实现思路如下: 通过 input 标签接收用户上传的文件。 把文件列表存储到 vue 组件的 data 中,通过 v-for 循环来渲染上传列表。 使用 FileRe…

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