JavaScript語法

JavaScript是編寫該語言程式的一套規則。JavaScript標準庫缺少官方標準串流函式。由於JavaScript主要用於現代網頁瀏覽器上執行客戶端指令碼，幾乎所有瀏覽器都支援codice_2函式。下列範例中使用標準文字輸出的console物件的log函式。起源.布蘭登·艾克在JavaScript 1.1 規範的第一段中總結如下：JavaScript從Java借來了大部分語法，但也從Awk和Perl繼承，在其物件原型系統中還受到 Self 的一些間接影響。基礎.大小寫敏感.JavaScript是大小寫敏感的。經常以一個大寫字母開始建構函式的名稱 ，一個小寫字母開始函式或變數的名字。例子：var a = 5;console.log(a); // 5console.log(A); // throws a ReferenceError: A is not defined空白和分號.不像在C語言中，JavaScript原始碼中的空白可以直接影響形式語義學。JavaScript裡的語句用分號結束。因為自動分號插入，也就是說，一些符合語法規則的的語句在分析到換行符時會被認為是完整的，如同在換行符前面插入了一個分號。一些當局建議顯式地寫結束語句的分號，因為它也許會減少自動分號插入未曾預料的效果。有兩個問題：有五個符記既能開始一條語句，也能擴充套件一條完整的語句；以及五個受限的語句，其中換行在一些位置不被允許，潛在可能會產生不正確的解析。五個有問題的符記是左圓括號“codice_3”，左方括號“codice_4”，斜線“codice_5”，加號“codice_6”，減號“codice_7”。當然，左圓括號在立即呼叫函式表示式模式中很常見，左方括號有時出現，其他幾個就很少了。規範中給出的示例是：a = b + c// Treated as:// a = b + c(d + e).foo();有建議前面的語句以分號結束。有些人建議在以“codice_3”或“codice_4”開始的行，使用"前導"分號，讓這行不會意外地與上一行連線。這被稱為防禦性分號，特別推薦，因為否則在重新排列程式碼時可能變得模稜兩可。例如：a = b + c// Treated as:// a = b + c(d + e).foo();最初的分號有時也在JavaScript庫中使用，在它們被追加到另一個省略尾部分號的庫的情況下，因為這可能會導致初始語句的模糊不清。五個受限的語句是codice_10，codice_11，codice_12，codice_13，和後導遞增或遞減。在所有情況裡，插入分號不會解決問題，但使得解析的語法更加清晰，錯誤更加容易檢測。codice_10 和 codice_11 取一個可選的值，codice_12 和 codice_13 取一個可選的標籤。所有情況下，都建議使值或標籤和語句保持在一行上。最多的情況是返回語句，一個人可能想返回一個大的物件文字，它可能意外地被放在了新行上。對於後導遞增或遞減，有可能與字首遞增或遞減模稜兩可，所以再一次推薦把這些放在同一行。returna + b;// Returns undefined. Treated as:// return;// a + b;// Should be written as:// return a + b;註釋.註釋語法和C++,Swift,和許多其他程式語言相同。// a short, one-line comment/* this is a long, multi-line commentabout my script. May it one daybe great. *//* Comments /* may not be nested */ Syntax error */變數.標準JavaScript中的變數沒有附加型別，因此任何值開始，變數可以用codice_18宣告函式範圍變數，而codice_19或codice_20用於塊級變數。在ES6之前，變數只能用codice_18語句宣告。分配給用codice_20宣告的變數的值不能更改，但其屬性可以。變數的識別符號必須以字母、下劃線 (codice_23) 或美元符號 (codice_24) 開頭，而後續字元也可以是數字 (codice_25)。JavaScript區分大小寫，因此大寫字元“A”到“Z”與小寫字元“a”到“z”不同。從JavaScript1.5 開始，可以在識別符號中使用ISO 8859-1或Unicode字元。在某些JavaScript實現中，可以在識別符號中使用at符號 (@)，但這與規範相反，並且在較新的實現中不受支援。作用域和提升.用codice_18宣告的變數是在函式級別的詞法作用域，而用codice_19或codice_20宣告的變數具有塊級作用域。由於宣告是在任何程式碼執行之前處理的，因此可以在程式碼中宣告之前分配和使用變數。這被稱為提升(hoisting)，它相當於在函式或塊的頂部前向宣告的變數。對於codice_18、codice_19和codice_20語句，只有宣告被提升；賦值未被提升。因此，函式中間的語句等效於函式頂部的宣告語句，以及函式中間該點的賦值語句。這意味著值在宣告之前不能被訪問；前向引用(forward reference)是不可能的。使用codice_18變數的值在初始化之前是未定義的(codice_34)。使用codice_19或codice_20宣告的變數在初始化之前無法訪問，因此之前引用此類變數會導致錯誤。函式宣告，它宣告一個變數併為其分配一個函式，類似於變數語句，但除了可以提升宣告之外，它們還提升了賦值——就好像整個語句出現在包含的函式的頂部一樣——因此前向引用(forward reference)也是允許的：函式語句在包含它的函式中的位置是不相關的。這不同於在codice_18、codice_19或codice_20語句中將函式表示式賦值給變數。因而，如：var func = function() { .. } // 僅提升宣告function func() { .. } // 宣告和賦值被提升塊作用域可以透過將整個塊包裝在一個函式中然後執行它來產生——這被稱為立即呼叫函式表示式模式——或者透過使用codice_19關鍵字宣告變數。宣告和賦值.在作用域外宣告的變數是全域性變數。如果一個變數在更高的作用域中宣告，它可以被子作用域(child scope)訪問。當JavaScript嘗試解析識別符號時，它會在本地作用域內查詢。如果沒有找到這個識別符號，它會在下一個外部作用域中查詢，依此類推，直到抵達全域性變數所在的全域性作用域。如果仍未找到，JavaScript將引發codice_41異常。給識別符號賦值時，JavaScript會透過完全相同的過程來獲取此識別符號；但如果在全域性範圍內找不到它，將在建立的作用域內建立“變數”。因此，如果給未宣告的變數賦值，會被建立為一個全域性變數。在全域性範圍內新增一個屬性，這將建立一個新的全域性變數。請注意，JavaScript的嚴格模式(strict mode)禁止給未宣告的變數賦值，從而避免了全域性名稱空間汙染。例子.變數宣告和作用域的一些例子：var x1 = 0; // 一個全域性變數，因為未在任何函式內let x2 = 0; // 也是全域性變數，因為未在任何塊內function f() {var z = 'foxes', r = 'birds'; // 2個區域性變數m = 'fish'; //全域性變數，因為給未宣告的變數賦值function child() {var r = 'monkeys'; //為區域性變數，不影響父函式中變數r的值"birds"z = 'penguins'; //閉包：子函式也能訪問父函式中的變數twenty = 20; //該變數在下一行宣告，但在該函式內任何位置都可用，這裡是在宣告之前使用var twenty;child();return x1 + x2; //這裡使用的x1和x2是全域性變數f();console.log(z); // 這將丟擲ReferenceError異常，因為z不可用了for (let i = 0; i  0) {this.pyz = function() { return this.prefix + "Y"; };} else {this.pyz = function() { return this.prefix + "Z"; };this.m1 = px;return this;var foo1 = new Foo(1);var foo2 = new Foo(0);foo2.prefix = "b-";console.log("foo1/2 " + foo1.pyz() + foo2.pyz());// foo1/2 a-Y b-Zfoo1.m3 = px; // Assigns the function itself, not its evaluated result, i.e. not px()var baz = {"prefix": "c-"};baz.m4 = px; // No need for a constructor to make an object.console.log("m1/m3/m4 " + foo1.m1() + foo1.m3() + baz.m4());// m1/m3/m4 a-X a-X c-Xfoo1.m2(); // Throws an exception, because foo1.m2 doesn't exist.建構函式.建構函式只需將值分配給新建立物件的槽。 這些值可以是資料或其他函式。示例：操作物件：function MyObject(attributeA, attributeB) {this.attributeA = attributeA;this.attributeB = attributeB;MyObject.staticC = "blue"; // On MyObject Function, not objectconsole.log(MyObject.staticC); // blueobject = new MyObject('red', 1000);console.log(object.attributeA); // redconsole.log(object["attributeB"]); // 1000console.log(object.staticC); // undefinedobject.attributeC = new Date(); // add a new propertydelete object.attributeB; // remove a property of objectconsole.log(object.attributeB); // undefineddelete object; // remove the whole Object (rarely used)console.log(object.attributeA); // throws an exception建構函式本身在物件原型的“建構函式”槽中被引用。 所以，// Use of 'new' sets prototype slots (for example,// x = new Foo() would set x's prototype to Foo.prototype,// and Foo.prototype has a constructor slot pointing back to Foo).x = new Foo();// The above is almost equivalent toy = {};y.constructor = Foo;y.constructor();// Exceptx.constructor == y.constructor // truex instanceof Foo // truey instanceof Foo // false// y's prototype is Object.prototype, not// Foo.prototype, since it was initialised with// {} instead of new Foo.// Even though Foo is set to y's constructor slot,// this is ignored by instanceof - only y's prototype's// constructor slot is considered.函式本身就是物件，可以用來產生類似於“靜態屬性”物件刪除很少使用，因為指令碼引擎將垃圾收集不再被引用的物件。繼承.JavaScript以Self的方式透過原型設計(prototyping)支援繼承層次結構。在以下示例中，#重定向 類繼承自 #重定向 類。當#重定向 建立為#重定向 時，對#重定向 基礎例項的引用被複制到 #重定向 。Derive不包含#重定向 的值，因此在訪問#重定向 時從#重定向 檢索它。 這可以透過改變#重定向 的值來明確，這反映在#重定向 的值中。一些實現允許使用#重定向 槽顯式訪問或設定原型，如下所示。function Base() {this.anOverride = function() { console.log("Base::anOverride()"); };this.aBaseFunction = function() { console.log("Base::aBaseFunction()"); };function Derived() {this.anOverride = function() { console.log("Derived::anOverride()"); };base = new Base();Derived.prototype = base; // Must be before new Derived()Derived.prototype.constructor = Derived; // Required to make `instanceof` workd = new Derived(); // Copies Derived.prototype to d instance's hidden prototype slot.d instanceof Derived; // trued instanceof Base; // trued.anOverride(); // Derived::anOverride()d.aBaseFunction(); // Base::aNEWBaseFunction()console.log(d.aBaseFunction == Derived.prototype.aBaseFunction); // trueconsole.log(d.__proto__ == base); // true in Mozilla-based implementations and false in many others.下面清楚地顯示了在例項建立時對原型的引用是如何“複製”的，但是對原型的更改會影響引用它的所有例項。Base.prototype.m = m2;bar = new Base();console.log("bar.m " + bar.m()); // bar.m Twot = new Top();foo = new Base();Base.prototype = t;// No effect on foo, the *reference* to t is copied.console.log("foo.m " + foo.m()); // foo.m Twobaz = new Base();console.log("baz.m " + baz.m()); // baz.m Threet.m = m1; // Does affect baz, and any other derived classes.console.log("baz.m1 " + baz.m()); // baz.m1 One在實踐中，使用了這些主題的許多變體，它可能既強大又令人困惑。異常處理.JavaScript 包含一個codice_120異常處理 語句來處理執行時錯誤。codice_120語句捕獲由錯誤或 throw 語句導致的異常。 它的語法如下：try {// Statements in which exceptions might be thrown} catch(errorValue) {// Statements that execute in the event of an exception} finally {// Statements that execute afterward either way最初，try塊中的語句執行。如果丟擲異常，指令碼的控制流會立即轉移到catch塊中的語句，異常可用作錯誤引數。否則將跳過catch塊。 如果catch塊不想處理特定錯誤，它可以 #重定向 。在任何情況下，finally塊中的語句都會被執行。這可用於釋放資源，儘管記憶體會自動進行垃圾回收。可以省略catch或finally子句。 catch引數是必需的。Mozilla實現允許多個catch語句，作為對ECMAScript標準的擴充套件。它們遵循類似於Java中使用的語法：在瀏覽器中，#重定向 比捕獲異常更常用。onerror = function (errorValue, url, lineNr) {...; return true;};本地函式與方法.與網頁瀏覽器不相關。eval (表示式).將第一個引數計算為表示式，其中可以包括賦值語句。 表示式可以引用函式的區域性變數。 但是，代表了主要的安全風險，因為它允許不良行為者執行任意程式碼，因此不鼓勵使用它。var x = 7;console.log("val " + eval("x + 2"));