青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

牽著老婆滿街逛

嚴(yán)以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

基于 C 語言的 JavaScript 引擎探索

轉(zhuǎn)載自:http://www.ibm.com/developerworks/cn/linux/l-cn-spidermonkey/index.html

基礎(chǔ)知識

SpiderMonkey 簡介

和其他的 JavaScript 引擎一樣,SpiderMonkey 不直接提供像 DOM 這樣的對象,而是提供解析,執(zhí)行 JavaSccript 代碼,垃圾回收等機制。SpidlerMonkey 是一個在 Mozilla 之下的開源項目,要使用 SpiderMonkey,需要下載其源碼,然后編譯為靜態(tài) / 動態(tài)庫使用。

要在自己的應(yīng)用程序中使用 SpiderMonkey,首先需要了解以下三個核心概念:

運行時環(huán)境運行時環(huán)境是所有 JavaScript 變量,對象,腳本以及代碼的上下文所存在的空間。每一個上下文對象,以及所有的對象均存在于此。一般應(yīng)用僅需要一個運行時即可。

上下文上下文即腳本執(zhí)行的環(huán)境,在 SpiderMonkey 中,上下文可以編譯執(zhí)行腳本,可以存取對象的屬性,調(diào)用 JavaScript 的函數(shù),轉(zhuǎn)換類型,創(chuàng)建 / 維護對象等。幾乎所有的 SpiderMonkey 函數(shù)都需要上下文作為其第一個參數(shù) (JSContext *)。

上下文與線程密不可分,一般來講,單線程應(yīng)用可以使用一個上下文來完成所有的操作,每一個上下文每次只能完成一個操作,所有在多線程應(yīng)用中,同一時刻只能有一個線程來使用上下文對象。一般而言,多線程應(yīng)用中,每個線程對應(yīng)一個上下文。

全局對象全局對象包含 JavaScript 代碼所用到的所有類,函數(shù),變量。在 DOM 操作中,我們使用的:

 alter("something"); 

事實上使用的是全局變量 window 的一個屬性 alter( 這個屬性正好是一個函數(shù) ),事實上上邊的語句在執(zhí)行時會別解釋為:

 window.alter("something"); 

三者的關(guān)系如下圖所示:


圖 1. 引擎內(nèi)部結(jié)構(gòu)依賴關(guān)系
圖 1. 引擎內(nèi)部結(jié)構(gòu)依賴關(guān)系 

安裝 SpiderMonkey

首先從 SpiderMonkey 的代碼庫中下載其源碼包 js-1.7.0.tar.gz 本文在 Linux 環(huán)境下編譯,SpiderMonkey 的編譯安裝很容易:

 # 解壓縮
 tar xvzf js-1.7.0.tar.gz 

 # 切換至源碼目錄
 cd js-1.7.0/src 

 # 編譯
 make -f Makefile.ref 

編譯完成之后,會生成一個新的目錄,這個目錄的名稱依賴于平臺,比如在 Linux 下,名稱為:Linux_All_DBG.OBJ,其中包含靜態(tài)鏈接庫 libjs.a 和動態(tài)鏈接庫 libjs.so 等。本文后續(xù)的編譯環(huán)境就需要依賴于我們此處編譯出來的庫文件。應(yīng)該注意的是,此處編譯出來的庫文件包含對調(diào)試的支持,體積較大,在應(yīng)用程序發(fā)布時,可以去掉這些調(diào)試支持,使用下列重新編譯庫:

 # 創(chuàng)建非 debug 模式的庫
 make BUILD_OPT=1 -f Makefile.ref 

Windows 及其他平臺的編譯此處不再贅述,讀者可以自行參考 SpiderMonkey 的官方文檔。

JavaScript 對象與 C 對象間的轉(zhuǎn)換關(guān)系

JavaScript 是一門弱類型的語言,變量的值的類型在運行時才確定,而且可以在運行時被修改為其他類型的變量;而 C 語言,是一門靜態(tài)類型的語言,變量類型在編譯時就已經(jīng)確定。因此,這兩者之間變量的互訪就有了一定的難度,SpiderMonkey 提供了一個通用的數(shù)據(jù)類型 jsval 來完成兩者之間的交互。

事實上,在 C 代碼中定義的 jsval 類型的變量可以是 JavaScript 中的字符串,數(shù)字,對象,布爾值,以及 null 或者 undefined?;谶@個類型,SpiderMonkey 提供了大量的類型判斷及類型轉(zhuǎn)換的宏和函數(shù)。可以參看下表:


表 1. JavaScript 對象與 C 對象轉(zhuǎn)換表
JavaScript 類型 jsval 類型判斷 jsval 常量 jsval 轉(zhuǎn)化
null JSVAL_IS_NULL(v) JSVAL_NULL
Undefined JSVAL_IS_VOID(v) JSVAL_VOID
Boolean JSVAL_IS_BOOLEAN(v) JSVAL_TRUE, 
JSVAL_FALSE, 
BOOLEAN_TO_JSVAL(b)
JSVAL_TO_BOOLEAN(v)
number JSVAL_IS_NUMBER(v), 
JSVAL_IS_INT(v), 
JSVAL_IS_DOUBLE(v)
INT_TO_JSVAL(i), 
DOUBLE_TO_JSVAL(d)
JSVAL_TO_INT(v), 
JSVAL_TO_DOUBLE(v)
string JSVAL_IS_STRING(v) STRING_TO_JSVAL(s) JSVAL_TO_STRING(v), 
JS_GetStringChars(s), 
JS_GetStringLength(s)
object JSVAL_IS_OBJECT(v) 
&& JSVAL_IS_NULL(v)
OBJECT_TO_JSVAL(o) JSVAL_TO_OBJECT(v)

應(yīng)該注意的是,jsval 有一定的缺陷:

  • jsval 并非完全的類型安全,在進行類型轉(zhuǎn)換之前,你需要明確被轉(zhuǎn)換的對象的真正類型,比如一個變量的值為 number 類型,而對其做向字符串的轉(zhuǎn)化,則可能引起程序崩潰。解決方法是,在轉(zhuǎn)換之前,先做判斷。
  • jsval 是 SpiderMonkey 垃圾回收機制的主要目標(biāo),如果 jsval 引用一個 JavaScript 對象,但是垃圾收集器無法得知這一點,一旦該對象被釋放,jsval 就會引用到一個懸空指針。這樣很容易使得程序崩潰。解決方法是,在引用了 JavaScript 對象之后,需要顯式的告知垃圾收集器,不引用時,再次通知垃圾收集器。

簡單示例

基本代碼模板

基本流程

使用 SpiderMonkey,一般來講會使用以下流程:

  • 創(chuàng)建運行時環(huán)境
  • 創(chuàng)建一個 / 多個上下文對象
  • 初始化全局對象
  • 執(zhí)行腳本,處理結(jié)果
  • 釋放引擎資源

在下一小節(jié)詳細說明每個流程

代碼模板

使用 SpiderMonkey,有部分代碼是幾乎每個應(yīng)用程序都會使用的,比如錯誤報告,初始化運行時環(huán)境,上下文,全局變量,實例化全局變量等操作。這里是一個典型的模板:


清單 1. 必須包含的頭文件
				
#include "jsapi.h"

引入 jsapi.h,聲明引擎中的所用到的記號,結(jié)構(gòu)體,函數(shù)簽名等,這是使用 SpiderMonkey 所需的唯一一個接口文件 ( 當(dāng)然,jsapi.h 中不可能定義所有的接口,這些文件在 jsapi.h 頭部引入 jsapi.h,如果對 C 語言的接口,頭文件引入方式不熟悉的讀者,請參閱相關(guān)資料 )。


清單 2. 全局變量聲明
				
 /* 全局變量的類聲明 */ 
static JSClass global_class = { 
    "global", 
    JSCLASS_GLOBAL_FLAGS, 
    JS_PropertyStub, 
    JS_PropertyStub, 
    JS_PropertyStub, 
    JS_PropertyStub, 
    JS_EnumerateStub, 
    JS_ResolveStub, 
    JS_ConvertStub, 
    JS_FinalizeStub, 
    JSCLASS_NO_OPTIONAL_MEMBERS 
 }; 

JSClass 是一個較為重要的數(shù)據(jù)結(jié)構(gòu),定義了 JavaScript 對象的基本結(jié)構(gòu) ---“類”,這個類可以通過 SpiderMonkey 引擎來實例化為對象。JS_PropertyStub 是 JS_PropertyOp 類型的變量,這里的 JS_PropertyStub 是為了提供一個默認(rèn)值。JS_PropertyOp 可以用做對象的 setter/getter 等的,這些內(nèi)容我們將在后邊的章節(jié)詳細討論。


清單 3. 錯誤處理函數(shù)
				
 /* 錯誤處理函數(shù),用于回調(diào),打印詳細信息 */ 
 void report_error(JSContext *cx,  const char *message, JSErrorReport *report){ 
    fprintf(stderr, "%s:%u:%s\n", 
    		 report->filename ? report->filename : "<no filename>", 
            (unsigned int) report->lineno, 
            message); 
 } 

定義好這些結(jié)構(gòu)之后,我們需要實例化這些結(jié)構(gòu),使之成為內(nèi)存對象,流程如下:


清單 4. 主流程
				
				int main(int argc, char *argv[]){ 
    JSRuntime *runtime; 
    JSContext *context; 
    JSObject *global; 

	 // 創(chuàng)建新的運行時 8M 
    runtime = JS_NewRuntime(8L * 1024L * 1024L); 
    if (runtime == NULL){ 
        return -1; 
    } 

	 // 創(chuàng)建新的上下文
    context = JS_NewContext(runtime, 8*1024); 
    if (context == NULL){ 
        return -1; 
    } 

	 // 
    JS_SetOptions(context, JSOPTION_VAROBJFIX); 
    // 設(shè)置錯誤回調(diào)函數(shù) , report_error 函數(shù)定義如上
	 JS_SetErrorReporter(context, report_error); 

	 // 創(chuàng)建一個新的 JavaScript 對象
    global = JS_NewObject(context, &global_class, NULL, NULL); 
    if (global == NULL){ 
        return -1; 
    } 

	 // 實例化 global, 加入對象,數(shù)組等支持
    if (!JS_InitStandardClasses(context, global)){ 
        return -1; 
    } 

	 // 
	 // 使用 global, context 等來完成其他操作,用戶定制代碼由此開始
	 // 

	 // 釋放上下文對象
    JS_DestroyContext(context); 
	 // 釋放運行時環(huán)境
    JS_DestroyRuntime(runtime); 
	 // 停止 JS 虛擬機
    JS_ShutDown(); 

	 return 0; 
 } 

用戶自己的代碼從上邊代碼中部注釋部分開始,用戶代碼可以使用此處的 context 對象及預(yù)設(shè)過一定屬性,方法的 global 對象。

執(zhí)行 JavaScript 代碼

執(zhí)行 JavaScript 代碼片段

執(zhí)行 JS 最簡單的方式,是將腳本作為字符串交給引擎來解釋執(zhí)行,執(zhí)行完成之后釋放臨時的腳本對象等。SpiderMonkey 提供一個 JS_EvaluateScript 函數(shù),原型如下:


清單 5. 執(zhí)行 JS 代碼的函數(shù)原型
				
 JSBool JS_EvaluateScript(JSContext *cx, JSObject *obj, 
    const char *src, uintN length, const
				char *filename, 
    uintN lineno, jsval *rval); 

使用這個函數(shù),需要提供上下文,全局變量,字符串形式的腳本,腳本長度及返回值指針,腳本名和行號參數(shù)可以填空值 ( 分別為 NULL 和 0)。如果函數(shù)返回 JS_TRUE,表示執(zhí)行成功,執(zhí)行結(jié)果存放在 rval 參數(shù)中,否則執(zhí)行失敗,rval 中的值為 undefined。我們可以具體來看一個例子:


清單 6. 執(zhí)行 JS 代碼片段
				
				char *script = "(function(a, b){return a * b;})(15, 6);"; 
	 jsval rval; 

	 status = JS_EvaluateScript(context, global, script, strlen(script)\ 
	        , NULL, 0, &rval); 

	 if (status == JS_TRUE){ 
	    jsdouble d; 
	    JS_ValueToNumber(context, rval, &d); 
	    printf("eval result = %f\n", d); 
	 } 

執(zhí)行結(jié)果為:

 eval result = 90.000000 

編譯 JavaScript 代碼

通常,我們可能會多次執(zhí)行一段腳本,SpiderMonkey 可以將腳本編譯成 JSScript 對象,然后可以供后續(xù)的多次調(diào)用?,F(xiàn)在來看一個例子,使用 C 代碼編譯一個 JavaScript 腳本,然后運行這個腳本。


清單 7. 從文件加載并執(zhí)行腳本
				
 JSBool evalScriptFromFile(JSContext *cntext, const
	char *file){ 
    JSScript *script; 
    JSString *jss; 
    JSBool status; 
    jsval value; 

    //get the global object 
    JSObject *global = JS_GetGlobalObject(context); 

    //compile the script for further using 
    script = JS_CompileFile(context, global, file); 

    if (script == NULL){ 
        return JS_FALSE; 
    } 

    //execute it once 
    status = JS_ExecuteScript(context, global, script, &value); 
    jss = JS_ValueToString(context, value); 
    printf("eval script result is : %s\n", JS_GetStringBytes(jss)); 

    //destory the script object 
    JS_DestroyScript(context, script); 

    return status; 
 } 

這里傳遞給函數(shù) evalScriptFromFile的 JSContext* 參數(shù)為外部創(chuàng)建好的 Context 對象,創(chuàng)建的方法參看上一節(jié)。


清單 8. 執(zhí)行
				
 JSBool status = evalScriptFromFile(context, "jstest.js"); 
 if (status == JS_FALSE){ 
        fprintf(stderr, "error while evaluate the script\n"); 
 } 

假設(shè)我們將如下腳本內(nèi)容保存進一個腳本 jstest.js:


清單 9. jstest.js 腳本內(nèi)容
				
				varPerson = function(name){ 
    var _name_ = name; 
    this.getName = function(){ 
        return _name_; 
    } 

    this.setName = function(newname){ 
        _name_ = newname; 
    } 
 } 

 varjack = new Person("jack"); 
 jack.setName("john"); 
 // 最后一句將作為腳本的執(zhí)行結(jié)果返回給 C 代碼
 jack.getName(); 

jack 對象的名字現(xiàn)在設(shè)置為了”john”, 腳本的最后一條語句的值將作為腳本的返回值返回到 C 代碼處,并打印出來:

 eval script result is : john 

C 與 JavaScript 的交互

C 程序調(diào)用 JavaScript 函數(shù)

由于兩者的數(shù)據(jù)類型上有較大的差異,因此無法直接從 C 代碼中調(diào)用 JavaScript 代碼,需要通過一定的轉(zhuǎn)化,將 C 的變量轉(zhuǎn)換為 JavaScript 可以設(shè)別的變量類型,然后進行參數(shù)的傳遞,返回值的處理也同樣要經(jīng)過轉(zhuǎn)換。

我們在 JavaScript 中定義一個函數(shù) add,這個函數(shù)接受兩個參數(shù)然后返回傳入的兩個參數(shù)的和。定義如下:


清單 10. JavaScript 版本的 add
				
				function add(x, y){ 
    return x + y; 
 } 

然后,我們在 C 語言中根據(jù)名稱調(diào)用這個 JS 函數(shù):


清單 11. 從 C 代碼中調(diào)用 JavaScript 函數(shù)
				
 JSBool func_test(JSContext *context){ 
    jsval res; 
    JSObject *global = JS_GetGlobalObject(context); 
    jsval argv[2]; 

    //new 2 number to pass into the function "add" in script 
    JS_NewNumberValue(context, 18.5, &res); 
    argv[0] = res; 
    JS_NewNumberValue(context, 23.1, &res); 
    argv[1] = res; 

    JS_CallFunctionName(context, global, "add", 2, argv, &res); 

    jsdouble d; 

    //convert the result to jsdouble 
    JS_ValueToNumber(context, res, &d); 
    printf("add result = %f\n", d); 

    return JS_TRUE; 
 } 

這里需要注意的是,JS_CallFunctionName 函數(shù)的參數(shù)列表:


清單 12. JS_CallFunctionName 原型
				
 JSBool  JS_CallFunctionName(JSContext *cx, JSObject *obj, 
 const char *name, uintN argc, jsval *argv, jsval *rval); 


表 2. JS_CallFunctionName 參數(shù)列表含義
名稱 類型 類型描述
cx JSContext * 上下文定義
obj JSObject * 調(diào)用該方法的對象
name const char * 函數(shù)名
argc uintN 函數(shù)參數(shù)個數(shù)
argv jsval * 函數(shù)實際參數(shù)形成的數(shù)組
rval jsval * 返回值

參數(shù)中的 argv 是一個 jsval 形成的數(shù)組,如果直接傳遞 C 類型的值,則很容易出現(xiàn) core dump(Linux 下的段錯誤所導(dǎo)致 ),因此,需要 JS_NewNumberValue 函數(shù)轉(zhuǎn)換 C 語言的 double 到 number( 原因見對象轉(zhuǎn)換小節(jié) )。

JavaScript 程序調(diào)用 C 函數(shù)

從 JS 中調(diào)用 C 函數(shù)較上一節(jié)為復(fù)雜,我們來看一個較為有趣的例子:SpiderMonkey 中原生的 JavaScript 的全局變量中沒有 print 函數(shù),我們可以使用 C 的 printf 來實現(xiàn)這個功能。我們定義了一個函數(shù) print, print 使用 logging 函數(shù),而 logging 函數(shù)是定義在 C 語言中的,接受一個字符串作為參數(shù),打印這個字符串到標(biāo)準(zhǔn)輸出上 :


清單 13. JavaScript 調(diào)用 C 函數(shù)
				
 //log user log in information 
 logging("user jack login on 2010/7/6"); 

 //user do nothing else 
 nothing(); 

 //log user log out information 
 logging("user jack logout on 2010/7/7"); 

 function print(){ 
    for (vari = 0; i < arguments.length; i++){ 
        logging(arguments[i]); 
    } 
 } 

 print("hello", "all", "my", "friend"); 

在 C 語言中,我們定義 logging 函數(shù)和 nothing 函數(shù)的原型如下:


清單 14. C 函數(shù)的實現(xiàn)
				
 /** 
 * define an exposed function to be used in scripts 
 * print out all the incoming arguments as string. 
 */ 
 static JSBool  logging(JSContext *context, JSObject *object, uintN argc, 
        jsval *argv, jsval *value){ 
    int i = 0; 
    JSString *jss; 

    for(i = 0; i < argc; i++){ 
       jss = JS_ValueToString(context, argv[i]); 
       printf("message from script environment : %s\n", \ 
               JS_GetStringBytes(jss)); 
    } 
    return JS_TRUE; 
 } 

 /** 
 * define an exposed function to be used in scripts 
 * do nothing but print out a single line. 
 */ 
 static JSBool  nothing(JSContext *context, 
 JSObject *object, uintN argc, jsval *argv, jsval *value) 
 { 
    printf("got nothing to do at all\n"); 
    return JS_TRUE; 
 } 

從函數(shù)的簽名上可以看出,C 中暴露給 JS 使用的函數(shù),參數(shù)的個數(shù),及對應(yīng)位置上的類型,返回值都是固定的。所有的從 C 中暴露給 JS 的函數(shù)都需要“實現(xiàn)這個接口”。

定義好了函數(shù)之后,還需要一些設(shè)置才能在 JS 中使用這些函數(shù)。首先定義一個 JSFunctionSpec 類型的數(shù)組,然后通過 JS_DefineFunctions 將這些函數(shù)放到 global 對象上,然后在 JS 代碼中就可以訪問上邊列出的 C 函數(shù)了。具體步驟如下:


清單 15. 注冊函數(shù)列表
				
	static JSFunctionSpec functions[] = { 
    {"logging", logging, LOG_MINARGS, 0, 0}, 
    {"nothing", nothing, NOT_MINARGS, 0, 0}, 
    {0, 0, 0, 0, 0} 
 }; 

    //define function list here 
    if (!JS_DefineFunctions(context, global, functions)){ 
        return -1; 
 } 

運行結(jié)果如下:

 message from script environment : user jack login on 2010/7/6 
 got nothing to do at all 
 message from script environment : user jack logout on 2010/7/7 
 message from script environment : hello 
 message from script environment : all 
 message from script environment : my 
 message from script environment : friend 

在 C 程序中定義 JavaScript 對象

在 SpiderMonkey 中,在 JavaScript 中使用由 C 語言定義的對象較為復(fù)雜,一旦我們可以定義對象,使得兩個世界通過 JS 交互就變得非常簡單而有趣,很容易使用這樣的方式來定制我們的應(yīng)用,在系統(tǒng)發(fā)布之后仍然可以輕松的修改系統(tǒng)的行為。

首先,我們要定義好基本的數(shù)據(jù)結(jié)構(gòu),即我們要暴露給 JS 世界的對象的屬性,結(jié)構(gòu);然后,使用 JSAPI 定義這個對象的屬性;然后,使用 JSAPI 定義對象的方法;最后,創(chuàng)佳這個對象,并綁定其屬性表和方法列表,放入全局對象。

假設(shè)我們有這樣一個數(shù)據(jù)結(jié)構(gòu),用來表述一個人的簡單信息 :


清單 16. PersionInfo 結(jié)構(gòu)
				
 typedef struct{ 
    char name[32]; 
    char addr[128]; 
 }PersonInfo; 

定義屬性表為枚舉類型:


清單 17. 屬性表
				
enum person{ 
    NAME, 
    ADDRESS
 }; 

我們需要將 C 語言原生的數(shù)據(jù)結(jié)構(gòu)定義為 JSAPI 所識別的那樣:


清單 18. 屬性定義
				
 //define person properties 
 JSPropertySpec pprops[] = { 
    {"name", NAME, JSPROP_ENUMERATE}, 
    {"address", ADDRESS, JSPROP_ENUMERATE}, 
    {0} 
 }; 


清單 19. 方法定義
				
 //define person methods 
 JSFunctionSpec pfuncs[] = { 
    {"print", printing, 0}, 
    {"getName", getName, 0}, 
    {"setName", setName, 0}, 
    {"getAddress", getAddress, 0}, 
    {"setAddress", setAddress, 0}, 
    {0} 
 }; 


清單 20. 類定義
				
 //define person class (JSClass) 
 JSClass pclass = { 
    "person", 0, 
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, 
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub 
 }; 

一旦這些基本信息定義好 (pfuncs 數(shù)組中的 getter/setter 的實現(xiàn)比較簡單,這里由于篇幅不列出代碼,感興趣的朋友可以參看附錄 ),我們就可以實例化它,并將其放入上下文中,使得 JS 代碼可以訪問。


清單 21. 定義對象及對象的屬性,方法
				
    JSObject *person; 

    //define the object 
    person = JS_DefineObject(\ 
            context, global, "person", &pclass, 0, JSPROP_ENUMERATE); 

    //install the properties and methods on the person object 
    JS_DefineProperties(context, person, pprops); 
    JS_DefineFunctions(context, person, pfuncs); 

這樣,在 JavaScript 代碼中,我們就可以通過 person 這個標(biāo)識符來訪問 person 這個對象了:


清單 22. 測試腳本
				
 //undefined of course 
 person.print(); 

 //person.name = "abruzzi"; 
 //person.address = "Huang Quan Road"; 

 person.setName("Desmond"); 
 person.setAddress("HuangQuan Road"); 

 //print is global function, access properties directly 
 print("person name = " + person.name); 
 print("person address = " + person.address); 

 person.print(); 

 (function(){ 
    //using getter/setter to access properties 
    return person.getName() + " : " + person.getAddress(); 
 })(); 

對運行結(jié)果如下:

 name : undefined
 address : undefined
 person name = Desmond 
 person address = HuangQuan Road 
 name : Desmond 
 address : HuangQuan Road 
 eval script result is : Desmond : HuangQuan Road 

結(jié)束語

本文中詳細討論了如何使用基于 C 的 JavaScript 引擎:SpiderMonkey 的用法。包括最基本的代碼模板,C 代碼與 JavaScript 代碼之間的交互,以及在 C 代碼中定義 JavaScript 對象等內(nèi)容,使用這些基本概念,很容易將實現(xiàn)應(yīng)用程序的腳本化。在實際的應(yīng)用中,可以將應(yīng)用程序的部分組件 ( 提供給用戶自定義的組件 ) 暴露給 JavaScript 訪問,或者在 JavaScript 腳本中提供函數(shù)的存根 ( 僅僅定義函數(shù)的原型 ),用戶可以通過實現(xiàn)這些函數(shù)的具體邏輯,來實現(xiàn)腳本化。


下載

描述 名字 大小 下載方法
樣例代碼 jsfun.zip 8KB HTTP

關(guān)于下載方法的信息


參考資料

學(xué)習(xí)

討論

關(guān)于作者

邱俊濤,畢業(yè)于昆明理工大學(xué)計算機科學(xué)與技術(shù)專業(yè),對機械控制、電子、人工智能、函數(shù)式編程等領(lǐng)域有濃厚的興趣,對計算機科學(xué)的底層比較熟悉。喜歡 C/JAVA/Python/JavaScript 等語言。現(xiàn)就職于云電同方研發(fā)中心。

posted on 2011-07-25 19:19 楊粼波 閱讀(1379) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            蜜桃久久精品乱码一区二区| 午夜精品理论片| 亚洲国产高清一区二区三区| 国产婷婷色综合av蜜臀av| 国产精品尤物| 国产美女精品免费电影| 国产欧美成人| 国产一区二区丝袜高跟鞋图片| 国产一区二区黄| 国语自产精品视频在线看抢先版结局| 国产一区视频观看| 亚洲电影在线看| 亚洲精品免费观看| 一区二区三区高清| 亚洲欧美日韩一区二区三区在线观看 | 久久国内精品自在自线400部| 欧美一级夜夜爽| 久久亚洲春色中文字幕| 美女脱光内衣内裤视频久久网站| 免费日韩精品中文字幕视频在线| 欧美激情一区二区三区全黄| 91久久精品国产91性色tv| 亚洲精品中文字幕在线观看| 一区二区三区**美女毛片| 亚洲一区中文| 老司机67194精品线观看| 欧美大片免费观看在线观看网站推荐 | 欧美福利在线观看| 99热在这里有精品免费| 亚洲欧美国产日韩天堂区| 久久精品一区中文字幕| 欧美福利电影在线观看| 国产精品v日韩精品| 国内综合精品午夜久久资源| 91久久精品久久国产性色也91| 亚洲天堂激情| 久久这里只有精品视频首页| 亚洲精品精选| 欧美一区二区三区在线播放| 欧美3dxxxxhd| 国产精品一区二区三区四区五区 | 亚洲国产午夜| 亚洲免费在线播放| 噜噜噜久久亚洲精品国产品小说| 亚洲精品美女在线观看| 亚洲欧美日韩精品久久| 你懂的视频一区二区| 国产精品麻豆成人av电影艾秋| 亚洲二区在线| 午夜老司机精品| 亚洲第一伊人| 欧美永久精品| 欧美午夜一区二区三区免费大片| 精品成人在线| 亚洲欧美一区二区在线观看| 欧美国产激情| 久久av一区二区| 欧美视频一区二区三区在线观看| 悠悠资源网亚洲青| 午夜精品视频在线| 亚洲精品美女91| 久久婷婷国产麻豆91天堂| 国产精品一区二区三区久久| 亚洲美女精品久久| 美女91精品| 亚洲一区二区久久| 欧美日韩国产小视频在线观看| 狠狠做深爱婷婷久久综合一区| 亚洲免费一级电影| 亚洲精品乱码久久久久久日本蜜臀| 久久国产精品久久久久久| 国产精品高清网站| 一本色道久久综合亚洲精品不卡 | 久久这里只精品最新地址| 国产精品推荐精品| 这里只有视频精品| 亚洲激情av| 蜜桃久久av一区| 在线不卡中文字幕| 久久久久国产精品www| 亚洲一区综合| 国产精品久久久一本精品| 一区二区三区 在线观看视频| 欧美国产日韩a欧美在线观看| 久久精品欧美| 好看的亚洲午夜视频在线| 欧美在线视频一区| 亚洲专区国产精品| 国产精品女主播在线观看| 亚洲一区二区精品视频| 久久99伊人| 亚洲综合精品四区| 国产精品一区二区久久| 亚洲欧美综合另类中字| 亚洲视频在线播放| 国产精品成人v| 亚洲女ⅴideoshd黑人| 一本久道久久综合狠狠爱| 欧美日韩一级片在线观看| 一区二区免费在线视频| 日韩写真视频在线观看| 欧美日本高清视频| 一区二区成人精品| 日韩一级网站| 国产精品久久久久久五月尺| 亚洲欧美另类中文字幕| 亚洲欧美激情视频在线观看一区二区三区| 国产精品视频免费| 久久精品国产亚洲高清剧情介绍| 午夜精品久久久久久久久| 国产一区二区三区久久久久久久久| 久久黄色网页| 久久午夜影视| 亚洲伦理在线观看| 9l国产精品久久久久麻豆| 欧美性感一类影片在线播放 | 亚洲午夜av在线| 国产欧美日韩精品在线| 久久综合中文| 欧美电影免费观看高清| 一本久久a久久精品亚洲| 一区二区三区四区精品| 国产免费观看久久| 美女黄毛**国产精品啪啪 | 在线观看欧美一区| 91久久在线播放| 国产精品日韩欧美一区二区| 久久久久久婷| 欧美成人黑人xx视频免费观看| 一本色道婷婷久久欧美| 亚洲欧美国产精品桃花| 狠狠色噜噜狠狠色综合久| 亚洲国产精彩中文乱码av在线播放| 欧美人牲a欧美精品| 欧美一区二区三区日韩| 久久免费视频观看| 亚洲视频在线观看三级| 欧美亚洲综合另类| 亚洲精品欧美日韩专区| 亚洲午夜免费视频| 亚洲国产一二三| 亚洲视频视频在线| 欧美日韩国内自拍| 久久激情五月丁香伊人| 欧美高清在线观看| 欧美一区国产一区| 欧美成人精品激情在线观看| 午夜激情综合网| 美国十次了思思久久精品导航| 亚洲视频一区在线| 久久理论片午夜琪琪电影网| 亚洲婷婷免费| 久久视频在线看| 亚洲欧美日韩高清| 欧美福利电影网| 久久久精品日韩欧美| 欧美日本亚洲韩国国产| 久久久蜜桃精品| 欧美午夜理伦三级在线观看| 美女精品在线观看| 国产精品久久久久秋霞鲁丝 | 一区二区三区在线看| 一区二区三区鲁丝不卡| 亚洲国产欧美一区二区三区同亚洲| 亚洲综合视频在线| 亚洲人体1000| 欧美在线免费视屏| 亚洲综合视频一区| 欧美激情一区二区三区高清视频| 久久精品91久久香蕉加勒比 | 亚洲精品国产视频| 亚洲福利国产精品| 欧美一区二区三区婷婷月色| 一区二区高清视频| 久久综合网色—综合色88| 欧美在线黄色| 国产精品第三页| 亚洲久久成人| 亚洲国产美女精品久久久久∴| 亚洲欧美日韩在线一区| 一区二区三区视频观看| 欧美1区免费| 欧美激情一区二区三区四区| 伊人成人在线| 欧美一区二区久久久| 午夜精品久久久久久久99樱桃 | 一区二区三区四区国产精品| 久久午夜精品| 看欧美日韩国产| 国产午夜精品全部视频在线播放| 亚洲视频福利| 亚洲午夜视频在线| 欧美日韩视频免费播放| 欧美激情视频免费观看| 在线看片日韩| 久久中文字幕一区| 免费视频一区二区三区在线观看| 国产一区二区三区在线观看精品 | 国产亚洲欧美另类一区二区三区| 宅男66日本亚洲欧美视频|