Is array indexing expensive?

In the snippet below backbone , this line

(ev = events[i]).callback.call(ev.ctx);

      

it is not clear. I would like to assume what is being ev = events[i]

interpreted before ev.ctx

, as the variable does not seem to have any other purpose other than to decrease array indexing.

Assuming this is correct, is it done because array indexing is costly? I know that in embedded engineering arrays, indexing is expensive when you are working with limited resources. But I thought it wasn't that dangerous in JavaScript.

Trunk snippet

triggerEvents = function(events, args) {
    var ev, 
        i = -1, 
        l = events.length;
    switch (args.length) {
        case 0: 
            while (++i < l) {
                (ev = events[i]).callback.call(ev.ctx);
            }
            return;
        case 1: 
            while (++i < l) {
               (ev = events[i]).callback.call(ev.ctx, args[0]);
            }
            return;
        case 2: 
            while (++i < l) { 
                (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
            }
            return;
        case 3: 
            while (++i < l) { 
                (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
            }
            return;
        default: 
            while (++i < l) {
                (ev = events[i]).callback.apply(ev.ctx, args);
            }
    }
};

      

+3


source to share


1 answer


OK, using the treehugger.js tree to create an AST approach backbone.js with this simplified bit of code:

var ev, i = -1, l = 3;
while (++i < l) { 
  (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
}

      

Produces this AST:

[
  VarDecls(
      [
        VarDecl("ev"),
        VarDeclInit(
            "i",
            PrefixOp(
                "-",
                Num("1")
            )
        ),
        VarDeclInit(
            "l",
            Num("3")
        )
      ]
  ),
  While(
      Op(
          "<",
          PrefixOp(
              "++",
              Var("i")
          ),
          Var("l")
      ),
      Block(
          [
            Call(
                PropAccess(
                    PropAccess(
                        Assign(
                            Var("ev"),
                            Index(
                                Var("events"),
                                Var("i")
                            )
                        ),
                        "callback"
                    ),
                    "call"
                ),
                [
                  PropAccess(
                      Var("ev"),
                      "ctx"
                  ),
                  Index(
                      Var("args"),
                      Num("0")
                  ),
                  Index(
                      Var("args"),
                      Num("1")
                  ),
                  Index(
                      Var("args"),
                      Num("2")
                  )
                ]
            )
          ]
      )
  )
]

      

Whereas the implied "cleaner" approach is:



var ev, i = -1, l = 3;
while (++i < l) {
  ev = events[i];
  ev.callback.call(ev.ctx, args[0], args[1], args[2]);
}

      

Produces this AST:

[
  VarDecls(
      [
        VarDecl("ev"),
        VarDeclInit(
            "i",
            PrefixOp(
                "-",
                Num("1")
            )
        ),
        VarDeclInit(
            "l",
            Num("3")
        )
      ]
  ),
  While(
      Op(
          "<",
          PrefixOp(
              "++",
              Var("i")
          ),
          Var("l")
      ),
      Block(
          [
            Assign(
                Var("ev"),
                Index(
                    Var("events"),
                    Var("i")
                )
            ),
            Call(
                PropAccess(
                    PropAccess(
                        Var("ev"),
                        "callback"
                    ),
                    "call"
                ),
                [
                  PropAccess(
                      Var("ev"),
                      "ctx"
                  ),
                  Index(
                      Var("args"),
                      Num("0")
                  ),
                  Index(
                      Var("args"),
                      Num("1")
                  ),
                  Index(
                      Var("args"),
                      Num("2")
                  )
                ]
            )
          ]
      )
  )
]

      

The only difference between the two is that it Assign()

takes place on the inside PropAccess()

, whereas in the "pure" approach it is on the outside. They have the same number of steps. You could avoid it Assign

all together and swap it with the second one Index

. I'm afraid I don't know enough about JS internals to know if it's faster. I assume it is platform dependent.

+1


source







All Articles