C # 'ref' keyword or workaround in Javascript

If I have an object:

var Edge = function() {
  this.a = 0;
  this.b = 0;
  this.prevEdge = null;
  this.nextEdge = null;
  // +20 other members
}

      

and the function:

function ProcessEdge(e)
{
  // some processing and then
  e = e.nextEdge;
  // some processing and then return something
}

      

which is called from another function like this:

var e = new Edge();
// some processing and then
var res = ProcessEdge(e);
// e should be now the same object as e.nextEdge
// but it is not, e is still e

      

e

should be now e.nextEdge

, but it's still e

because the function e = e.nextEdge;

in is ProcessEdge()

breaking the link.

First thought was to achieve parity by assigning each member one at a time in the function ProcessEdge()

using something like e.a = e.nextEdge.a; e.b = e.nextEdge.b; e.prevEdge = e.nextEdge.prevEdge; e.nextEdge = e.nextEdge.nextEdge;

, but the link is still broken. When I do this, I also have to compare the member by member, and the spaghetti code and its slowness appears.

In C # and similar languages, referencing can be achieved simply by using a keyword ref

before the variable name and the link is retained, and the speed and simplicity and speed will be as expected.

Ok, now the method that works (this is the one I have used so far):

function ProcessEdge(e)
{
  // some processing and then
  e.Value = e.Value.nextEdge; // instead of e = e.nextEdge;
  // some processing and then return something
}

// And the calling part:
var e = new Edge();
// some processing and then
var res = (function ()
{
  e = { Value: e };
  var $res = ProcessEdge(e);
  e = e.Value;
  return $res;
})
.call(this);

      

This method works great, but the problem is in the built-in function that (AFAIK) is created every time the string is executed var res = (function() {}...

. This var res...

is an inner loop that is called very many times, in some cases 100,000 to 500,000 times per second if there is a lot of data.

So, is there a faster way to save the link?


EDIT:

As per the comments below, I did speed tests: http://jsperf.com/closure-vs-compund http://jsperf.com/closure-vs-compund/2

As a result, it was pointed out that the above closing method is very slow as I expected. I found that the fastest way is to drop the feature entirely ProcessEdge()

and enable it instead. The closing method rate was 26.63% of the fastest. So the inline method was 3.7 times faster than the close method. The built-in method looks like this:

function main10(a)
{
  var res=0, res2, e, b;
  for (var i=0;i<10000;i++)
  {
    e = new Edge();
    b = new Edge();
    b.a = i*a;

    e.nextEdge = b;

    // ProcessEdge() as inline version:
    e = e.nextEdge;
    res += e.a-10;

    if (e!=b) res+=1000;
  }
  return res;
}

      

But usually we need to use functions (and give the interpreter a chance for automatic insertion, if ever). The next fastest was to use a "global" link. The speed was 98.45% of the fastest.

global_val

is a holder for the return value (it is used because a function in Javascript cannot return more than one value). This means that we have outer loops and just one step up in the hierachy area a reference object global_val

that is created at the same time as all other functions are created. The function ProcessEdge()

overwrites the value global_val

, but because it e.nextEdge

is an object, it only means a light and fast rewrite of the reference (no new copy). e = e.nextEdge

causes the link to break, but it doesn't matter because the link is now in global_val

and we're safe.

The function main11()

we call ProcessEdge () as follows: res += ProcessEdge11(e)

and save the link from global_val to e as follows: e = global_val

.

var global_val = {};
function ProcessEdge11(e)
{
  e = e.nextEdge;
  global_val = e;
  return e.a-10;
}

function main11(a)
{
  var res=0, res2, e, b;
  for (var i=0;i<10000;i++)
  {
    e = new Edge();
    b = new Edge();
    b.a = i*a;
    e.nextEdge = b;

    // some processing and then
    res += ProcessEdge11(e);
    e = global_val;
    if (e!=b) res+=1000;  
  }  
  return res;
}

      

Then there is another method that should be mentioned: using function inside function

. It is slower (84.42% of the fastest) than the above two methods, but quite simple. It basically relies on the same fact as the one it uses global_val

: the function has access to its parent variable (object) scopes in a way that doesn't break the link, since no local vars are instantiated, and the function processes variables one scope up. The essential note is that the variable is not "passed" and that there are no local assignments that break the reference.

function main8(a)
{
  var pseudo_global_ret = 0;

  var res=0, res2, e, b;
  for (var i=0;i<10000;i++)
  {
    e = new Edge();
    b = new Edge();
    b.a = i*a;

     e.nextEdge = b;

    _ProcessEdge();
    res += pseudo_global_ret;
    if (e!=b) res+=1000;
  }
  return res;

  function _ProcessEdge()
  {
    e = e.nextEdge;
    pseudo_global_ret = e.a-10; // instead of return e.a-10
  }
}

      

And one more note: the Javascript version of the swap function is slightly different from the C # version where the keyword resides ref

. In C # we could call it swap(ref a, ref b)

, but in Javascript it is not possible. Way:

function swap()
{
  var tmp=a;
  a=b;
  b=tmp;
}
var a={x:0}
var b={x:1}
swap();

      

If you try in any way swap(a,b)

, this link breaks. Of course, it is necessary for the closure inside the closure to prevent global pollution.

If anyone finds a faster way to link to save, please answer this question.

+3


source to share





All Articles