Jurassic [C# .Net Unity JavaScript運行時] 二.高級用法

從JavaScript調(diào)用單個.NET方法

您可以使用SetGlobalFunctionAPIJavaScript調(diào)用任何.NET 唱凯。例如:

var engine = new Jurassic.ScriptEngine();
engine.SetGlobalFunction("test", new Func<int, int, int>((a, b) => a + b));
Console.WriteLine(engine.Evaluate<int>("test(5, 6)"));

此代碼將向控制臺輸出"11"羡忘。

請注意以下幾點:

  • 必須全部支持委托參數(shù)類型和返回類型。
  • 在提供的委托中引發(fā)的異常無法在JavaScript中捕獲(除非它是JavaScriptException)磕昼。
  • 由于安全限制卷雕,以上示例在Silverlight中不起作用。要解決此問題票从,請將委托傳遞給公共方法漫雕。

從.NET調(diào)用JavaScript函數(shù)

您也可以從.NET調(diào)用JavaScript函數(shù)。

var engine = new Jurassic.ScriptEngine();
engine.Evaluate("function test(a, b) { return a + b }");
Console.WriteLine(engine.CallGlobalFunction<int>("test", 5, 6));

此代碼將"11"輸出到控制臺峰鄙。

將.NET類暴露給JavaScript

Building a property bag class

首先,讓我們創(chuàng)建一個包含幾個屬性的類浸间。

using Jurassic;
using Jurassic.Library;

public class AppInfo : ObjectInstance
{
    public AppInfo(ScriptEngine engine)
        : base(engine)
    {
        // Read-write property (name).
        //類索引器可用于創(chuàng)建讀寫屬性。
        this["name"] = "Test Application";

        // Read-only property (version).
        //`DefineProperty`可用于創(chuàng)建只讀屬性
        this.DefineProperty("version", new PropertyDescriptor(5, PropertyAttributes.Sealed), true);
    }
}

在此示例中,有幾件事要注意:

  • 暴露給JavaScript的類需要繼承Jurassic.Library.ObjectInstance吟榴。
  • ScriptEngine傳遞給基類構(gòu)造函數(shù)意味著該對象將沒有原型魁蒜。因此,常規(guī)功能(hasOwnProperty,toString)將不可用。
  • 類索引器可用于創(chuàng)建讀寫屬性吩翻。
  • DefineProperty可用于創(chuàng)建只讀屬性兜看。

這是有關(guān)如何創(chuàng)建和使用新類的示例:

var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("appInfo", new AppInfo(engine));
Console.WriteLine(engine.Evaluate<string>("appInfo.name + ' ' + appInfo.version"));

Building a class with static functions

下一步是使用靜態(tài)函數(shù)創(chuàng)建一個類,類似于內(nèi)置Math對象的工作方式。例如,假設您要使用log10函數(shù)創(chuàng)建一個新的Math2對象:

using Jurassic;
using Jurassic.Library;

public class Math2 : ObjectInstance
{
    public Math2(ScriptEngine engine)
        : base(engine)
    {
        this.PopulateFunctions();
    }

    [JSFunction(Name = "log10")]
    public static double Log10(double num)
    {
        return Math.Log10(num);
    }
}

請注意以下幾點:

  • PopulateFunctions 在類中搜索[JSFunction]屬性,并為找到的每個屬性創(chuàng)建一個函數(shù)狭瞎。
  • [JSFunction]屬性允許JavaScript函數(shù)名稱與.NET方法名稱不同细移。
  • 參數(shù)類型和返回類型必須在[支持的類型|支持的類型]列表中。
  • 使用[JSProperty]屬性裝飾屬性可將屬性作為訪問者公開給腳本脚作。因此,您可以在CLR中編寫帶有支持者的屬性,或在CLR代碼中設置只讀屬性葫哗。

這是有關(guān)如何創(chuàng)建和使用新類的示例:

var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("math2", new Math2(engine));
Console.WriteLine(engine.Evaluate<double>("math2.log10(1000)"));

Building an instance class

可以實例化的對象(例如內(nèi)置的Number,String,Array和RegExp對象)需要兩個.NET類,一個用于構(gòu)造函數(shù),一個用于實例。例如,讓我們制作一個與.NET Random類類似的JavaScript對象(帶有種子,因為JavaScript不支持該對象):

using Jurassic;
using Jurassic.Library;

public class RandomConstructor : ClrFunction
{
    public RandomConstructor(ScriptEngine engine)
        : base(engine.Function.InstancePrototype, "Random", new RandomInstance(engine.Object.InstancePrototype))
    {
    }

    [JSConstructorFunction]
    public RandomInstance Construct(int seed)
    {
        return new RandomInstance(this.InstancePrototype, seed);
    }
}

public class RandomInstance : ObjectInstance
{
    private Random random;

    public RandomInstance(ObjectInstance prototype)
        : base(prototype)
    {
        this.PopulateFunctions();
        this.random = new Random(0);
    }

    public RandomInstance(ObjectInstance prototype, int seed)
        : base(prototype)
    {
        this.random = new Random(seed);
    }

    [JSFunction(Name = "nextDouble")]
    public double NextDouble()
    {
        return this.random.NextDouble();
    }
}

請注意以下幾點:

  • 您需要兩個類-一個是構(gòu)造函數(shù)(即調(diào)用new的函數(shù)對象),另一個是實例對象球涛。
  • ClrFunction基類需要三個參數(shù):函數(shù)對象的原型,函數(shù)的名稱和使用該函數(shù)創(chuàng)建的任何實例的原型劣针。
  • [JSConstructorFunction]屬性標記使用新運算符時調(diào)用的方法。您也可以使用[JSCallFunction]標記直接調(diào)用該函數(shù)時所調(diào)用的方法亿扁。
  • RandomInstance類具有兩個構(gòu)造函數(shù)-一個用于初始化原型,一個用于初始化所有其他實例捺典。 PopulateFunctions只能從原型對象中調(diào)用。

這是有關(guān)如何創(chuàng)建和使用新類的示例:

var engine = new Jurassic.ScriptEngine();
engine.SetGlobalValue("Random", new RandomConstructor(engine));
Console.WriteLine(engine.Evaluate<double>("var rand = new Random(1000); rand.nextDouble()"));

這將向控制臺輸出"0.151557459100875"(由于我們使用的是種子,因此每次對nextDouble()的第一次調(diào)用都相同从祝。)

這個例子涉及更多,但是它支持所有高級JavaScript概念:

  • rand支持內(nèi)置的Object函數(shù)(hasOwnProperty,toString等)襟己。
  • rand利用原型繼承引谜。在這種情況下,您具有以下原型鏈:random instance (with no properties) -> random prototype (with nextDouble defined) -> object prototype -> null.

從自定義源加載腳本

如果要執(zhí)行的腳本不在文件中,并且不想將其加載到字符串中擎浴,則可以創(chuàng)建一個custom ScriptSource员咽。以下示例顯示了如何完成此操作:

/// <summary>
/// Represents a string containing script code.
/// </summary>
public class StringScriptSource : ScriptSource
{
    private string code;

    /// <summary>
    /// Creates a new StringScriptSource instance.
    /// </summary>
    /// <param name="code"> The script code. </param>
    public StringScriptSource(string code)
    {
        if (code == null)
            throw new ArgumentNullException("code");
        this.code = code;
    }

    /// <summary>
    /// Gets the path of the source file (either a path on the file system or a URL).  This
    /// can be <c>null</c> if no path is available.
    /// </summary>
    public override string Path
    {
        get { return null; }
    }

    /// <summary>
    /// Returns a reader that can be used to read the source code for the script.
    /// </summary>
    /// <returns> A reader that can be used to read the source code for the script, positioned
    /// at the start of the source code. </returns>
    /// <remarks> If this method is called multiple times then each reader must return the
    /// same source code. </remarks>
    public override TextReader GetReader()
    {
        return new StringReader(this.code);
    }
}

線程與并發(fā)

侏羅紀不是線程安全的。但是贮预,它也不使用任何線程局部或全局狀態(tài)贝室。因此,只要確保沒有一次從多個線程調(diào)用任何Jurassic對象仿吞,它將起作用滑频。確保這一點的最簡單方法是使用多個腳本引擎(每個線程一個是理想的)。由于非原始對象綁定到單個腳本引擎唤冈,因此每個腳本引擎都完全相互隔離峡迷。這確實使腳本引擎之間難以共享數(shù)據(jù)。共享數(shù)據(jù)的一種方法是將其序列化為字符串你虹,然后在線程之間傳遞(JSON對象可用于序列化JavaScript對象)绘搞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市傅物,隨后出現(xiàn)的幾起案子看杭,更是在濱河造成了極大的恐慌,老刑警劉巖挟伙,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件楼雹,死亡現(xiàn)場離奇詭異,居然都是意外死亡尖阔,警方通過查閱死者的電腦和手機贮缅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來介却,“玉大人谴供,你說我怎么就攤上這事〕菘溃” “怎么了桂肌?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長永淌。 經(jīng)常有香客問我崎场,道長,這世上最難降的妖魔是什么遂蛀? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任谭跨,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘螃宙。我一直安慰自己蛮瞄,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布谆扎。 她就那樣靜靜地躺著挂捅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堂湖。 梳的紋絲不亂的頭發(fā)上籍凝,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音苗缩,去河邊找鬼。 笑死声诸,一個胖子當著我的面吹牛酱讶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播彼乌,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼泻肯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了慰照?” 一聲冷哼從身側(cè)響起灶挟,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毒租,沒想到半個月后稚铣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡墅垮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年惕医,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片算色。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡抬伺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灾梦,到底是詐尸還是另有隱情峡钓,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布若河,位于F島的核電站能岩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏萧福。R本人自食惡果不足惜捧灰,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毛俏,春花似錦炭庙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至阀溶,卻和暖如春腻脏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背银锻。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工永品, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人击纬。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓鼎姐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親更振。 傳聞我的和親對象是個殘疾皇子炕桨,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容