0 Comments

I am not sure if this is of any use or not.  While playing around with trying to find a more elegant syntax for my LINQ-like querying code, I accidentally bumped into this topic.

Say... I want to be able to write something like:

var peoples = [ ... ]; 

function from() {
    // do something with the arguments passed here...
} 

from (a, in, peoples)

This will never work since "a" is undefined and "in" is a JavaScript keyword.  What I wanted to do is cache the arguments that were passed to the "from" function into a local buffer so I can do something with it later inside the function.

There are several problems here that are related to JavaScript global object.

Problem 1: 'a' is undefined will be thrown when the "from" function is called.  Now, how can we possibly remedy this?  Well, we can declare "a" as a global variable and assigned something to it (does not matter what), but that's kind of weird.  Is it possible to inject "a" into global on the fly?  Well, yes, somewhat.  You can use try and catch block and detect the "'a" is undefined" error that was thrown and have the catch block inject the missing variable as a global variable.

Example:

try {
    from(a, inside, people);
} catch(e) {
    var m = e.message.match(/^'(.+)' is undefined$/);
    if  (m) {
        this[m[1]] = {};
    }
}

Well, this will inject variable 'a' into the global object (this). If you need a proof for this, just output 'a' somewhere after the above code. (i.e. WScript.Echo(a)). Unfortunately, this route does not take me to where I want since once the error is caught the function will never complete the call anyway.  Hmm...

Problem 2: Ignoring the 'in' Syntax error, the second thing that bugs me is how to get the function parameter variable name (in this example, I want to be able to get the name of the people object (which is "people").  So, how can you reflect over JavaScript global object to get this value?

After a little experimentation, I finally found the answer.  Take a look at the code below:

function GetGlobalObjectName(aGlobalMember) {
    var global = this; //when the function is called as a function, "this" will point to global object
    for (var object in global) {
        if (global[object] === aGlobalMember) {
           return object;
         }
    }
    return null;
}

now I can modify my "from" function as follow:

function from() {
    for (var x = 0, a = arguments, k = a.length; x < k; x++) {
        var v = a[x];
        if (typeof(v) === "object") {
           WScript.Echo(GetGlobalObjectName(v);
        }
    }
}

Now I can pass any object to my "from" function and if it detects that the argument type is "object" it will get the name of that object as defined in the global.  Afterward I can use that name string to do whatever I want.  In this example, perhaps use it to construct dynamic JavaScript statement from all the arguments being passed and do an eval() on it.

Hmm... with all these problems, I doubt I can get the syntax structure to anywhere close to C# LINQ... alternatively, mixing string into the function call might work, but that's just messy Sad smile.

from("a", "in", people)

Hmm... frankly I like the current syntax that I have, minus the orderby array part that is still in string.

from(people)
    .where(function(n) { n.Age > 19 && n.Age < 31) })
    .select(function(n) { return { FullName : n.FirstName + " " + n.LastName }; });

To me that seems a little bit a elegant than mixing string substitutions into the function argument. 

I don't anticipate that I'll get anywhere far with this in regard of finding a more elegant way to write my query syntax, but this is sure is one fun trip into JavaScript internals.  I learnt something new today Smile .  It's all good.