个人文档
  • AI编程Cursor
  • GPT使用笔记
  • npm常用库合集
  • 同步用
  • 小Demo们
  • 工具网站教程集合
  • HTML、CSS 工具方法集合
    • HTML 全局属性
    • css常用功能
    • font-face 字体|子集相关
    • iframe父子页面传值
    • input输入优化
    • loading状态
    • nodejs使用谷歌邮箱发邮件
    • 为 Dom 自定义事件监听
    • 初始html的head标签配置
    • 拼音输入中文汉字的事件监听
    • 文字颜色效果
    • 文档片段范围 Range
    • 移动端开发-rem
    • 等宽字体推荐
    • 网站SEO优化注意点
    • 邮件html模板
  • JS 工具方法集合
    • Axios 简单使用
    • Axios 简单封装
    • Gitbook的安装和使用
    • Github 登录开发
    • HTML转为纯文本
    • JS 中强大的操作符
    • cookie 操作
    • js 动态加载js资源
    • js 常用功能语句
    • js取代trycatch的方法封装
    • js接口下载二进制
    • script 标签的异步属性
    • 判断当前是移动端还是pc端
    • 刷新token队列管理
    • 前端多线程 Web Worker
    • 加密-AES对称加密
    • 加密-node进行rsa加密解密
    • 地区省市区三级联动的地址数据 + 功能
    • 复制插件
    • 开发时环境变量
    • 得到随机图片
    • 数字格式整理集合
    • 数学计算插件
    • 时间格式整理
    • 获取ip地址
    • 获取url传参
    • 进制转换和位运算符
    • 页面隐藏|激活|关闭的监听
  • JS 知识点研究
    • Babel 历史和原理
    • Babel 配置和使用
    • Function 的 apply、call、bind
    • HTTP浏览器缓存粗解
    • Source map 文件还原为源码
    • TS常用技巧
    • js 的加载和模块化
    • js 的新数据类型 Symbol
    • js的代理对象 proxy 和 defineProperty
    • js的原型链 prototype
    • vite 打包体积优化
    • webpack 可视化打包文件大小插件
    • webpack 基础使用配置
    • webpack 版本5的报错
    • yeoman 开发脚手架的工具
    • 同步异步和微任务宏任务
    • 移动端调试---谷歌工具+eruda+vconsole
    • 转换-Blob URL
    • 转换-FileReader
    • 转换-Js文件类型和转换
    • 转换-前端开发的URL的编码和解码
    • 转换-字符串和Base 64的转换
  • Node 和 Npm 相关
    • Node 开发环境配置
    • express + jwt 校验
    • node 常用方法
    • node后台服务器-PM2
    • node基本使用
    • npm 中依赖的版本问题
    • npm 功能使用
    • npm指令说明和其他对比
    • nvm版本管理+自动切换node版本
  • React 学习
    • React Hook
    • React 项目基础开发
    • React.memo 和 React.PureComponent
    • React懒加载进阶
    • useContext Hook
    • useEffect Hook
    • useMemo 和 useCallback - Hook
    • useRef Hook
    • useState Hook
    • 同步修改变量功能封装 useVal for react
    • 轻便的传值组件
  • Rust 语言相关
    • Rust 基本
    • Rust 基础学习
    • Rust 调用 Object-C 的API
    • Tauri 基本使用
    • Tauri 是什么
  • VUE 学习
    • Vue3 使用
    • Vue3使用hook
    • Vue开发小技术点
    • vue路由切换时的动画效果
    • 花式引入组件和资源-打包时拆包减少js体积
  • Web3相关
    • Web3.0开发上-准备和概念理解
    • Web3.0开发下-功能代码示例
    • 以太坊区块链和Web3.0
    • 开发智能合约
  • python
    • pyenv版本管理工具
    • python初始化
    • python基本概念
    • venv虚拟环境
  • 个人其他
    • Steam Deck的基本设置和插件
  • 其他编程相关
    • Git教程和常用命令
    • Java开发-JDK和Maven的安装和卸载
    • Jenkins安装和基本使用
    • Linux系统指令
    • Mac 使用2K屏幕开启缩放
    • Mac 使用VS code打开项目
    • Mac 安装 Homebrew
    • Mac 的终端 shell 与 zsh
    • Mac 软件和插件
    • MacBook使用建议
    • Mac升降级到指定版本的系统
    • Mac安装Zsh
    • Mac安装软件各种提示
    • Mac系统脚本语言 AppleScript 的使用
    • Mac终端代理工具
    • Markdown(md)文档开发-Typora
    • Mysql 的安装和使用
    • Nginx 安装和基础使用
    • Nginx 稍微高深的配置
    • Slate - Api 的文档开发工具
    • Sublime配置
    • Ubuntu的 apt-get 使用
    • VScode配置
    • Windows 软件和插件
    • curl 工具使用
    • github 网站访问优化
    • host 文件
    • inquirer 终端中和用户交互
    • uTools的插件开发教程
    • vim 文本编辑功能
    • 使用 Github Pages 免费部署网站
    • 压缩指令 zip 和 unzip
    • 油猴的安装和开发(Tampermonkey)
    • 阿里云简略使用
  • 微信开发
    • 微信小程序开发
    • 微信开发必读
    • 微信开发提前购买域名
    • 微信手机打开的页面中授权登录
    • 微信扫码登录
    • 微信服务号登录+推送服务提醒
    • 自定义分享卡片-node.js实现
  • 数据结构与算法
    • KMP算法
    • Wildcard字符串分析算法
    • 二叉树
    • 字典树
    • 时间复杂度浅析
    • 算法神器——动态规划
Powered by GitBook
On this page
  • defineProperty 和 proxy
  • 对象和类的 getter 和 setter
  • Object.defineProperty
  • 对象代理 proxy

Was this helpful?

  1. JS 知识点研究

js的代理对象 proxy 和 defineProperty

title: defineProperty 和 proxy id: e8deee0107f7390989e5aaa7bd015512 tags: [] date: 2000/01/01 00:00:00 updated: 2023/03/04 19:29:12 isPublic: true --#|[分隔]|#--

defineProperty 和 proxy

对象和类的 getter 和 setter

getter 和 setter 作用于对象或类的一个属性,设置当获取或设置该属性时,执行的方法。

使用 getter 或 setter 定义的属性,称为伪属性。

getter

官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/get

语法:

{get prop() { ... } }
{get [expression]() { ... } }
  • prop:要获取值的的属性名

  • expression:表达式,类似比如 let type = 'apple'; obj[type] = 100;

setter

官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/set

语法:

{set prop(val) { . . . }}
{set [expression](val) { . . . }}、
  • prop:要设置 setter 的属性名

  • val:传入的数据,也就是要设置的值

  • expression:表达式,类似比如 let type = 'apple'; obj[type] = 100;

getter 和 setter 程序说明

let obj = {
  _num: 0,
  get num() {
    this._num++
    return this._num
  },
  set num(val) {
    this._num = val * 10
    return this._num
  }
}

console.log(obj._num) // 0 - 直接取 _num,直接返回,无其他作用
console.log(obj.num) // 1 - 取 num,执行了方法 _num 自增1,并返回 _num
console.log(obj._num) // 1 - 直接取 _num,直接返回,此时 _num 在上一步被自增 1
console.log(obj.num) // 2
console.log(obj._num) // 2

obj.num = 2 // 设置 num,执行它的 setter 方法,实际给 _num 设置的值是 2 * 10

console.log(obj._num) // 20 直接取 _num
console.log(obj.num) // 21 取 num,先自增1

直接打印对象 obj,可以看到如下的显示:

  • _num 是普通属性,直接显示

  • num 会在获取时调用 getter 方法,可能会影响程序运行,所以没有直接显示,可以点击一下,执行 getter 方法查看

  • num 的 getter 和 setter 方法表现为暗色的属性

注意

  • 不能为一个已有真实值的变量使用 get 或 set ,也不能为一个属性设置多个 get 或 set

  • 可以使用对象的 delete 方法删除伪属性

  • 当给对象使用 get 关键字时,它和 Object.defineProperty() 有类似的效果

  • 在类中使用 get 和 set,再通过类实例化出来的对象,属性将被定义在对象实例的原型上

Object.defineProperty

官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

Object.defineProperty(obj, prop, descriptor)

  • obj:要定义属性的对象

  • prop:要定义或修改的属性的名称或 Symbol

  • descriptor(可选):要定义或修改的属性描述符对象

属性描述符:是对象中一个属性的相关信息,比如这个属性的值、值是否可更改、是否可枚举等等。

使用 defineProperty 设置属性,主要就是为了设置属性描述符。

属性描述符又分为两种,一个描述符只能是这两者其中之一,不能同时是两者,否则会直接报错:

  • 数据描述符:常规对象都是这种,是一个具有值的属性,该值可以是可写的,也可以是不可写的

  • 存取描述符:属性描述符中有 get 或 set 属性的属性描述符们

所有属性描述符为以下几个字段:

属性描述符
说明
默认值

value

属性的值

undefined

writable

值为 true 时,属性的值(也就是 value)才能被修改

false

enumerable

值为 true 时,该属性才会出现在对象的枚举属性中

false

configurable

值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除

false

get

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

undefined

set

属性的 setter 函数,当属性值被修改时,会调用此函数,该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象

undefined

两种属性描述符可用的属性:

描述符类型
configurable
enumerable
value
writable
get
set

数据描述符

可以

可以

可以

可以

不可以

不可以

存取描述符

可以

可以

不可以

不可以

可以

可以

程序说明:

const obj = {
  key_1: 100
};

let obj2 = Object.defineProperty(obj, 'pro_1', {
  value: '我是 pro_1',
})

Object.defineProperty(obj, 'pro_2', {
  enumerable: true, // 设置可枚举
  get() {
    return '我是 pro_2'
  },
})

obj.key_1 = 101 // 修改三个属性的值
obj.pro_1 = 101 // 修改三个属性的值
obj.pro_2 = 101 // 修改三个属性的值

console.log(obj === obj2) // true
console.log(obj.key_1) // 101 - 被修改
console.log(obj.pro_1) // 我是 pro_1 - 未设置 writable 为true 不能修改
console.log(obj.pro_2) // 我是 pro_2 - 设置了 get,是存取器属性,未设置 set,值无法被修改
console.log(Object.keys(obj)) // ['key_1', 'pro_2'] - 可以被枚举的属性

直接打印对象 obj,可以看到如下的显示:

  • key_1 和 pro_2 可遍历的是亮的,不可遍历的 pro_1 颜色比较暗

  • pro_2 的值是获取值才运行方法返回的,需要点击一下运行 get 方法才能看到值,所以直接打印是,pro_2 的值是省略号

  • pro_2 是一个存取器属性,打印中也展示这一特点

对象代理 proxy

proxy 用于创建一个对象代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

官方文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

语法:

const objProxy = new Proxy(target, handler)

target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 handler:一个对象,属性通常为函数,每个函数分别定义了在执行各种操作时代理对象的行为。

handler对象最常用的两个属性:

  • get:获取对象中某个属性,参数如下

    • target:被代理的对象本身

    • prop:要获取的属性

  • set:设置对象中某个属性,参数如下:

    • target:被代理的对象本身

    • prop:要设置的属性

    • value:赋的值

所有的可设置见官网:一个完整的_traps_列表示例

程序说明:

let obj = {
  num: 1,
}
// 生成对象代理
let obj_proxy = new Proxy(obj, {
  get(target, prop) {
    console.log(target === obj) // true
    return target[prop] + '——来自proxy'
  },
  set(target, prop, value) {
    console.log(target === obj) // true
    target[prop] = value * 10
    return target[prop]
  }
})
// 打印查看一下值
console.log(obj.num) // 1
console.log(obj_proxy.num) // 1——来自proxy

obj.num = 2 // 直接修改对象

console.log(obj.num) // 2
console.log(obj_proxy.num) // 2——来自proxy

obj_proxy.num = 3 // 通过对象代理修改

console.log(obj.num) // 3
console.log(obj_proxy.num) // 3——来自proxy

delete obj.num // 删除属性

console.log(obj.num) // undefined
console.log(obj_proxy.num) // undefined——来自proxy

自己封装 proxy 代理深层对象

proxy 作用于整个对象,但只能配置对象的直接属性,不能深层代理,比如对象的某个属性本身是个对象,就无法再代理这个对象了,这是就需要在 get 方法中,对值做一个判断,如果是个对象,则需要再次生成一个 proxy 代理。

// 用于存储所有的 proxy
const proxys = new Map()

let obj = getProxy({
  a: 10,
  d: {e: '我是e'}
})

obj.b = {c: 100}
obj.b.c = 200
console.log(obj.b.c)
console.log(obj.d.e)

function getProxy(obj) {
  // 如果有,直接返回
  if (proxys.has(obj)) {
    return proxys.get(obj)
  }
  let proxy = new Proxy(obj, {
    set(target, prop, value) {
      console.log('设置 ', prop)
      target[prop] = value
      return target[prop]
    },
    get(target, prop) {
      console.log('获取 ', prop)
      if (typeof(target[prop]) === 'object') {
        return getProxy(target[prop])
      }
      return target[prop]
    },
  })
  // 存入 proxys 中
  proxys.set(obj, proxy)
  return proxy
}

// 最终打印顺序:
// 设置  b - 正在执行 obj.b = {c: 100},要设置 b,需要先获取一下b
// 获取  b - 正在执行 obj.b.c = 200,要获取 c,需要获取它的父对象 b
// 设置  c - 正在执行 obj.b.c = 200,设置 c
// 获取  b - 正在执行 console.log(obj.b.c),要打印 c,需要先获取 b
// 获取  c - 正在执行 console.log(obj.b.c),获取了 b,要再获取 c
// 200 - 正在执行 console.log(obj.b.c) 正常打印的 c 的值
// 获取  d 正在执行 console.log(obj.d.e),要打印 e,需要先获取 d
// 获取  e 正在执行 console.log(obj.d.e),正常打印的 e 的值

可撤销的代理对象 Proxy.revocable

Proxy.revocable() 方法可以用来创建一个可撤销的代理对象。

语法:

const { proxy, revoke } = Proxy.revocable(target, handler);
  • proxy:new Proxy(target, handler) 的返回值

  • revoke:撤销的当前代理对象的方法,可以直接执行

一旦某个代理对象被撤销,它将变得几乎完全不可调用,在它身上执行任何的可代理操作都会抛出 TypeError 异常(注意,可代理操作一共有 14 种,执行这 14 种操作以外的操作不会抛出异常)。一旦被撤销,这个代理对象便不可能被直接恢复到原来的状态,同时和它关联的目标对象以及处理器对象都有可能被垃圾回收掉。再次调用撤销方法 revoke() 则不会有任何效果,但也不会报错。

Previousjs 的新数据类型 SymbolNextjs的原型链 prototype

Last updated 3 months ago

Was this helpful?

Snipaste_2020-12-31_16-25-21.png
Snipaste_2020-12-31_15-10-55.png