突破 JS 的作用域规则

发布于 2022-10-18 21:24:45 字数 1688 浏览 101 评论 2

会 JS 的同学都知道 JS 的作用域规则,也就是在函数和块的内部,可以访问外部的变量,比如全局变量。看起来这是一条语言铁律,但是实际上我们可以突破这一点,可以让函数无法访问到外部的变量甚至全局变量。

首先给出一段典型的代码:

var a = 1;
function factory() {
  console.log(a);
}
factory();

毫无疑问,这段代码会输出1,因为factory可以访问到外部的变量。那我们可不可以通过一定的手段让 factory 无法访问到a呢,答案是肯定的,只是需要一定的技巧。

首先,我们需要明确一点,JS函数中变量的引用是在函数定义点决定的,也就是说,只要在定义函数的地方访问不到外部的变量,函数也就访问不到了。不过这听起来还是没啥用。

其次,我们知道,在JS中有个被批的很惨的关键字——with,而且还被严格模式给驱逐出境了。with 被批的原因,一在于他可以改变作用域规则,让局部变量的优先级甚至更低;二则是因为浏览器厂商痛恨他,因为有他不利于性能提升。由此可以看出,我们可以利用 with 来改变一下作用域,比如说想要屏蔽到外部的变量 a,就可以给个对象里面含有同名变量名。结合第一点,我们可以写出下面的代码:

var a = 1;
var shadow = {
  a: 2,
};
function factory() {
  console.log(a);
}
function sandbox(factory) {
  with (shadow) {
    return eval('((' + factory.toString() + ')())');
  }
}
sandbox(factory);

上述代码会输出 2,不过你肯定想说,这有什么卵用,我只能指定某个变量,然后拿个假的值来保护原值。这是没什么卵用,但是如果配合上 ES6 的一个新特性——Proxy 就很有用了。

ES6 的 Proxy 应该是大家很少接触的一个特性,这个特性使得JS可以元编程了。结合 Proxy 可以把我们的 sanbox 函数改变得很有用处:

var a = 1;
function sandbox(factory) {
  var shadow = new Proxy({
    window: {},
    factory,
    eval,
    console,
  }, {
    get(target, key, reveiver) {
      return Reflect.get(target, key, reveiver);
    },
    has() {
      return true;
    }
  });
  with (shadow) {
    return eval('((' + factory.toString() + ')())');
  }
}
function factory() {
  console.log(a);
  console.log(this.a);
  !function () {
    var b = 3;
    console.log(b);
  }();
  console.log(b);
}
sandbox(factory);

执行这个函数可以发现,外部变量甚至全局变量 a 无法被访问到了。而且由于函数的缘故,内部的作用域并没有被打乱,也就是说我们实际上获得了一个真沙盒!通过使用 sandbox,我们完完全全突破了 JS 的作用域规则。对外部变量的访问受到我们控制了,只能访问到我们所设置的 白名单 里的对象,想怎么玩就怎么玩。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

莫多说 2022-05-02 13:14:15

@slashhuang Proxy更重要啦

金兰素衣 2022-05-01 13:09:04

说到底还是with

~没有更多了~

关于作者

迷你仙

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文