javascript with语句

小鱼儿 2022-12-23 09:55 275阅读 0赞

不要用with

一、with 语句的使用

with 的初衷为了避免冗余的对象调用

  1. foo.bar.data.x = 1;
  2. foo.bar.data.y = 2;
  3. foo.bar.data.z = 3;
  4. with (foo.bar.data){ // 改变块内作用域
  5. x = 1;
  6. y = 2;
  7. z = 3;
  8. }

但其实用变量替换的方法也可以轻松解决

  1. var o = foo.bar.data;
  2. o.x = 1;
  3. o.y = 2;
  4. o.z = 3;

所以with似乎本来就没有存在的必要。到了如今,会去用with的人才真的是罕见。到了strict模式里,使用with会直接报错:

  1. (function (){
  2. 'use strict';
  3. var o = { };
  4. with(o){
  5. x = 1;
  6. }
  7. })()
  8. // VM132:4 Uncaught SyntaxError: Strict mode code may not include a with statement

二、with 语法中的 this 指向

with 中的 this 与with外部的this指向相同

  1. // 全局函数
  2. function foo(_obj){
  3. with(_obj){
  4. console.log(this === globalThis, this.x);
  5. }
  6. }
  7. foo({ x: 1}); // true undefined
  8. // 构造函数
  9. function Bar(){
  10. this.x = 'bar';
  11. this.withFunc = function(_obj){
  12. with(_obj){
  13. console.log(this instanceof Bar, this.x)
  14. }
  15. }
  16. }
  17. let bar = new Bar();
  18. bar.withFunc({ x: 1}); // true "bar"

三、为什么不要使用 with 语句

  1. 性能问题
  2. 不可预测
  3. 优化困难
  4. 严格模式不支持使用with
  1. 性能问题

    做个简单的测试:对对象中的某个属性连续赋值100万次,观察使用with与不使用with的时间开销

    1. // chrome v86.0.4240.111
    2. var o = { x: 1 };
    3. function useWith(){
    4. with(o){
    5. for(let i=0; i<100*10000; i++){
    6. x = i;
    7. }
    8. }
    9. }
    10. function noWith(){
    11. for(let i=0; i<100*10000; i++){
    12. o.x = i;
    13. }
    14. }
    15. console.time('useWith');
    16. useWith();
    17. console.timeEnd('useWith');
    18. // useWith: 168.0419921875 ms
    19. console.time('noWith');
    20. noWith();
    21. console.timeEnd('noWith');
    22. // noWith: 2.031982421875 ms
  2. 不可预测

    使用with语句后代码产生的不可预测性是废弃with的根本原因。with强行割裂了词法作用域,将对象临时性地插入到了作用域链中。这使得出现了难以捉摸的代码

    • 栗子1

      function printInput(_input){

      1. /** * 函数的本意是将输入的对象打印出来 */
      2. with(_input){
      3. console.log(_input);
      4. }

      }
      printInput(“正常”) // “正常”
      printInput({ output: “正常”}) // { output: “正常” }
      printInput({ _input: “不正常”}) // “不正常”

    但当传入的参数是带有同名 _input 属性的 _input 对象时,with 强行访问了 _input._input

    • 栗子2

      function func(){

      1. with({ }){
      2. x = '插入with引入的新对象'
      3. }
      4. console.log(x)

      }
      func(); // “插入with引入的新对象”

    with 中引入的新变量实际上是被添加到外层的 function 上的

  3. 代码难以优化

    由于无法进行预测,不同的调用,或者即使相同的调用也会因为运行时的变化而出现偏差,代码含义只能在运行时才能被确定,从而使得代码无法在编译阶段被优化

    优化指两方面

    • 解析和运行变得缓慢,指的就是之前已经谈到的性能。
    • 对于代码优化和压缩工具来说,无法确定是变量还是属性(例如刚刚的 _input),也就不能进行重命名(因为属性无法被重命名)。

发表评论

表情:
评论列表 (有 0 条评论,275人围观)

还没有评论,来说两句吧...

相关阅读

    相关 with语句

    一 语法 with语句被用于在访问一个对象的属性或方法时避免重复使用指定对象引用。 语法: with(object) \{ stataments \} objec