-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Cap
committed
Dec 27, 2024
1 parent
1d8c0b3
commit bdaacc4
Showing
3 changed files
with
254 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
--- | ||
title: 'Object.defineProperty与Proxy' # 当前页面内容标题,默认为 Markdown 文件中的第一个 h1 标签内容 | ||
shortTitle: '' # 当前页面的短标题 | ||
description: '' # 当前页面内容描述 | ||
icon: '' # 当前页面图标的 FontClass 或文件路径 (建议填写)。 | ||
author: { | ||
name: 'Cap' | ||
} | ||
isOriginal: true # 当前文章是否为原创。 | ||
date: 2024-12-27 # 写作时间。 | ||
category: '' # 分类 | ||
tag: 'vue' # 标签 | ||
sticky: 241227 # 是否在列表中置顶。当填入数字时,数字越大,排名越靠前 | ||
star: true # 是否收藏在博客主题的文章列表中。当填入数字时,数字越大,排名越靠前。 | ||
article: true # 是否将该文章添加至文章列表中 | ||
timeline: true # 是否将该文章添加至时间线中 | ||
--- | ||
|
||
## Object.defineProperty | ||
|
||
Object.defineProperty 是 ES5 引入的方法,用于在对象上定义新属性或修改现有属性。 | ||
|
||
```javascript | ||
let obj = {}; | ||
Object.defineProperty(obj, 'prop', { | ||
value: 42, | ||
writable: false | ||
}); | ||
``` | ||
|
||
### 优点 | ||
|
||
- 兼容性好,支持旧版浏览器 | ||
- 可以精确定义属性的特性(如可写、可枚举、可配置) | ||
|
||
### 缺点 | ||
|
||
- 不能监听数组的变化(如通过索引修改数组元素) | ||
- 不能监听新增属性 | ||
- 需要递归遍历对象的所有属性来实现深度监听 | ||
|
||
## Proxy | ||
|
||
Proxy 是 ES6 引入的特性,它可以创建一个对象的代理,从而实现基本操作的拦截和自定义。 | ||
|
||
```javascript | ||
let obj = {}; | ||
let proxy = new Proxy(obj, { | ||
get(target, property) { | ||
console.log(`Getting ${property}`); | ||
return target[property]; | ||
}, | ||
set(target, property, value) { | ||
console.log(`Setting ${property} to ${value}`); | ||
target[property] = value; | ||
return true; | ||
} | ||
}); | ||
``` | ||
|
||
### 优点 | ||
|
||
- 可以监听数组变化 | ||
- 可以监听新增属性 | ||
- 不需要递归遍历,可以懒处理 | ||
- 提供了更多的拦截方法(如 deleteProperty, has 等) | ||
|
||
### 缺点 | ||
|
||
- 兼容性较差,不支持 IE | ||
|
||
|
||
## 大规模数据处理的差异 | ||
|
||
|
||
在处理大规模数据时,这两种方法有以下主要差异: | ||
|
||
### A. 初始化性能: | ||
|
||
- Object.defineProperty 需要递归遍历对象的所有属性,对于大对象来说,初始化时间可能会很长。 | ||
- Proxy 不需要初始化时遍历,可以懒处理,因此初始化速度更快。 | ||
|
||
|
||
### B. 内存占用: | ||
|
||
- Object.defineProperty 会为每个属性创建 getter 和 setter,可能导致较高的内存占用。 | ||
- Proxy 创建的是整个对象的代理,不会为每个属性创建额外的函数,内存占用相对较低。 | ||
|
||
|
||
### C. 动态属性处理: | ||
|
||
- Object.defineProperty 不能监听新增属性,需要额外的处理(如 Vue 2.x 中的 Vue.set)。 | ||
- Proxy 可以自动监听新增属性,无需额外处理。 | ||
|
||
|
||
### d. 数组处理: | ||
|
||
- Object.defineProperty 不能有效地监听数组的变化,需要额外的处理。 | ||
- Proxy 可以直接监听数组的变化,包括通过索引修改元素。 | ||
|
||
## 性能比较 | ||
|
||
理论上,在处理大规模数据时,Proxy 的性能应该更好: | ||
|
||
1. 初始化更快:Proxy 不需要递归遍历对象,初始化大对象时更快。 | ||
2. 懒处理:Proxy 可以在真正访问属性时才执行拦截操作,而 Object.defineProperty 需要预先定义所有属性的 getter 和 setter。 | ||
3. 更少的内存开销:Proxy 为整个对象创建一个代理,而不是为每个属性创建 getter 和 setter。 | ||
4. 更好的数组处理:Proxy 可以直接监听数组操作,而 Object.defineProperty 需要额外的处理。 | ||
|
||
然而,实际性能可能因具体使用场景和浏览器实现而异。在某些情况下,Object.defineProperty 可能表现更好,特别是在旧版浏览器中。 | ||
|
||
## 结论: | ||
对于现代web应用,特别是处理大规模数据时,Proxy 通常是更好的选择。它提供了更强大和灵活的功能,理论上有更好的性能。然而,如果需要支持旧版浏览器(如 IE),则可能需要使用 Object.defineProperty。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
--- | ||
title: 'Object.defineProperty可能表现更好的场景' # 当前页面内容标题,默认为 Markdown 文件中的第一个 h1 标签内容 | ||
shortTitle: '' # 当前页面的短标题 | ||
description: '' # 当前页面内容描述 | ||
icon: '' # 当前页面图标的 FontClass 或文件路径 (建议填写)。 | ||
author: { | ||
name: 'Cap' | ||
} | ||
isOriginal: true # 当前文章是否为原创。 | ||
date: 2024-12-27 # 写作时间。 | ||
category: '' # 分类 | ||
tag: 'vue' # 标签 | ||
sticky: 241227 # 是否在列表中置顶。当填入数字时,数字越大,排名越靠前 | ||
star: true # 是否收藏在博客主题的文章列表中。当填入数字时,数字越大,排名越靠前。 | ||
article: true # 是否将该文章添加至文章列表中 | ||
timeline: true # 是否将该文章添加至时间线中 | ||
--- | ||
|
||
## 简单对象的监听 | ||
|
||
当我们只需要监听一个简单对象的少量属性时,Object.defineProperty 可能会有更好的性能。这是因为它不需要创建额外的代理对象。 | ||
|
||
```javascript | ||
let obj = {}; | ||
Object.defineProperty(obj, 'name', { | ||
get() { | ||
console.log('Getting name'); | ||
return this._name; | ||
}, | ||
set(value) { | ||
console.log('Setting name'); | ||
this._name = value; | ||
} | ||
}); | ||
``` | ||
|
||
在这种情况下,Object.defineProperty 直接修改了原对象,而 Proxy 会创建一个新的代理对象。 | ||
|
||
## 频繁访问的小型对象 | ||
|
||
对于频繁访问的小型对象,Object.defineProperty 可能会有更好的性能,因为它不需要通过代理来访问属性。 | ||
|
||
```javascript | ||
let person = { name: 'John', age: 30 }; | ||
Object.keys(person).forEach(key => { | ||
let value = person[key]; | ||
Object.defineProperty(person, key, { | ||
get() { | ||
console.log(`Getting ${key}`); | ||
return value; | ||
}, | ||
set(newValue) { | ||
console.log(`Setting ${key}`); | ||
value = newValue; | ||
} | ||
}); | ||
}); | ||
``` | ||
|
||
在这个例子中,直接访问 person.name 或 person.age 可能比通过 Proxy 访问更快。 | ||
|
||
## 旧版浏览器兼容性 | ||
|
||
在需要支持旧版浏览器(如 IE11)的情况下,Object.defineProperty 是唯一的选择,因为这些浏览器不支持 Proxy。 | ||
|
||
```javascript | ||
// 这在 IE11 中可以工作 | ||
let obj = {}; | ||
Object.defineProperty(obj, 'prop', { | ||
value: 42, | ||
writable: true | ||
}); | ||
|
||
// 这在 IE11 中会报错 | ||
let proxy = new Proxy({}, { | ||
get(target, prop) { | ||
return 42; | ||
} | ||
}); | ||
``` | ||
|
||
## 特定属性的精细控制 | ||
|
||
当我们需要对特定属性进行精细控制时,Object.defineProperty 可能更合适。例如,我们可以轻松地创建一个只读属性: | ||
|
||
```javascript | ||
let obj = {}; | ||
Object.defineProperty(obj, 'constant', { | ||
value: 42, | ||
writable: false, | ||
configurable: false | ||
}); | ||
``` | ||
|
||
虽然 Proxy 也可以实现类似的功能,但可能需要更多的代码。 | ||
|
||
## 与旧代码的兼容性 | ||
|
||
在一些遗留系统中,可能已经大量使用了 Object.defineProperty。在这种情况下,继续使用 Object.defineProperty 可能会更容易维护和理解。 | ||
|
||
```javascript | ||
// 假设这是一个已存在的代码库 | ||
function createPerson(name, age) { | ||
let person = {}; | ||
Object.defineProperty(person, 'name', { | ||
get() { return name; }, | ||
set(value) { name = value; } | ||
}); | ||
Object.defineProperty(person, 'age', { | ||
get() { return age; }, | ||
set(value) { age = value; } | ||
}); | ||
return person; | ||
} | ||
|
||
// 继续使用 Object.defineProperty 可能比引入 Proxy 更容易维护 | ||
``` | ||
|
||
## 单一属性的监听 | ||
|
||
当我们只需要监听一个对象的单一属性时,Object.defineProperty 可能会有更好的性能,因为它不需要为整个对象创建代理。 | ||
|
||
```javascript | ||
let obj = { a: 1, b: 2, c: 3 }; | ||
Object.defineProperty(obj, 'a', { | ||
get() { | ||
console.log('Getting a'); | ||
return this._a; | ||
}, | ||
set(value) { | ||
console.log('Setting a'); | ||
this._a = value; | ||
} | ||
}); | ||
``` | ||
|
||
在这个例子中,我们只监听了 'a' 属性,而 'b' 和 'c' 保持不变。使用 Proxy 可能会对所有属性都进行不必要的代理。 | ||
|
||
## 总结 | ||
|
||
虽然 Proxy 在大多数现代场景下可能更优,但 Object.defineProperty 在某些特定情况下仍然有其优势。这些情况主要包括:简单对象的监听、频繁访问的小型对象、需要旧版浏览器兼容性、特定属性的精细控制、与旧代码的兼容性,以及单一属性的监听等。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters