JavaScript Proxy 对象、eval函数详解

🧑‍🎓 个人主页:《爱蹦跶的大A阿》

🔥当前正在更新专栏:《VUE》 、《JavaScript保姆级教程》《krpano》《krpano中文文档》

​ 

目录

✨ 前言

✨ 正文

Proxy

什么是 Proxy

代理 handlers

get 捕获器

set 捕获器

Reflect API

Proxy vs Object.defineProperty

总结

二、eval函数

eval基本用法

eval作用域

eval返回值

eval局限性

eval实际应用

总结

✨ 结语


 

✨ 前言

        JavaScript作为一门非常灵活的语言,提供了许多强大的特性来扩展开发者的能力。但同时,一些特性如果使用不当,也会带来危险。

        本文将详细探索Proxy和eval这两个功能强大但危险度较高的JavaScript特性。Proxy可以拦截并修改对象行为,而eval可以执行代码字符串。

        我们将深入学习它们的用法,以及需要注意的安全隐患。同时也会介绍它们的实际应用场景,在必要时合理利用这些特性的力量。

✨ 正文

一、Proxy

什么是 Proxy

        Proxy 是 ES6 新增的功能,可以帮助我们自定义对象的各种操作。Proxy 用于自定义对象的基本操作,比如属性访问、函数调用等。

其基本语法如下:

let proxy = new Proxy(target, handler);
  • target - 要代理的对象
  • handler - 一个对象,定义代理的行为

由于没有捕捉器,所有对 proxy 的操作都直接转发给了 target

  1. 写入操作 proxy.test= 会将值写入 target
  2. 读取操作 proxy.test 会从 target 返回对应的值。
  3. 迭代 proxy 会从 target 返回对应的值。

我们可以看到,没有任何捕捉器,proxy 是一个 target 的透明包装器(wrapper)。

Proxy 捕捉器会拦截这些方法的调用。它们在 proxy 规范 和下表中被列出。

对于每个内部方法,此表中都有一个捕捉器:可用于添加到 new Proxy 的 handler 参数中以拦截操作的方法名称:

内部方法Handler 方法何时触发
[[Get]]get读取属性
[[Set]]set写入属性
[[HasProperty]]hasin 操作符
[[Delete]]deletePropertydelete 操作符
[[Call]]apply函数调用
[[Construct]]constructnew 操作符
[[GetPrototypeOf]]getPrototypeOfObject.getPrototypeOf
[[SetPrototypeOf]]setPrototypeOfObject.setPrototypeOf
[[IsExtensible]]isExtensibleObject.isExtensible
[[PreventExtensions]]preventExtensionsObject.preventExtensions
[[DefineOwnProperty]]definePropertyObject.definePropertyObject.defineProperties
[[GetOwnProperty]]getOwnPropertyDescriptorObject.getOwnPropertyDescriptorfor..inObject.keys/values/entries
[[OwnPropertyKeys]]ownKeysObject.getOwnPropertyNamesObject.getOwnPropertySymbolsfor..inObject.keys/values/entries

代理 handlers

handler 对象可以决定对象的不同行为,常用的有:

  • get - 捕获属性读取
  • set - 捕获属性赋值
  • apply - 捕获函数调用
  • construct - 捕获 new 操作
  • deleteProperty - 捕获 delete 操作
  • etc.

这些方法允许我们自定义对象的基本行为。

get 捕获器

get 方法在属性被访问时触发:

let proxy = new Proxy({}, {
  get(target, prop) {
    return prop in target ? target[prop] : '默认值';
  }  
});

proxy.name // 默认值

这里我们用 get 实现了一个默认值。

set 捕获器

set 方法可以拦截写入:

let validator = {
  set(target, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('年龄必须是整数');
      }
      if (value > 200) {
        throw new RangeError('年龄似乎不对劲啊!');
      }
    }

    target[prop] = value; // 写入被允许
  }
};

let person = new Proxy({}, validator);

person.age = 100; // 工作正常!
person.age = '年龄'; // Uncaught TypeError: 年龄必须是整数

这里我们用 set 实现了对 age 属性的验证。

Reflect API

Reflect API 可以更便捷地操纵目标对象:

let userHandler = {
  get(target, prop, receiver) {
    return Reflect.get(...arguments);
  },
  set(target, prop, val, receiver) {
    return Reflect.set(...arguments);
  }
};

Proxy 与 Reflect 非常配合。

Proxy vs Object.defineProperty

Proxy 可以轻松地拦截整个对象,而 Object.defineProperty 只能单独定义属性。

总结

  • Proxy 用于自定义对象行为
  • handler 对象定义了行为
  • get/set 等方法实现属性拦截
  • Reflect API 可以轻松地操作目标对象
  • Proxy 功能更强大,优于 Object.defineProperty

Proxy 为对象操作提供了极大的可扩展性。

二、eval函数

eval函数可以执行一段JavaScript代码字符串。

eval基本用法

eval接收一个代码字符串作为参数,并执行其中的代码:

let code = 'alert("Hello")';
eval(code); // Hello

代码字符串会被当作正常的代码执行。

eval作用域

eval代码字符串采用当前词法作用域,可以访问外部变量:

let msg = "Hello";

eval('alert(msg)'); // Hello

eval返回值

eval的执行结果是代码的最后一个表达式返回值:

let value = eval('1+2'); 

alert(value); // 3

如果没有返回语句,则返回undefined。

eval局限性

eval不适合执行大段代码,它运行速度比较慢。

eval也无法访问函数作用域外的局部变量。

由于eval可以执行任意代码,因此也存在安全风险,必须非常谨慎使用。

eval实际应用

eval在某些场景下还是有用的,比如:

  • 动态执行JavaScript代码字符串
  • 解析JSON格式的代码字符串
  • 在Safari浏览器中强制刷新页面

但大部分情况还是应该避免使用eval。

总结

  • eval可以执行代码字符串
  • 采用当前词法作用域
  • 返回最后一个表达式的值
  • 存在性能和安全风险
  • 谨慎使用,仅在必要情况下使用

eval是一个高危的函数,在非必要情况下应尽量避免使用。

 

✨ 结语

        综上所述,Proxy和eval为开发者提供了极大的能力,但也需要非常谨慎地使用。合理运用它们可以开拓更多可能,但不当使用也会造成难以预料的结果。

        作为一个负责任的JavaScript开发者,我们应该全面理解语言特性的利弊,进行风险权衡,仅在必要时慎用它们。做到这一点,就可以安全享受这些“双刃剑”带来的好处。

        

  • 44
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱蹦跶的大A阿

你的打赏就是我蹦跶的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值