7.6 CLR/Javascript(SpiderMonkey)

The Limax provides a clrjs project, which combines C# with Javascript, supports the interoperability between the C# and Javascript, to implement the JavaScriptHandle in the framework of the C# script model. This charpter introduces the functions provided by the clrjs.


  • 7.6.1 Programming interface

    • limax.script.Js

      When creating this object, a javascript virtual machine is also created, and use this object to interact with the javascript virtual machine.

      Constructor:

      • Js(uint maxbytes)

        maxbytes determines the maximum memory byte numbers used by the javascript virtual machine.

      • Js()

        Call the previous construct method, and the default maxbytes = 8388608.

      Method:

      • object eval(string code)

        Execute the code chunk expressed by the code and return the result.

      • object eval(string codepattern, params object[] parameters)

        Use the variable-length parameter list to fill the placeholder <0>, <1>...... of the codepattern, then execute chunk and return the result. The placeholder is associated with the context variable created by the placeholder, which should be used as the variable name in the template code, but not be enclosed in quation marks, or the replacement result will be a context variable name string.

        The returned result could be any type, and in particular, it is possible to return JsObject, JsArray, JsFunction type.

      • Js name(string chunkname)

        Name the following eval. If the run-time error occurs in the named eval code, the name will be prefixed in the error message for debugging. This name uses UTF8 encoding internally and non-ASCII characters is not recommended.

      Exception:

      • ScriptException

        Refer to the exception specification section.

      • ThreadContextException

        Refer to the thread safety section.


    • limax.script.JsObject

      The javascript object which could not convert to C# type. Which can not be converted is introduced in the type mapping section. This object implements the System.Collections.IDictionary interface in order to manipulate the property of the javascript object in the C# code.


    • limax.script.JsArray

      Derived from the JsObject, corresponding to the Array of the javascript, implement the IList interface to control the Array object of the javascript in the C# code.


    • limax.script.JsFunction

      A variable-length argument delegation, encapsulates the object derived from JsObject and associated with Function of the javascript virtual machine. Calling on this delegation is equivalent to calling the corresponding Function of the virtual machine.

    Attention, the object created through limax.script.js, is named as the javascript operating object in the following content to distinguish from the JsObject.


  • 7.6.2 Interoperability example between C# and Javascript

    First, define Js js = new Js();

    • C# controls Javascript

      C# controls Javascript through calling eval method to implement.

      • hello world


        js.eval("print('hello world')");
        js.eval("print(<0>)", "hello world");
        Console.WriteLine(js.eval("'hello world'"));
        Console.WriteLine(js.eval("<0>", "hello world"));
        

        Output:

        hello world

        hello world

        hello world

        hello world

        The first line of code need not be interpreted, the second line of code explains the usage of the placeholder, the third line of code explains that the eval could return the value held in the javascript virtual machine, and the forth line of code explains that an value could be repeatedly transferred between C# and Javascript.


      • null and underfined


        Console.WriteLine(js.eval("null") == null);
        js.eval("print(<0> === null)", null);
        Console.WriteLine(js.eval("undefined") == DBNull.Value);
        js.eval("print(<0> === undefined)", DBNull.Value);
        

        Output:

        True

        true

        True

        true

        This proves that javascript's null is completely equivalent to the null of C#, and javascipt's underfined is completely equivalent to the DBNull.Value of C#.


      • Unicode


        js.eval("var 好好学习=<0>", "天天向上");
        js.eval("print(好好学习)");
        Console.WriteLine(js.eval("好好学习"));
        

        Output:

        天天向上

        天天向上

        Seen from here that the Unicode could be correctly supported.


      • Execute code and return JsObject


        JsObject obj = (JsObject)js.eval("var t = { a: 'A', b :'B' };  t ");
        foreach (DictionaryEntry e in obj)	Console.WriteLine(e.Key + ":" + e.Value);
        

        Output:

        a:A

        b:B


        Continue execute:


        obj.Remove("a");
        obj.Add("c", "C");
        js.eval("print (t.a)");
        js.eval("print (t.c)");
        

        Output:

        undefined

        C

        Seen from here that the modification in the C# affects the property of the javascript object.


        Continue execute:


        js.eval("t.d = 100");
        foreach (DictionaryEntry e in obj)	Console.WriteLine(e.Key + ":" + e.Value);
        

        Output:

        b:B

        c:C

        d:100

        Seen from here that modification of the object’s property in the javascript internal is alos reflected to the C#.


      • Execute code and return JsArray


        JsArray a = (JsArray)js.eval("var o=[1,2]; o");
        foreach (var v in a) Console.WriteLine(v);
        

        Output:

        1

        2


        Continue execute:


        a.Add(3);
        js.eval("print(o)");
        

        Output:

        1,2,3

        Seen from here that the modification in the C# affects the content of the javascript's array.


        Continue execute:


        js.eval("o.shift()");
        foreach (var v in a) Console.WriteLine(v);
        

        Output:

        2

        3

        Seen from here that the operate of the arrary in the javascript internal is also reflected to the C#.


        Continue execute:


        Console.WriteLine(a.Count);
        a[5] = 100;
        js.eval("print(o)");
        

        Output:

        2

        2,3,,,,100

        Seen from here that the operate on the JsArray array complies with the access specification of the javascript array, but does not comply with the access specification of the C# array and does not throw System.ArgumentOutOfRangeException exception.


        Continue execute:


        a.Remove(DBNull.Value);
        js.eval("print(o)");
        

        Output:

        2,3,100

        Specifically here again, the DBNull.Value of C# equals to the undefined of javascript, and the non-existed element is expressed as undefined in the javascript array.


        Continue execute:


        JsObject o = a;
        o['c'] = 1000;
        Console.WriteLine(a.Count);
        Console.WriteLine(o.Count);
        

        Output:

        3

        4

        It should be particularly noted that for javascript, Array is also an Object, and the property could be manipulated on the Array. Reference to the same object through JsObject or JsArray lead to the different behaviour. In non-special case, to avoid the confusion, the array only using JsArray to manipulate is more understandable.


      • Execute code and return JsFunction


        JsFunction f = (JsFunction)js.eval("var func = function(a,b){ return a + b;}; func");
        Console.WriteLine(f(10, 20));
        

        Output:

        30

        Seen from here that returning a javascript function is esay to use in C#.


      • Javascript object operation


        JsObject obj1 = (JsObject)js.eval("function CLS(n){this.value = n; this.dump = function(){print(this.value);}}; new CLS(200)");
        ((JsFunction)obj1["dump"])();
        

        Output:

        200

        Seen from here that the javascipt code uses CLS function to create an object which is held by the obj1, the obj1 queries the dump property with the function as value to call and outputs the created object's value 200. The C#'s syntax could not be writted as obj1.dump and has to use indexed way to access.


        Continue execute:


        JsFunction cls = (JsFunction)js.eval("CLS");
        JsObject obj2 = JsObject.create(cls, 400);
        ((JsFunction)obj2["dump"])();
        

        Output:

        400

        The first line returns the previous created CLS function, the second line uses the static method create of the JsObject to create object obj2. Compared with the previous code, the JsObject.create equals to the new in the javascript.


Prev Next