国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

jsweet中英文文檔,java代碼轉js代碼

Mr_houzi / 1805人閱讀

摘要:例如允許的對象默認情況下,通過使用內置宏將核心對象和方法映射到。例如這被轉換為以下代碼類可以定義構造函數,具有超類,并且可以像在中一樣實例化。因此,它不違反原則。用于聲明該對象可以用作構造函數。

這個工具可以將java代碼轉為js代碼,從而可以使用java編寫前端代碼 如果排版看著費勁可以下載下方html,打開html后使用google翻譯

JSweet語言規范
版本:2.x(快照)

作者:Renaud Pawlak

作者助理:Louis Grignon

JSweet JavaDoc API:http://www.jsweet.org/core-api-javadoc/

注意:此降價是從Latex源文件自動生成的。不要直接修改。

內容
基本概念
核心類型和對象

接口
無類型對象(地圖)
枚舉
全局
可選參數和重載
橋接外部JavaScript元素
例子
寫定義規則(又名橋梁)
無法訪問
混入
從現有的TypeScript定義生成JSweet糖果
輔助類型
功能類型
對象類型
字符串類型
元組類型
聯盟類型
交叉類型
語義
主要方法
初始化器
數組初始化和分配
異步編程
姓名沖突
測試對象的類型
lambda表達式中的變量作用域
這個范圍
打包
使用您的文件,無需任何包裝
為瀏覽器創建捆綁包
包裝模塊
根包
包裝JSweet jar(糖果)
擴展轉換器
核心注釋
集中注釋 jsweetconfig.json
使用適配器進行編程調整
擴展示例
附錄1:JSweet轉換器選項
附錄2:包裝和靜態行為
調用main方法時
靜態和繼承依賴項
基本概念
本節介紹JSweet語言的基本概念。必須記住,JSweet作為Java-to-JavaScript轉換器,是編譯時Java的擴展,并在運行時作為JavaScript執行。JSweet旨在通過盡可能多地尊重Java語義來實現Java和JavaScript之間的權衡,但不會失去與JavaScript的互操作性。因此,在某種程度上,JSweet可以看作是Java和JavaScript之間的融合,試圖用一種獨特且一致的語言來充分利用這兩個世界。在某些情況下,很難充分利用這兩個世界,JSweet可以提供方便實用的選擇。

因為JSweet是一個開放的JavaScript轉換器,所以用戶可以毫不費力地調整JavaScript生成,從而做出除默認選擇之外的其他選擇來將Java映射到JavaScript。例如,如果JSweet實現Java映射的方式不適合您的上下文或用例,則可以編寫JSweet擴展以覆蓋默認策略。第6節詳細介紹了編程和激活JSweet擴展 。

核心類型和對象
JSweet允許使用原始Java類型,核心Java對象(在java.lang許多JDK類中定義(特別是java.util但不僅僅是),以及在def.js包中定義的核心JavaScript對象 。接下來,我們描述了這些核心類型的使用和對象。

原始Java類型
JSweet允許使用Java原始類型(和相關的文字)。

int,byte,short,double,float被全部轉換成JavaScript數字(打字稿number類型)。精密通常不會在JSweet無所謂,但是,鑄造int,byte或 short強制四舍五入到合適的長度整數數量。

char遵循Java類型規則,但由轉換器轉換為JavaScript string。

boolean對應于JavaScript boolean。

java.lang.String對應于JavaScript string。(不是說原始類型,但是是不可變的并且在Java中用作字符串文字的類)

轉換的直接后果是,JSweet中并不總是可以使用數字或字符/字符串安全地重載方法。例如,方法pow(int, int)以及 pow(double, double)可能引起過載的問題。使用JSweet上下文,轉換器將能夠選擇正確的方法,但JavaScript互操作性可能是一個問題??傊捎跊]有區別n instanceof Integer和n instanceof Double (它既裝置typeof n === ’number’)調用pow(number, number) 從JavaScript將隨機選擇一個實現或其他。這不應該總是一個問題,但在某些特殊情況下,它可能會產生微妙的錯誤。請注意,在這些情況下,程序員將能夠調整JavaScript生成,如第6節中的完整解釋 。

有效聲明的示例:

// warning "==" behaves like JavaScript "===" at runtime
int i = 2;
assert i == 2;
double d = i + 4;
assert d == 6;
String s = "string" + "0" + i;
assert s == "string02";
boolean b = false;
assert !b;
該==運營商的行為類似于JavaScript的嚴格等于運算符 ===,使其接近Java語義。同樣,!=映射到!==。在將對象與null文字進行比較時,該行為有一個例外。在這種情況下,JSweet轉換為松散的相等運算符,以便程序員看不到null和之間的區別undefined(這在JavaScript中是不同的,但它可能會讓Java程序員感到困惑)。要控制JSweet是否生成嚴格或松散的運算符,可以使用以下輔助方法:jsweet.util.Lang.$strict和 jsweet.util.Lang.$loose。在這樣的宏中包裝比較運算符將強制JSweet生成嚴格或松散的運算符。例如:

import static jsweet.util.Lang.$loose;
[...]
int i = 2;
assert i == 2; // generates i === 2
assert !((Object)"2" == i);
assert $loose((Object)"2" == i); // generates "2" == i
允許的Java對象
默認情況下,JSweet通過使用內置宏將核心Java對象和方法映射到JavaScript。這意味著Java代碼直接替換為實現類似行為的有效JavaScript代碼。為大多數有用的核心Java類(java.lang,java.util)實現了默認映射。在可能的情況下(當它有意義時),為其他JDK類實現一些部分映射,例如輸入和輸出流,區域設置,日歷,反射等。

使用默認行為,我們可以指出以下限制:

除了某些特定的上下文之外,通常不可能擴展JDK類。如果需要擴展JDK類,應該考慮重構您的程序,或者使用允許它的JavaScript運行時(例如J4TS)。

Java反射API(java.lang.reflect)僅限于非?;镜牟僮?。可以訪問類和成員,但無法訪問類型??梢允褂酶暾腏ava反射支持,但需要JSweet擴展。

目前還不支持Java 8流,但部分支持它們很簡單(歡迎貢獻)。

有效聲明的示例:

Integer i = 2;
assert i == 2;
Double d = i + 4d;
assert d.toString() == "6";
assert !((Object) d == "6");
BiFunction f = (s, i) -> { return s.substring(i); };
assert "bc" == f.apply("abc", 1);
獲得更多Java API
使用JSweet,可以添加在JavaScript中實現Java API的運行時,以便程序員可以訪問更多Java API,從而在Java和JavaScript之間共享相同的代碼。為JSweet實現Java API的核心項目是J4TS(https://github.com/cincheo/j4ts),它包含一個非常完整的java.util.*類和其他核心包的實現。J4TS基于GWT的JRE仿真的一個分支,但它適合用JSweet編譯。程序員可以將J4TS用作Maven存儲庫中的常規JavaScript庫。

雖然J4TS不能直接執行Java核心類型的使用JavaScript的人發生沖突(Boolean,Byte,Short,Integer, Long,Float,Double,Character,String),J4TS有助于通過為每個類提供傭工(支持他們的靜態部分javaemul.internal.BooleanHelper,javaemul.internal.ByteHelper...)。當JSweet轉換器在java.lang.T不支持作為內置宏的類型上遇到靜態Java方法時 ,它會委托給 javaemul.internal.THelper,它可以為給定的靜態方法提供JavaScript實現。這樣,通過使用J4TS,程序員可以使用更多的核心JRE API。

Java數組
數組可以在JSweet中使用,并轉換為JavaScript數組。數組初始化,訪問和迭代都是有效的語句。

int[] arrayOfInts = { 1, 2, 3, 4};
assert arrayOfInts.length == 4;
assert arrayOfInts[0] == 1;
int i = 0;
for (int intItem : arrayOfInts) {

assert arrayOfInts[i++] == intItem;

}
核心JavaScript API
核心JavaScript API已定義def.js(完整文檔可在http://www.jsweet.org/core-ap...)。主要的JavaScript類是:

def.js.Object:JavaScript Object類。JavaScript對象函數和屬性的共同祖先。

def.js.Boolean:JavaScript布爾類。布爾值的包裝器。

def.js.Number:JavaScript Number類。數值的包裝器。

def.js.String:JavaScript String類。字符串的包裝器和構造函數。

def.js.Function:JavaScript函數類。函數的構造函數。

def.js.Date:JavaScript Date類,它支持基本存儲和檢索日期和時間。

def.js.Array:JavaScript Array類。它用于構造數組,它是高級的,類似列表的對象。

def.js.Error:JavaScript錯誤類。這個類實現 java.lang.RuntimeException并且可以被拋出并被try ... catch語句捕獲。

使用JavaScript框架時,程序員應該在大多數時間使用此API,這與HTML5兼容并遵循JavaScript最新支持的版本。但是,對于需要與Java文字(數字,布爾值和字符串)一起使用的對象,java.lang 建議使用包類。例如,jQuery API聲明 $(java.lang.String)而不是$(def.js.String)。這允許程序員使用文字來編寫表達式,例如$("a")(用于選擇文檔中的所有鏈接)。

使用JSweet,程序員可以根據需要輕松地從Java切換到JavaScript API(反之亦然)。在jsweet.util.Lang 類定義方便的靜態方法投來回核心Java對象到其相應的JavaScript對象。例如,該 string(...)方法將允許程序員從Java切換到JavaScript字符串,反之亦然。

import static jsweet.util.Lang.string;
// str is a Java string, but is actually a JavaScript string at runtime
String str = "This is a test string";
// str is exactly the same string object, but shown through the JS API
def.js.String str2 = string(str);
// valid: toLowerCase it defined both in Java and JavaScript
str.toLowerCase();
// this method is not JS-compatible, so a macro generates the JS code
str.equalsIgnoreCase("abc");
// direct call to the JS substr method on the JavaScript string
string(str).substr(1);
// or
str2.substr(1);
注意:例如,對于JavaScript客戶端和Java服務器之間的代碼共享,最好只使用Java API并避免使用JavaScript API。JavaScript API將編譯有效的Java字節碼,但嘗試在JVM上執行它們會引起不滿意的鏈接錯誤。

這是另一個示例,顯示了使用該array方法訪問pushJavaScript數組中可用的方法。

import static jsweet.util.Lang.array;
String[] strings = { "a", "b", "c" };
array(strings).push("d");
assert strings[3] == "d";

JSweet中的類完全支持所有類型的Java類聲明。例如:

public class BankAccount {

public double balance = 0;
public double deposit(double credit) {
    balance += credit;
    return this.balance;
}

}
這被轉換為以下JavaScript代碼:

var BankAccount = (function () {

function BankAccount() {
    this.balance = 0;
}
BankAccount.prototype.deposit = function(credit) {
    this.balance += credit;
    return this.balance;
};
return BankAccount;

})();
類可以定義構造函數,具有超類,并且可以像在Java中一樣實例化。與Java類似,JSweet中允許使用內部類和匿名類(從1.1.0版開始)。JSweet支持靜態和常規內部/匿名類,它們可以與封閉類共享狀態。仍然像在Java中一樣,匿名類可以訪問其作用域中聲明的最終變量。例如,以下聲明在JSweet中有效,并且將在運行時模仿Java語義,以便Java程序員可以受益于Java語言的所有功能。

abstract class C {

public abstract int m();

}
public class ContainerClass {

// inner class
public class InnerClass {
    public I aMethod(final int i) {
        // anonymous class
        return new C() {
            @Override
            public int m() {
                // access to final variable i
                return i;
            }
        }
    }
}

}
接口
在JSweet中,可以像在Java中一樣使用接口。但是,與Java相反,沒有關聯的類可用作運行時。使用接口時,JSweet會生成代碼來模擬特定的Java行為(例如instanceof在接口上)。

JSweet支持Java 8靜態和默認方法。但是,默認方法到目前為止都是實驗性的,你應該自擔風險使用它們。

在JSweet中,接口更類似于TypeScript中的接口而不是Java中的接口。這意味著它們必須被視為對象簽名,它可以指定函數,還可以指定屬性。為了在定義接口時允許使用字段作為屬性,JSweet允許使用帶注釋的常規類@jsweet.lang.Interface。例如,以下接口鍵入Point具有2個屬性的對象。

@Interface
public class Point {

public double x;
public double y;

}
對于Java程序員來說,這可能看起來像是一種非常奇怪的方法來定義一個對象,但是你必須記住它不是一個類,而是一個JavaScript對象的類型。因此,它不違反OOP原則。我們可以創建一個在界面后鍵入的JavaScript對象。請注意,以下代碼實際上并未創建Point 接口的實例,而是創建符合接口的對象。

Point p1 = new Point() {{ x=1; y=1; }};
此對象創建機制是TypeScript / JavaScript機制,不應與匿名類混淆,匿名類是類似Java的構造。因為Point有注釋@Interface,轉換后的JavaScript代碼類似于:

var p1 = Object.defineProperty({ x:1, y:1 }, "_interfaces", ["Point"]);
請注意,對于每個對象,JSweet會跟蹤其創建的接口以及其類實現的所有可能接口。此接口跟蹤系統實現為一個名為的特殊對象屬性__interfaces。使用該屬性,JSweet允許instanceof在Java之類的接口上使用運算符。

接口中的可選字段
接口可以定義可選字段,用于在程序員忘記初始化對象中的必填字段時報告錯誤。在JSweet中支持可選字段是通過使用 @jsweet.lang.Optional注釋完成的。例如:

@Interface
public class Point {

public double x;
public double y;
@Optional
public double z = 0;

}
在從接口構造對象時,JSweet編譯器將檢查字段是否已正確初始化。

// no errors (z is optional)
Point p1 = new Point() {{ x=1; y=1; }};
// JSweet reports a compile error since y is not optional
Point p2 = new Point() {{ x=1; z=1; }};
接口中的特殊JavaScript函數
在JavaScript中,對象可以具有屬性和函數,但也可以(非排他地)用作構造函數和函數本身。這在Java中是不可能的,因此JSweet定義了用于處理這些情況的特殊函數。

$apply 用于表示該對象可以用作函數。

$new 用于聲明該對象可以用作構造函數。

例如,如果一個對象o是O定義 的接口$apply(),則寫:

o.$apply();
將轉變為:

o();
同樣,如果O定義$new():

o.$new();
將轉變為:

new o();
是的,它在Java中沒有意義,但在JavaScript中確實如此!

無類型對象(地圖)
在JavaScript中,對象可以看作包含鍵值對的映射(鍵通常稱為索引,尤其是當它是數字時)。因此,在JSweet中,所有對象都定義了特殊函數(定義于 def.js.Object):

$get(key) 使用給定鍵訪問值。

$set(key,value) 設置或替換給定鍵的值。

$delete(key) 刪除給定鍵的值。

反射/無類型訪問
的功能$get(key),$set(key,value)并且$delete(key)可以被看作是一個簡單的反射API來訪問對象字段和狀態。還要注意靜態方法def.js.Object.keys(object),它返回給定對象上定義的所有鍵。

以下代碼使用此API來內省對象的狀態 o。

for(String key : def.js.Object.keys(o)) {
console.log("key=" + key + " value=" + o.$get(key));
});
當沒有給定對象的類型化API時,此API可用于以無類型方式操作對象(當然應盡可能避免使用)。

無類型對象初始化
可以使用該$set(key,value)函數創建新的無類型對象。例如:

Object point = new def.js.Object() {{ $set("x", 1); $set("y", 1); }};
它也轉化為:

var point = { "x": 1, "y": 1};
作為一種快捷方式,可以使用該jsweet.util.Lang.$map函數,該函數轉換為完全相同的JavaScript代碼:

import static jsweet.util.Lang.$map;
[...]
Object point = $map("x", 1, "y", 1);
索引對象
可以為每個對象重載鍵和值的類型。例如,Array類將鍵作為數字和值定義為符合類型的對象T。

對于使用數字鍵索引的對象,允許實現java.lang.Iterable接口,以便可以在foreach循環中使用它們。例如,NodeList類型(來自DOM)定義了一個索引函數:

@Interface
class NodeList implements java.lang.Iterable {

public double length;
public Node item(double index);
public Node $get(double index);

}
在JSweet中,您可以使用該$get 函數訪問節點列表元素,也可以使用foreach語法進行迭代。以下代碼生成完全有效的JavaScript代碼。

NodeList nodes = ...
for (int i = 0; i < nodes.length; i++) {

HTMLElement element = (HTMLElement) nodes.$get(i);
[...]

}
// same as:
NodeList nodes = ...
for (Node node : nodes) {

HTMLElement element = (HTMLElement) node;
[...]

}
枚舉
JSweet允許類似于Java定義枚舉。下面的代碼聲明與樹可能值的枚舉(A,B,和C)。

enum MyEnum {

A, B, C

}
以下語句是JSweet中的有效語句。

MyEnum e = MyEnum.A;
assert MyEnum.A == e;
assert e.name() == "A";
assert e.ordinal() == 0;
assert MyEnum.valueOf("A") == e;
assert array(MyEnum.values()).indexOf(MyEnum.valueOf("C")) == 2;
與Java枚舉一樣,可以在枚舉中添加其他方法,構造函數和字段。

enum ScreenRatio {

FREE_RATIO(null),
RATIO_4_3(4f / 3),
RATIO_3_2(1.5f),
RATIO_16_9(16f / 9),
RATIO_2_1(2f / 1f),
SQUARE_RATIO(1f);

private final Float value;

private MyComplexEnum(Float value) {
    this.value = value;
}

public Float getValue() {
    return value;
}

}
枚舉便攜性說明
簡單的枚舉被轉換為常規的TypeScript枚舉,即數字。在JavaScript中,在運行時,枚舉實例是簡單編碼的序數。因此,JSweet枚舉很容易與TypeScript枚舉共享,即使使用枚舉,JSweet程序也可以與TypeScript程序進行互操作。

具有其他成員的枚舉也會映射到TypeScript枚舉,但會生成另一個類來存儲其他信息。與TypeScript互操作時,序號將保留,但附加信息將丟失。想要與TypeScript共享枚舉的程序員應該知道這種行為。

全局
在Java中,與JavaScript相反,沒有全局變量或函數(只有靜態成員,但即使那些必須屬于一個類)。因此,JSweet引入了保留的Globals 類和globals包。這有兩個目的:

生成具有全局變量和函數的代碼(在Java中不鼓勵這樣做)

綁定到定義全局變量和函數的現有JavaScript代碼(盡可能多的JavaScript框架)

在Globals類中,只允許使用靜態字段(全局變量)和靜態方法(全局函數)。以下是適用于Globals類的主要約束:

沒有非靜態成員

沒有超級課程

不能延長

不能用作常規類的類型

沒有公共構造函數(空私有構造函數可以)

不能在方法中使用$ get,$ set和$ delete

例如,以下代碼片段將引發轉換錯誤。

class Globals {

public int a;
// error: public constructors are not allowed
public Globals() {
    this.a = 3;
}
public static void test() {
    // error: no instance is available
    $delete("key");
}

}
// error: Globals classes cannot be used as types
Globals myVariable = null;
必須記住,Globals類和global包在運行時被擦除,以便可以直接訪問它們的成員。例如mypackage.Globals.m(),在JSweet程序中,對應mypackage.m()于生成的代碼中的函數以及運行時的JavaScript VM中的 函數。此外,mypackage.globals.Globals.m()對應于m()。

為了擦除生成代碼中的包,程序員也可以使用@Root注釋,這將在第5節中解釋 。

可選參數和重載
In JavaScript, parameters can be optional, in the sense that a parameter value does not need to be provided when calling a function. Except for varargs, which are fully supported in JSweet, the general concept of an optional parameter does not exist in Java. To simulate optional parameters, JSweet programmers can use method overloading, which is supported in Java. Here are some examples of supported overloads in JSweet:

String m(String s, double n) { return s + n; }
// simple overloading (JSweet transpiles to optional parameter)
String m(String s) { return m(s, 0); }
// complex overloading (JSweet generates more complex code to mimic the Java behavior)
String m(String s) { return s; }
Bridging to external JavaScript elements
It can be the case that programmers need to use existing libraries from JSweet. In most cases, one should look up in the available candies, a.k.a. bridges at http://www.jsweet.org/jsweet-... When the candy does not exist, or does not entirely cover what is needed, one can create new definitions in the program just by placing them in the def.libname package. Definitions only specify the types of external libraries, but no implementations. Definitions are similar to TypeScript’s .d.ts definition files (actually JSweet generates intermediate TypeScript definition files for compilation purposes). Definitions can also be seen as similar to .h C/C++ header files.

Examples
以下示例顯示了使用簡單定義可供JSweet程序員訪問的主干存儲類。此類僅用于鍵入,將作為TypeScript定義生成,并在JavaScript生成期間擦除。

package def.backbone;
class Store {

public Store(String dbName) {}

}
請注意,定義類構造函數必須具有空體。此外,定義類方法必須是native。例如:

package def.mylib;
class MyExternalJavaScriptClass {

public native myExternalJavaScriptMethod();

}
可以在定義中定義屬性,但是,無法初始化這些屬性。

寫定義規則(又名橋梁)
按照慣例,將類放在def.libname包中定義了一組libname名為的外部JavaScript庫 的定義libname。請注意,此機制類似于TypeScript d.ts 定義文件。

Candies(外部JavaScript庫的橋梁)使用定義。例如,jQuery candy定義了def.jquery包中的所有jQuery API 。

以下是編寫定義時需要遵循的規則和約束的列表。

接口比類更受歡迎,因為接口可以合并,類可以實例化。僅當API定義顯式構造函數(可以使用其創建對象new)時,才應使用類。要在JSweet中定義接口,只需使用注釋類@jsweet.lang.Interface。

必須將頂級函數和變量定義為類中的public static 成員Globals。

所有類,接口和包都應記錄在Javadoc標準之后的注釋。

當函數參數有多種類型時,方法重載應優先于使用union類型。當無法進行方法重載時,簡單地使用Object類型會更方便。鍵入的強度較低,但更容易使用。

可以使用字符串類型來提供函數重載,具體取決于字符串參數值。

在方法簽名中,可以使用@jsweet.lang.Optional注釋定義可選參數 。

在界面中,可以使用@jsweet.lang.Optional注釋定義可選字段 。

定義可以直接嵌入到JSweet項目中,以便以類型化的方式訪問外部庫。

定義也可以打包成糖果(Maven工件),以便它們可以被其他項目共享。有關如何創建糖果的完整詳細信息,請參閱“ 包裝”部分。請注意,在使用JSweet編寫庫時不需要編寫定義,因為Java API可以直接訪問,并且可以使用該declaration選項由JSweet自動生成TypeScript定義。

無法訪問
有時,定義不可用或不正確,只需要一個小補丁即可訪問功能。程序員必須記住,JSweet只是一個語法層,并且總是可以繞過鍵入以訪問未在API中明確指定的字段或函數。

雖然具有良好類型的API是首選和建議的方式,但是當這樣的API不可用時,使用def.js.Object.$get允許反射訪問方法和屬性,然后可以將其轉換為正確的類型。為了以無類型方式訪問函數,可以強制轉換 def.js.Function并調用泛型和非類型化方法$apply。例如,以下是$在jQuery API不可用時如何調用jQuery 方法:

import def.dom.Globals.window;
[...]
Function $ = (Function)window.$get("$");
$.$apply("aCssSelector"):
該$get函數可用于def.js.Object(或子類)的實例。對于a def.js.Object,您可以使用jsweet.util.Lang.object輔助方法強制轉換它 。例如:

import static jsweet.dom.Lang.object;
[...]
object(anyObject).$get("$");
最后,jsweet.util.Lang.$inserthelper方法允許用戶在程序中插入任何TypeScript表達式。無效的表達式將引發TypeScript編譯錯誤,但不建議使用此技術。

import static jsweet.dom.Lang.$get;
import static jsweet.dom.Lang.$apply;
[...]
// generate anyObject"prop";
$apply($get(anyObject, "prop"), "param");
最后,還要注意使用jsweet.util.Lang.any輔助方法,這對于擦除鍵入非常有用。由于該any方法any在TypeScript中生成類型的強制轉換,因此它比例如強制轉換更激進Object。以下示例說明如何使用該any方法將Int32ArrayJava轉換為Java int[](然后允許對其進行直接索引訪問)。

ArrayBuffer arb = new ArrayBuffer(2 2 4);
int[] array = any(new Int32Array(arb));
int whatever = array[0];
混入
在JavaScript中,通常的做法是使用新聞元素(字段和方法)來增強現有類。它是框架定義插件時使用的擴展機制。通常,jQuery插件會向JQuery類中添加新元素。例如,jQuery計時器插件timer向JQuery該類添加一個字段。因此,JQuery如果您多帶帶使用jQuery,或者使用其計時器插件增強jQuery ,則 該類沒有相同的原型。

在Java中,此擴展機制存在問題,因為Java語言默認情況下不支持mixins或任何類型的擴展。

無法訪問mixins
程序員可以使用訪問$get器和/或強力轉換來訪問添加的元素。

以下是$get用于計時器插件的示例:

((Timer)$("#myId").$get("timer")).pause();
這是另一種通過使用jQuery UI插件來實現它的方法(請注意,此解決方案強制使用def.jqueryui.JQuery 而不是def.jquery.JQuery為了訪問menu()由UI插件添加的功能):

import def.jqueryui.JQuery;
[...]
Object obj = $("#myMenu");
JQuery jq = (JQuery) obj;
jq.menu();
然而,這些解決方案并不完全令人滿意,因為在打字方面明顯不安全。

使用mixins鍵入訪問
當需要交叉糖果動態擴展時,JSweet定義了mixin的概念。mixin是一個定義成員的類,最終可以在目標類(mixin-ed類)中直接訪問。Mixins使用@Mixin注釋定義。這是def.jqueryui.JQuerymixin 的摘錄 :

package def.jqueryui;
import def.dom.MouseEvent;
import def.js.Function;
import def.js.Date;
import def.js.Array;
import def.js.RegExp;
import def.dom.Element;
import def.jquery.JQueryEventObject;
@jsweet.lang.Interface
@jsweet.lang.Mixin(target=def.jquery.JQuery.class)
public abstract class JQuery extends def.jquery.JQuery {

native public JQuery accordion();
native public void accordion(jsweet.util.StringTypes.destroy methodName);
native public void accordion(jsweet.util.StringTypes.disable methodName);
native public void accordion(jsweet.util.StringTypes.enable methodName);
native public void accordion(jsweet.util.StringTypes.refresh methodName);
...
native public def.jqueryui.JQuery menu();
...

人們可以注意到@jsweet.lang.Mixin(target=def.jquery.JQuery.class) ,這個mixin將被合并到一起,def.jquery.JQuery以便用戶能夠直接以一種良好的方式使用所有UI插件成員。

如何使用
TBD。

從現有的TypeScript定義生成JSweet糖果
TBD。

輔助類型
JSweet使用大多數Java輸入功能(包括功能類型),但也使用所謂的輔助類型擴展Java類型系統。輔助類型背后的想法是創建可以通過使用類型參數(也稱為泛型)來保存鍵入信息的類或接口 ,以便JSweet轉換器可以涵蓋更多的鍵入方案。這些類型已經從TypeScript類型系統映射,它比Java更豐富(主要是因為JavaScript是一種動態語言,需要比Java更多的打字場景)。

功能類型
用于功能類型,JSweet重用java.Runnable和 java.util.function爪哇8的功能接口,這些接口是通用的,但只支持高達2參數的功能。因此,JSweet為更多參數添加了一些支持jsweet.util.function,因為它是JavaScript API中的常見情況。

以下是使用Function通用功能類型的示例:

import java.util.function.Function;

public class C {

String test(Function f) {
    f.apply("a");
}

public static void main(String[] args) {
    String s = new C().test(p -> p);
    assert s == "a";
}

}
我們鼓勵程序員使用jsweet.util.function和java.util.function(以及 java.lang.Runnable)中定義的通用功能接口。當需要具有更多參數的函數時,程序員可以jsweet.util.function通過遵循與現有函數相同的模板來定義他們自己的通用函數類型 。

在某些情況下,程序員更愿意定義自己的特定功能接口。這得到了JSweet的支持。例如:

@FunctionalInterface
interface MyFunction {

void run(int i, String s);

}

public class C {

void m(MyFunction f) {
    f.run(1, "test");
}
public static void main(String[] args) {
    new C().m((i, s) -> {
        // do something with i and s
    });
}

}
重要警告:這里要注意的是,與Java相反,@FunctionInterface注釋的使用是強制性的。

還要注意apply函數的可能用途,按照慣例,該函數始終是目標對象的功能定義(除非使用apply注釋進行@Name注釋)。定義/調用 apply可以在任何類/對象上完成(因為在JavaScript中任何對象都可以成為一個功能對象)。

對象類型
對象類型與接口類似:它們定義了一組適用于對象的字段和方法(但請記住它是一個編譯時合同)。在TypeScript中,對象類型是內聯的和匿名的。例如,在TypeScript中,以下方法m接受一個參數,該參數是包含index字段的對象:

// TypeScript:
public class C {

public m(param : { index : number }) { ... }

}
對象類型是編寫較短代碼的便捷方式??梢酝ㄟ^動態構建對象來傳遞正確鍵入的對象:

// TypeScript:
var c : C = ...;
c.m({ index : 2 });
顯然,對象類型是一種使程序員很容易輸入JavaScript程序的方法,這是TypeScript的主要目標之一。它使得JavaScript程序員的輸入簡潔,直觀,直觀。在Java / JSweet中,不存在類似的內聯類型,Java程序員用于為這種情況定義類或接口。因此,在JSweet中,程序員必須定義用@ObjectType對象類型注釋的輔助類。這可能看起來更復雜,但它有利于強制程序員命名所有類型,最終可以根據上下文導致更易讀和可維護的代碼。請注意,與接口類似,對象類型在運行時被擦除。另外@ObjectType 注解的類可以內部類,使他們在本地使用。

這是以前的TypeScript程序的JSweet版本。

public class C {

@ObjectType
public static class Indexed {
    int index;
}
public void m(Indexed param) { ... }

}
使用對象類型與使用接口類似:

C c = ...;
c.m(new Indexed() {{ index = 2; }});
當對象類型是共享對象并表示可以在多個上下文中使用的鍵入實體時,建議使用 @Interface注釋而不是@ObjectType。這是基于界面的版本。

@Interface
public class Indexed {

int index;

}

public class C {

public m(Indexed param) { ... }

}

C c = ...;
c.m(new Indexed {{ index = 2; }});
字符串類型
在TypeScript中,字符串類型是一種根據字符串參數的值來模擬函數重載的方法。例如,這是DOM TypeScript定義文件的簡化摘錄:

// TypeScript:
interface Document {

[...]
getElementsByTagName(tagname: "a"): NodeListOf;
getElementsByTagName(tagname: "b"): NodeListOf;
getElementsByTagName(tagname: "body"): NodeListOf;
getElementsByTagName(tagname: "button"): NodeListOf;
[...]

}
在此代碼中,getElementsByTagName函數都是依賴于傳遞給tagname參數的字符串的重載。不僅字符串類型允許函數重載(通常在TypeScript / JavaScript中不允許),但它們也約束字符串值(類似于枚舉),因此編譯器可以自動檢測字符串值中的拼寫錯誤并引發錯誤。

此功能對代碼質量很有用,JSweet提供了一種機制來模擬具有相同級別類型安全性的字符串類型。字符串類型是使用注釋的公共靜態字段@StringType。必須使用在同一容器類型中聲明的同名接口鍵入它。

對于JSweet翻譯庫(糖果),所有字符串類型都在類中聲明jsweet.util.StringTypes,因此程序員很容易找到它們。舉例來說,如果一個"body"字符串類型需要定義,一個名為Java接口body和一個靜態的最終場被稱為body在一個定義jsweet.util.StringTypes。

請注意,每個糖果可能在jsweet.util.StringTypes類中定義了自己的字符串類型 。JSweet轉換器在字節碼級別合并所有這些類,以便所有糖果的所有字符串類型在同一個jsweet.util.StringTypes實用程序類中可用。因此,JSweet DOM API將如下所示:

@Interface
public class Document {

[...]
public native NodeListOf getElementsByTagName(a tagname);
public native NodeListOf getElementsByTagName(b tagname);
public native NodeListOf getElementsByTagName(body tagname);
public native NodeListOf getElementsByTagName(button tagname);
[...]

}
在此API中a,b,body和button是在定義的接口 jsweet.util.StringTypes類。當使用一種方法時 Document,程序員只需要使用相應的類型實例(同名)。例如:

Document doc = ...;
NodeListOf elts = doc.getElementsByTagName(StringTypes.a);
注意:如果字符串值不是有效的Java標識符(例如 "2d"或者"string-with-dashes"),則將其轉換為有效的標識符并使??用注釋@Name("originalName"),以便JSweet轉換器知道必須在生成的代碼中使用什么實際字符串值。例如,默認情況下,"2d"和"string-with-dashes"將對應于接口StringTypes._2d和 StringTypes.string_with_dashes與@Name注解。

程序員可以根據自己的需要定義字符串類型,如下所示:

import jsweet.lang.Erased;
import jsweet.lang.StringType;

public class CustomStringTypes {

@Erased
public interface abc {}

@StringType
public static final abc abc = null;

// This method takes a string type parameter
void m2(abc arg) {
}

public static void main(String[] args) {
    new CustomStringTypes().m2(abc);
}

}
注意使用@Erased注釋,它允許聲明abc內部接口。此接口用于鍵入字符串類型字段abc。通常,我們建議程序員將程序的所有字符串類型分組到同一個實用程序類中,以便于查找它們。

元組類型
元組類型表示具有多帶帶跟蹤的元素類型的JavaScript數組。對于的元組類型,JSweet定義參數化輔助類TupleN,它定義$0,$1... $N-1 公共字段來模擬訪問類型數組(字段$i中鍵入與 Ti)。

例如,給定以下大小為2的元組:

Tuple2 tuple = new Tuple2("test", 10);
我們可以期待以下(良好類型)行為:

assert tuple.$0 == "test";
assert tuple.$1 == 10;
tuple.$0 = "ok";
tuple.$1--;
assert tuple.$0 == "ok";
assert tuple.$1 == 9;
元組類型都在jsweet.util.tuple包中定義(并且必須定義) 。默認情況下Tuple[2..6],定義了類。當在糖果API中遇到時,會自動生成其他元組(> 6)。當然,當需要在jsweet.util.tuple包中找不到更大的元組時,程序員可以根據需要在該包中添加自己的元組,只需遵循與現有元組相同的模板即可。

聯盟類型
聯合類型表示可能具有多個不同表示之一的值。當這種情況發生在方法簽名中時(例如,允許給定參數的幾種類型的方法),JSweet利用了Java中可用的方法重載機制。例如,以下m方法接受參數p,該參數可以是a String或a Integer。

public void m(String p) {...}
public void m(Integer p) {...}
在前一種情況下,不需要使用顯式聯合類型。對于更一般的情況,JSweet 在 包中定義了一個輔助接口 Union(和UnionN)jsweet.util.union。通過使用此輔助類型和union實用程序方法,程序員可以在union類型和union-ed類型之間來回轉換,以便JSweet可以確保與TypeScript聯合類型類似的屬性。

以下代碼顯示了JSweet中union類型的典型用法。它只是將一個變量聲明為一個字符串和一個數字之間的聯合,這意味著該變量實際上可以是其中一種類型(但沒有其他類型)。從聯合類型到常規類型的切換是通過jsweet.util.Lang.union輔助方法完成的。這個輔助方法是完全無類型的,允許從Java角度將任何聯合轉換為另一種類型。它實際上是JSweet轉換器,它檢查是否一直使用了union類型。

import static jsweet.util.Lang.union;
import jsweet.util.union.Union;
[...]
Union u = ...;
// u can be used as a String
String s = union(u);
// or a number
Number n = union(u);
// but nothing else
Date d = union(u); // JSweet error
如果union需要,也可以使用其他方式將助手從常規類型切換回聯合類型。

import static jsweet.util.Lang.union;
import jsweet.util.union.Union3;
[...]
public void m(Union3> u) { ... }
[...]
// u can be a String, a Number or a Date
m(union("a string"));
// but nothing else
m(union(new RegExp(".*"))); // compile error
注意:在鍵入函數參數時,優先使用Java函數重載而不是union類型。例如:

// with union types (discouraged)
native public void m(Union3> u);
// with overloading (preferred way)
native public void m(String s);
native public void m(Number n);
native public void m(Date d);
交叉類型
TypeScript定義了類型交集的概念。當類型相交時,意味著結果類型是更大的類型,它是所有相交類型的總和。例如,在TypeScript中, A & B對應于定義兩者A和B成員的類型。

由于許多原因,Java中的交集類型無法輕松實現。因此,這里做出的實際選擇是使用聯合類型代替交集類型。A & B因此,在JSweet中定義為 Union,這意味著程序員可以使用輔助方法訪問這兩者A和 B成員jsweet.util.Lang.union。它當然不如TypeScript版本方便,但它仍然是類型安全的。

語義
語義指定給定程序在執行時的行為方式。雖然JSweet依賴于Java語法,但程序被轉換為JavaScript并且不在JRE中運行。因此,與Java程序相比,JavaScript語義將影響JSweet程序的最終語義。在本節中,我們將通過關注Java / JavaSript和JSweet之間的差異或共性來討論語義。

主要方法
主要方法是程序執行入口點,并且在main評估包含方法的類時將全局調用。例如:

public class C {

private int n;
public static C instance;
public static void main(String[] args) {
    instance = new C();
    instance.n = 4;
}
public int getN() {
    return n;
}

}
// when the source file containing C has been evaluated:
assert C.instance != null;
assert C.instance.getN() == 4;
全局調用main方法的方式取決于程序的打包方式。有關詳細信息,請參閱附錄。

初始化器
初始化器的行為與Java類似。

例如:

public class C1 {

int n;
{
    n = 4;
}

}
assert new C1().n == 4;
與靜態初始化器類似:

public class C2 {

static int n;
static {
    n = 4;
}

}
assert C2.n == 4;
雖然在實例化類時會評估常規初始值設定項,但是為了避免前向依賴性問題而懶惰地評估靜態初始化程序,并模擬初始化程序的Java行為。使用JSweet,程序員可以定義靜態字段或靜態初始化程序,它依賴于尚未初始化的靜態字段。

有關此行為的更多詳細信息,請參閱附錄。

數組初始化和分配
數組可以像Java一樣使用。

String[] strings = { "a", "b", "c" };
assert strings[1] == "b";
指定維度時,數組是預先分配的(如Java中所示),因此它們使用正確的長度進行初始化,并在多維數組的情況下使用正確的子數組進行初始化。

String[][] strings = new String2;
assert strings.length == 2;
assert strings[0].length == 2;
strings0 = "a";
assert strings0 == "a";
通過強制轉換為def.js.Arraywith,可以在數組上使用JavaScript API jsweet.util.Lang.array。

import static jsweet.util.Lang.array;
[...]
String[] strings = { "a", "b", "c" };
assert strings.length == 3;
array(strings).push("d");
assert strings.length == 4;
assert strings[3] == "d";
在某些情況下,最好def.js.Array直接使用該類。

Array strings = new Array("a", "b", "c");
// same as: Array strings = array(new String[] { "a", "b", "c" });
// same as: Array strings = new Array(); strings.push("a", "b", "c");
assert strings.length == 3;
strings.push("d");
assert strings.length == 4;
assert strings.$get(3) == "d";
異步編程
在ES2015 + Promise API的幫助下,JSweet支持基本回調概念之外的高級異步編程。

承諾
通過聲明Promise返回類型來定義異步方法非常簡單 。當毫秒毫秒過去時,Promise將 滿足以下方法。

Promise delay(int millis) {
return new Promise((Consumer resolve, Consumer reject) -> {

setTimeout(resolve, millis);

});
}
然后,您可以在履行承諾后鏈接同步和異步操作。

delay(1000)
// chain with a synchronous action with "then". Here we just return a constant.
.then(() -> {

System.out.println("wait complete");
return 42;

})
// chain with an asynchronous action with "thenAsync". Here it is implied that anotherAsyncAction(String) returns a Promise<...>
.thenAsync((Integer result) -> {

System.out.println("previous task result: " + result); // will print "previous task result: 42"

return anotherAsyncAction("param");

})
// this chained action will be executed once anotherAsyncAction finishes its execution.
.then((String result) -> {

System.out.println("anotherAsyncAction returned " + result);

})
// catch errors during process using this method
.Catch(error -> {

System.out.println("error is " + error);

});
這允許完全類型安全和流暢的異步編程模型。

異步/ AWAIT
Promises非常有趣,以避免回調,但編寫它仍然需要大量的樣板代碼。它比純回調更好,但比線性編程更不易讀和直接。這就是async/await幫助的地方 。

使用await關鍵字,您可以告訴運行時等待 Promise實現,而無需編寫then方法。await“是” then部分之后的代碼。結果是您可以使用線性編程編寫異步代碼。

import static jsweet.util.Lang.await;

// wait for the Promise returned by the delay method to be fulfilled
await(delay(1000));

System.out.println("wait complete");
錯誤處理也是如此。您可以使用普通的 try / catch習語來處理異常。

import static jsweet.util.Lang.await;
import def.js.Error;

try {
Integer promiseResult = await(getANumber());
assert promiseResult == 42;
} catch(Error e) {
System.err.println("something unexpected happened: " + e);
}
你必須聲明為async每個異步方法/ lambda(即每個等待某事的方法)。

import static jsweet.util.Lang.await;
import static jsweet.util.Lang.async;
import static jsweet.util.Lang.function;

import jsweet.lang.Async;
import def.js.Function;

@Async
Promise findAnswer() {
await(delay(1000)); // won"t compile if the enclosing method isn"t @Async
return asyncReturn(42); // converts to Promise
}

@Async
void askAnswerThenVerifyAndPrintIt() {

try {

Integer answer = await(findAnswer());

// lambda expressions can be async
Function verifyAnswerAsync = async(function(() -> {
  return await(answerService.verifyAnswer(answer));
}))

Boolean verified = await(verifyAnswerAsync.$apply());

if (!verified) {
  throw new Error("cannot verify this answer");
}

console.log("answer found: " + answer);

} catch (Error e) {

console.error(e, "asynchronous process failed");

}
}
甜,不是嗎?;)

姓名沖突
與TypeScript / JavaScript相反,Java在方法,字段和包之間存在根本區別。Java還支持方法重載(具有相同名稱的不同簽名的方法)。在JavaScript中,對象變量和函數存儲在同一個對象映射中,這基本上意味著您不能為多個對象成員使用相同的密鑰(這也解釋了Java中無法實現Java語義中的方法重載)。因此,在TypeScript中生成時,某些Java代碼可能包含名稱沖突。JSweet將盡可能自動避免名稱沖突,并在其他情況下報告聲音錯誤。

方法和字段名稱沖突
JSweet執行轉換以自動允許方法和私有字段具有相同的名稱。另一方面,同一個類或具有子類鏈接的類中不允許使用相同名稱的方法和公共字段。

為了避免由于這種JavaScript行為導致編程錯誤,JSweet添加了一個語義檢查來檢測類中的重復名稱(這也考慮了在父類中定義的成員)。舉個例子:

public class NameClashes {

// error: field name clashes with existing method name
public String a;

// error: method name clashes with existing field name
public void a() {
    return a;
}

}
方法重載
與TypeScript和JavaScript相反(但與Java類似),JSweet中可能有多個具有相同名稱但具有不同參數的方法(所謂的重載)。我們區分了簡單的重載和復雜的重載。簡單重載是使用方法重載來定義可選參數。JSweet允許這個習慣用語,它對應于以下模板:

String m(String s, double n) { return s + n; }
// valid overloading (JSweet transpiles to optional parameter)
String m(String s) { return m(s, 0); }
在這種情況下,JSweet將生成JavaScript代碼,只有一個方法具有可選參數的默認值,因此生成的程序的行為對應于原始程序。在這種情況下:

function m(s, n = 0) { return s + n; }
如果程序員嘗試以不同方式使用重載,例如通過為同一方法名定義兩個不同的實現,JSweet將回退復雜的重載,包括生成根實現(包含更多參數的方法)和一個輔助實現per overloading方法(用表示方法簽名的后綴命名)。根實現是通用的,并通過測試給定參數的值和類型調度到其他實現。例如:

String m(String s, double n) { return s + n; }
String m(String s) { return s; }
生成以下(略微簡化的)JavaScript代碼:

function m(s, n) {

if(typeof s === "string" && typeof n === "number") {
    return s + n;
} else if(typeof s === "string" && n === undefined) {
    return this.m$java_lang_String(s);
} else {
    throw new Error("invalid overload");
}

}

function m$java_lang_String(s) { return s; }
局部變量名稱
在TypeScript / JavaScript中,局部變量可能與使用全局方法沖突。例如,使用alertDOM(jsweet.dom.Globals.alert)中的全局方法要求沒有局部變量隱藏它:

import static jsweet.dom.Globals.alert;

[...]

public void m1(boolean alert) {

// JSweet compile error: name clash between parameter and method call
alert("test");

}

public void m2() {

// JSweet compile error: name clash between local variable and method call
String alert = "test";
alert(alert);

}
請注意,在調用全局方法時使用完全限定名稱時也會發生此問題(這是因為限定條件在TypeScript / JavaScript中被刪除)。在任何情況下,JSweet都會在發生此類問題時報告聲音錯誤,以便程序員可以調整局部變量名稱以避免與全局變量發生沖突。

測試對象的類型
要在運行時測試給定對象的類型,可以使用instanceofJava運算符,也可以使用 Object.getClass()函數。

instanceof
這instanceof是在運行時測試類型的建議和首選方法。JSweet將transpile到常規instanceof或一個 typeof取決于所測試的類型的操作(這將在回退 typeof對number,string和boolean核心類型)。

盡管不是必需的,但也可以使用實用方法直接使用typeof JSweet中的運算符jsweet.util.Lang.typeof。以下是有效類型測試的一些示例:

import static jsweet.util.Lang.typeof;
import static jsweet.util.Lang.equalsStrict;
[...]
Number n1 = 2;
Object n2 = 2;
int n3 = 2;
Object s = "test";
MyClass c = new MyClass();

assert n1 instanceof Number; // transpiles to a typeof
assert n2 instanceof Number; // transpiles to a typeof
assert n2 instanceof Integer; // transpiles to a typeof
assert !(n2 instanceof String); // transpiles to a typeof
assert s instanceof String; // transpiles to a typeof
assert !(s instanceof Integer); // transpiles to a typeof
assert c instanceof MyClass;
assert typeof(n3) == "number";
從JSweet版本1.1.0開始,instanceof接口上也允許運算符,因為JSweet會跟蹤所有對象的所有實現接口。通過調用的對象中的附加隱藏屬性來確保此接口跟蹤,__interfaces并且包含對象實現的所有接口的名稱(直接或通過在編譯時確定的類繼承樹)。因此,如果instanceof 運算符的類型參數是接口,JSweet只是檢查對象的 __interfaces字段是否存在并包含給定的接口。例如,當Point接口是這個代碼在JSweet中完全有效:

Point p1 = new Point() {{ x=1; y=1; }};
[...]
assert p1 instanceof Point
Object.getClass() 和 X.class
在JSweet中,可以使用Object.getClass()on any實例。它實際上將返回類的構造函數。X.class如果X是類,using 也將返回構造函數。因此,以下斷言將在JSweet中保留:

String s = "abc";
assert String.class == s.getClass()
在課堂上,您可以調用getSimpleName()或getName()函數。

String s = "abc";
assert "String" == s.getClass().getSimpleName()
assert String.class.getSimpleName() == s.getClass().getSimpleName()
請注意,getSimpleName()或者getName()函數也適用于接口。但是,您必須知道,X.class如果X是接口,將以字符串形式編碼(保存接口的名稱)。

限制和約束
由于所有數字都映射到JavaScript數字,因此JSweet不區分整數和浮點數。因此, 無論實際類型是什么n instanceof Integer,n instanceof Float都會給出相同的結果n。對于字符串和字符存在相同的限制,這些字符串和字符在運行時無法區分,但也適用于具有相同參數數量的函數。例如,一個實例IntFunction將無法在運行時與a區分開Function。

這些限制對函數重載有直接影響,因為重載使用instanceof運算符來決定調用哪個重載。

就像在JavaScript中工作時一樣,序列化對象必須與其實際類正確“復活”,以便 instanceof操作員可以再次工作。例如,通過創建的點對象Point p = (Point)JSON.parse("{x:1,y:1}")不會對instanceof運算符起作用。如果您遇到這樣的用例,您可以聯系我們獲取一些有用的JSweet代碼以正確恢復對象類型。

lambda表達式中的變量作用域
已知JavaScript變量作用域給程序員帶來了一些問題,因為可以從使用此變量的lambda外部更改對變量的引用。因此,JavaScript程序員不能依賴于在lambda范圍之外聲明的變量,因為當執行lambda時,該變量可能已在程序中的其他位置被修改。例如,以下程序顯示了一個典型案例:

NodeList nodes = document.querySelectorAll(".control");
for (int i = 0; i < nodes.length; i++) {

HTMLElement element = (HTMLElement) nodes.$get(i); // final
element.addEventListener("keyup", (evt) -> {
    // this element variable will not change here
    element.classList.add("hit");
});

}
在JavaScript中(注意EcmaScript 6修復了這個問題),這樣的程序將無法實現其目的,因為element事件監聽器中使用的變量被for循環修改并且不保持期望值。在JSweet中,這些問題與最終的Java變量類似。在我們的示例中,element變量在lambda表達式中重新定義,以便封閉循環不會更改其值,因此程序的行為與Java類似(正如大多數程序員所預期的那樣)。

這個范圍
與JavaScript相反,與Java類似,將方法用作lambda將防止丟失對引用的引用this。例如,在action以下程序的方法中this,即使在方法中action被稱為lambda 時,也保持正確的值main。雖然這對Java程序員來說似乎是合乎邏輯的,但JavaScript語義并不能確保這種行為。

package example;
import static jsweet.dom.Globals.console;

public class Example {

private int i = 8;
public Runnable getAction() {
    return this::action;
}
public void action() {
    console.log(this.i); // this.i is 8
}
public static void main(String[] args) {
    Example instance = new Example();
    instance.getAction().run();
}

}
重要的是要強調this通過與ES5 bind功能類似的機制確保正確的值。結果是函數引用被包裝在函數中,這意味著函數指針(例如this::action)動態地創建包裝函數。它在操作函數指針時有副作用,這個問題在本期https://github.com/cincheo/js... 。

打包
打包是JavaScript的復雜點之一,尤其是來自Java時。JavaScript包裝的復雜性歸結為JavaScript本身沒有定義任何包裝這一事實。因此,多年來出現了許多事實上的解決方案和指南,使得對常規Java程序員的包裝理解不安。JSweet提供了有用的選項并生成代碼,以便通過使包裝問題更加透明和大多數情況下的Java“簡單”來簡化Java程序員的生活。在本節中,我們將描述和解釋典型的包裝方案。

使用您的文件,無需任何包裝
運行程序最常見和最簡單的情況就是將每個生成的文件包含在HTML頁面中。這不是任何包裝選項的默認模式。例如,當您的程序定義兩個類x.y.z.A并x.y.z.B在兩個多帶帶的文件中時,您可以按如下方式使用它們:



[...]


這樣做時,程序員需要非常謹慎,以避免文件之間的正向靜態依賴關系。換句話說,A 類不能B在靜態字段,靜態初始化程序或靜態導入中使用任何內容,否則在嘗試加載頁面時會導致運行時錯誤。此外,A該類不能擴展B該類。這些約束來自JavaScript / TypeScript,與JSweet無關。

可以想象,使用這種手動技術運行簡單的程序很好,但是對于開發復雜的應用程序會變得非常不舒服。復雜的應用程序大多數時候使用適當的工具捆綁和/或打包程序,以避免必須手動處理JavaScript文件之間的依賴關系。

為瀏覽器創建捆綁包
為了避免必須手動處理依賴項,程序員使用捆綁工具將其類捆綁到一個文件中。這樣的包使用以下內容包含在任何網頁中:


[...]


JSweet帶有這樣的捆綁設施。要創建一個包文件,只需設定true的bundleJSweet的選項。請注意,您還可以設置true的declaration,詢問JSweet生成打字稿定義文件(可選bundle.d.ts)。此文件允許您以類型合適的方式使用/編譯來自TypeScript的JSweet程序。

JSweet捆綁選項的“神奇之處”在于它分析源代碼中的依賴關系,并在構建捆綁時負責解決前向引用。特別是,JSweet為靜態字段和初始化器實現了一個惰性初始化機制,以便分解跨類的靜態前向引用。程序員沒有具體的附加聲明使其工作(與TypeScript相反)。

請注意,它仍然存在一些小的限制(例如,在使用內部和匿名類時),但很少遇到這些限制,并且將在以后的版本中刪除。

另請注意,如果您隨module 選項一起指定選項,JSweet將引發錯誤bundle。

包裝模塊
首先,讓我們從解釋模塊開始,重點關注Java 包(或TypeScript 命名空間)和模塊之間的區別。如果您對差異感到滿意,請跳過此部分。

包和模塊是兩個相似的概念,但適用于不同的上下文。必須將Java包理解為編譯時命名空間。它們允許通過名稱路徑對程序進行編譯時結構化,具有隱式或顯式可見性規則。軟件包通常對程序實際捆綁和部署的方式影響不大。

必須將模塊理解為部署/運行時“捆綁”,這可以required由其他模塊實現。與Java世界中最接近模塊的概念可能是OSGi包。模塊定義導入和導出的元素,以便它們創建強大的運行時結構,可用于獨立部署軟件組件,從而避免名稱沖突。例如,對于模塊,兩個不同的庫可以定義一個util.List類,并且實際上在同一個VM上運行和使用,沒有命名問題(只要庫被捆綁在不同的模塊中)。

如今,許多庫都是通過模塊打包和訪問的。在瀏覽器中使用模塊的標準方法是AMD,但在Node.js中它是commonjs模塊系統。

JSweet中的模塊
JSweet支持用于打包的AMD,commonjs和UMD模塊系統。JSweet定義了一個module選項(值:amd,commonjs或umd)。指定此選項時,JSweet會根據簡單規則自動創建默認模塊組織:一個文件=一個模塊。

例如,當將module選項設置為打包時commonjs,可以編寫:

node target/js/x/y/z/MyMainClass.js
哪里MyMainClass包含main方法。

模塊系統將自動處理參考,并在需要時需要其他模塊。在引擎蓋下,JSweet分析了Java import語句并將它們轉換為require指令。

注意:一旦使用該module選項編譯程序,就可以使用適當的工具(如Browserify)將其打包為捆綁包,這樣可以提供與使用bundleJSweet選項類似的輸出。還要注意,同時指定時JSweet會引發錯誤module和bundle,這是排斥的選項。

外部模塊
使用module選項編譯JSweet程序時,必須將所有外部庫和組件作為外部模塊。只需使用@Module(name) 注釋,JSweet就可以自動需要模塊。在JSweet中,導入或使用帶有注釋的類或成員@Module(name)將在運行時自動需要相應的模塊。請注意,只有使用該module選項生成代碼時才會出現這種情況。如果該module選項處于禁用狀態,@Module 則會忽略注釋。

package def.jquery;
public final class Globals extends def.js.Object {

...
@jsweet.lang.Module("jquery")
native public static def.jquery.JQuery $(java.lang.String selector);
...

}
上面的代碼顯示了JSweet jQuery API的摘錄。我們可以注意到,該$函數帶有注釋@Module("jquery")。因此,對此函數的任何調用都將觸發jquery模塊的要求 。

注意:未來版本中可能會提供模塊的手動要求概念。但是,自動需求對于大多數程序員來說已經足夠,并且隱藏了必須明確要求模塊的復雜性。無論是否使用模塊,它還具有使用相同代碼的優點。

故障排除:當糖果沒有正確定義@Module 注釋時,可以在一個名為的特殊文件的注釋中強制聲明module_defs.java。例如,要強制將BABYLONBabylonjs candy 的 名稱空間導出為 babylonjs模塊,可以編寫以下文件:

package myprogram;
// declare module "babylonjs" {
// export = BABYLON;
// }
請注意,JSweet項目只能定義一個module_defs.java文件,該文件應包含注釋中的所有模塊聲明。另請注意,這是一個黑客攻擊,首選方法是為糖果做出貢獻來解決問題。

根包
Root包是一種調整生成的代碼的方法,以便在生成的代碼中擦除JSweet包,從而在運行時刪除。要設置根包,只需定義一個package-info.java文件并使用@Root 包上的注釋,如下所示:

@Root
package a.b.c;
上述聲明意味著該c包是一個根包,即它將在生成的代碼及其所有父包中被刪除。因此,如果c包含一個包d和一個類C,它們將是運行時的頂級對象。換句話說,a.b.c.d成為 d,a.b.c.C變成C。

請注意,由于在封裝之前放置的@Root封裝被擦除,因此在封裝之前不能定義任何類型@Root。在前面的示例中,a和b包必須是空包。

不使用模塊時的行為(默認)
默認情況下,root包不會更改生成的文件的文件夾層次結構。例如,a.b.c.C該類仍將在/a/b/c/C.js文件中生成(相對于 輸出目錄)。但是,打開該noRootDirectories選項將刪除根目錄,以便為該文件a.b.c.C生成類/C.js。

不使用模塊時(默認),可以有多個@Root 包(但@Root包不能包含另一個@Root 包)。

使用模塊時的行為
使用模塊時(請參閱模塊選項),只@Root允許一個@Root包,當有一個包時,其他包或類型不能超出該@Root包的范圍。然后,生成的文件夾/文件層次結構從根包開始,以便實際擦除之前的所有文件夾。

包裝JSweet jar(糖果)
糖果是一種Maven工件,包含從JSweet客戶端程序輕松訪問JavaScript庫所需的所有內容。該庫可以是外部JavaScript庫,TypeScript程序或其他JSweet程序。

糖果的解剖學

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75287.html

相關文章

  • jsweet英文文檔java代碼js代碼

    摘要:例如允許的對象默認情況下,通過使用內置宏將核心對象和方法映射到。例如這被轉換為以下代碼類可以定義構造函數,具有超類,并且可以像在中一樣實例化。因此,它不違反原則。用于聲明該對象可以用作構造函數。 這個工具可以將java代碼轉為js代碼,從而可以使用java編寫前端代碼 如果排版看著費勁可以下載下方html,打開html后使用google翻譯 JSweet語言規范版本:2.x(快照) 作...

    Near_Li 評論0 收藏0
  • :從框架看PHP的五種境界及各自的薪資待遇

    摘要:語言行為及特征狀態看不懂任何英語技術,英語文檔,凡事沒有培訓部在搞的,只有英文文檔的東西國內一律沒大公司在用,都非主流,排斥英文文檔和新技術,以及各種超出他學習能力范圍的技術。 在撰寫此文前首先必須申明的是本人不鄙視任何一種框架,也無意于挑起PHP框架間的戰爭,更沒有貶低某個框架使用者的用意,本文純粹個人的看法。你可以認為我無知也好,或者裝逼也好,請不要試著在任何情況下,隨便發起言語的...

    Godtoy 評論0 收藏0
  • MDN搜索結果自動跳中文地址

    摘要:每次都是自己手動切換下中文顯示。需求分析點擊英文的搜索結果自動跳轉到中文文檔地址。其實我要做的也很簡單,就是在頁面加載的時候,使表單選擇中文簡體然后重新提交一次表單即可。解決方案解決方案就是使用代碼選擇中文簡體并且提交表單。 MDN社區(即Mozilla開發者社區)具有很多高質量中英文文檔。它是我開發時遇到概念模糊的地方經常訪問的網站。因為默認搜索一些代碼,優先顯示的都是英文。但是恰恰...

    monw3c 評論0 收藏0
  • 程序員如何自我學習?阿里資深技術專家這樣做

    摘要:而程序員和醫生律師的不同點在于持續學習上。兩個小問題是需要收費,一年大概刀圖書都是英文的。的視頻基本都有英文字幕,配合作者的,英語不好的同學學習也沒有問題。英文好的有技術功底的同學多發表一些觀點,其他的同學都 摘要: 行業發展得太快,你必須學習,純靠經驗積累行不通,技術淘汰的速度遠大于你經驗積累的速度。 非雞湯:不要和程序員談自己的編程歷史,很多的經驗在今天已經不適用了。只要2-3年...

    Jacendfeng 評論0 收藏0
  • Chrome擴展插件練習——書簽管理

    摘要:代碼代碼戳這里插件預備知識首先給出一本參考的中文書籍,在練習的過程中有幫到忙。你還可以重寫別的頁面,比如書簽管理頁面等,可以參考文檔中文翻譯過來應該叫內容腳本,它可以運行在你指定的頁面之中,可以拿到指定頁面的一些信息。 前言 這是一篇關于Chrome擴展插件入門、Vue.js入門的小練習,功能是:在當前瀏覽的頁面點擊擴展圖標,并點擊保存之后,該頁面就會存在你的新標簽頁中。其實就是一個可...

    lingdududu 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<