JavaScript 的應用場合極其普遍。簡單到幻燈片、照片庫、浮動佈局和響應按鈕點擊。複雜到遊戲、2D 和 3D 動畫、大型數據庫驅動程序,等等。javascript
JavaScript 至關簡潔,卻很是靈活。開發者們基於 JavaScript 核心編寫了大量實用工具,可使 開發工做事半功倍。其中包括:java
在應用程序中,使用變量來做爲值的符號名。變量的名字又叫作標識符,其須要遵照必定的規則。數據庫
一個 JavaScript 標識符必須以字母、下劃線(_)或者美圓符號($)開頭;後續的字符也能夠是數字(0-9)。由於 JavaScript 語言是區分大小寫的,因此字母能夠是從「A」到「Z」的大寫字母和從「a」到「z」的小寫字母。編程
變量 | 解釋 |
---|---|
string | 字符串(一串文本)。字符串的值必須將用引號(單雙都可,必須成對)擴起來。 |
Number | 數字。無需引號。 |
Boolean | 布爾值(真 / 假)。 true/false 是 JS 裏的特殊關鍵字,無需引號。 |
Array | 數組,用於在單一引用中存儲多個值的結構 |
Object | 對象,JavaScript 裏一切皆對象,一切皆可儲存在變量裏。這一點要牢記於心。 |
字符串轉換爲數字
有一些方法能夠將內存中表示一個數字的字符串轉換爲對應的數字。parseInt()和parseFloat()json
parseInt 方法只能返回整數,因此使用它會丟失小數部分。另外,調用 parseInt 時最好老是帶上進制(radix) 參數,這個參數用於指定使用哪種進制。數組
將字符串轉換爲數字的另外一種方法是使用一元加法運算符。瀏覽器
"1.1" + "1.1" = "1.11.1" (+"1.1") + (+"1.1") = 2.2 // 注意:加入括號爲清楚起見,不是必需的。
var 聲明全局變量和局部變量
let 聲明塊做用域的局部變量
const 聲明一個常量app
使用var和let聲明的變量時沒有賦予初始值的,其值爲undefined,框架
var a; console.log("The value of a is " + a); // a 的值是 undefined console.log("The value of b is " + b);// b 的值是 undefined var b; console.log("The value of c is " + c); // 未捕獲的引用錯誤: c 未被定義 let x; console.log("The value of x is " + x); // x 的值是 undefined console.log("The value of y is " + y);// 未捕獲的引用錯誤: y 未被定義 let y;
你可使用 undefined 來判斷一個變量是否已賦值。在如下的代碼中,變量input未被賦值,所以 if 條件語句的求值結果是 true異步
var input; if(input === undefined){ doThis(); } else { doThat(); }
var n = null; console.log(n * 32); // 在控制檯中會顯示 0
在函數以外聲明的變量,叫作全局變量,由於它可被當前文檔中的任何其餘代碼所訪問。在函數內部聲明的變量,叫作局部變量,由於它只能在當前函數的內部訪問。
ECMAScript 6 以前的 JavaScript 沒有 語句塊 做用域;相反,語句塊中聲明的變量將成爲語句塊所在函數(或全局做用域)的局部變量。例如,以下的代碼將在控制檯輸出 5,由於 x 的做用域是聲明瞭 x 的那個函數(或全局範圍),而不是 if 語句塊。
if (true) { var x = 5; } console.log(x); // 5
若是使用 ECMAScript 6 中的 let 聲明,上述行爲將發生變化。
if (true) { let y = 5; } console.log(y); // ReferenceError: y 沒有被聲明
JavaScript 變量的另外一個不一樣尋常的地方是,你能夠先使用變量稍後再聲明變量而不會引起異常。這一律念稱爲變量提高;JavaScript 變量感受上是被「提高」或移到了函數或語句的最前面。可是,提高後的變量將返回 undefined 值。所以在使用或引用某個變量以後進行聲明和初始化操做,這個被提高的變量仍將返回 undefined 值。
/** * 例子1 */ console.log(x === undefined); // true var x = 3; /** * 例子2 */ // will return a value of undefined var myvar = "my value"; (function() { console.log(myvar); // undefined var myvar = "local value"; })(); //詳細解釋就是 /** * 例子1 */ var x; console.log(x === undefined); // true x = 3; /** * 例子2 */ var myvar = "my value"; (function() { var myvar; console.log(myvar); // undefined myvar = "local value"; })();
因爲存在變量提高,一個函數中全部的var語句應儘量地放在接近函數頂部的地方。這個習慣將大大提高代碼的清晰度。
在 ECMAScript 6 中,let(const)將不會提高變量到代碼塊的頂部。所以,在變量聲明以前引用這個變量,將拋出引用錯誤(ReferenceError)。這個變量將從代碼塊一開始的時候就處在一個「暫時性死區」,直到這個變量被聲明爲止。
console.log(x); // ReferenceError let x = 3;
對於函數來講,只有函數聲明會被提高到頂部,而函數表達式不會被提高。
/* 函數聲明 */ foo(); // "bar" function foo() { console.log("bar"); } /* 函數表達式 */ baz(); // 類型錯誤:baz 不是一個函數 var baz = function() { console.log("bar2"); };
你能夠用關鍵字 const 建立一個只讀的常量。常量標識符的命名規則和變量相同:必須以字母、下劃線(_)或美圓符號($)開頭並能夠包含有字母、數字或下劃線。
const PI = 3.14;
常量不能夠經過從新賦值改變其值,也不能夠在代碼運行時從新聲明。它必須被初始化爲某個值。
常量的做用域規則與 let 塊級做用域變量相同。若省略const關鍵字,則該標識符將被視爲變量。
在同一做用域中,不能使用與變量名或函數名相同的名字來命名常量。
然而,對象屬性被賦值爲常量是不受保護的,因此下面的語句執行時不會產生錯誤。
const MY_OBJECT = {"key": "value"}; MY_OBJECT.key = "otherValue";
一樣的,數組的被定義爲常量也是不受保護的,因此下面的語句執行時也不會產生錯誤。
const MY_ARRAY = ['HTML','CSS']; MY_ARRAY.push('JAVASCRIPT'); console.log(MY_ARRAY); //logs ['HTML','CSS','JAVASCRIPT'];
譯註:字面量是由語法表達式定義的常量;或,經過由必定字詞組成的語詞表達式定義的常量
在JavaScript中,你可使用各類字面量。這些字面量是腳本中按字面意思給出的固定的值,而不是變量。(譯註:字面量是常量,其值是固定的,並且在程序腳本運行中不可更改
數組字面值是一個封閉在方括號對([])中的包含有零個或多個表達式的列表,其中每一個表達式表明數組的一個元素。當你使用數組字面值建立一個數組時,該數組將會以指定的值做爲其元素進行初始化,而其長度被設定爲元素的個數。
下面的示例用3個元素生成數組coffees,它的長度是3。
var coffees = ["French Roast", "Colombian", "Kona"]; var a=[3]; console.log(a.length); // 1 console.log(a[0]); // 3 //注意 這裏的數組字面值也是一種對象初始化器。
若在頂層(全局)腳本里用字面值建立數組,JavaScript語言將會在每次對包含該數組字面值的表達式求值時解釋該數組。另外一方面,在函數中使用的數組,將在每次調用函數時都會被建立一次。
數組字面值同時也是數組對象。有關數組對象的詳情請參見數組對象一文。
數組字面值中的多餘逗號
(譯註:聲明時)你沒必要列舉數組字面值中的全部元素。若你在同一行中連寫兩個逗號(,),數組中就會產生一個沒有被指定的元素,其初始值是undefined。如下示例建立了一個名爲fish的數組:
var fish = ["Lion", , "Angel"];
在這個數組中,有兩個已被賦值的元素,和一個空元素(fish[0]是"Lion",fish[1]是undefined,而fish[2]是"Angel";譯註:此時數組的長度屬性fish.length是3)。
若是你在元素列表的尾部添加了一個逗號,它將會被忽略。在下面的例子中,數組的長度是3,並不存在myList[3]這個元素(譯註:這是指數組的第4個元素噢,做者是在幫你們複習數組元素的排序命名方法)。元素列表中其它全部的逗號都表示一個新元素(的開始)。
注意:尾部的逗號在早期版本的瀏覽器中會產生錯誤,於是編程時的最佳實踐方式就是移除它們。
(譯註:而「現代」的瀏覽器彷佛鼓勵這種方式,這也很好解釋緣由。尾部逗號能夠減小向數組的最後添加元素時,由於忘記爲這最後一個元素加逗號 所形成的錯誤。)
var myList = ['home', , 'school', ];
在下面的例子中,數組的長度是4,元素myList[0]和myList[2]缺失(譯註:沒被賦值,於是是undefined)。
var myList = [ , 'home', , 'school'];
再看一個例子。在這裏,該數組的長度是4,元素myList[1]和myList[3]被漏掉了。(可是)只有最後的那個逗號被忽略。
var myList = ['home', , 'school', , ];
理解多餘的逗號(在腳本運行時會被如何處理)的含義,對於從語言層面理解JavaScript是十分重要的。可是,在你本身寫代碼時:顯式地將缺失的元素聲明爲undefined,將大大提升你的代碼的清晰度和可維護性。
布爾類型有兩種字面量:true和false。
不要混淆做爲布爾對象的真和假與布爾類型的原始值true和false。布爾對象是原始布爾數據類型的一個包裝器
整數能夠用十進制(基數爲10)、十六進制(基數爲16)、八進制(基數爲8)以及二進制(基數爲2)表示。
嚴格模式下,八進制整數字面量必須以0o或0O開頭,而不能以0開頭。
整數字面量舉例:
0, 117 and -345 (十進制, 基數爲10)
015, 0001 and -0o77 (八進制, 基數爲8)
0x1123, 0x00111 and -0xF1A7 (十六進制, 基數爲16或"hex")
0b11, 0b0011 and -0b11 (二進制, 基數爲2)
對象字面值是封閉在花括號對({})中的一個對象的零個或多個"屬性名-值"對的(元素)列表。你不能在一條語句的開頭就使用對象字面值,這將致使錯誤或產生超出預料的行爲, 由於此時左花括號({)會被認爲是一個語句塊的起始符號。(譯者:這 裏須要對語句statement、塊block等基本名詞的解釋)
如下是一個對象字面值的例子。對象car的第一個元素(譯註:即一個屬性/值對)定義了屬性myCar;第二個元素,屬性getCar,引用了一個函數(即CarTypes("Honda"));第三個元素,屬性special,使用了一個已有的變量(即Sales)。
var Sales = "Toyota"; function CarTypes(name) { return (name === "Honda") ? name : "Sorry, we don't sell " + name + "." ; } var car = { myCar: "Saturn", getCar: CarTypes("Honda"), special: Sales }; console.log(car.myCar); // Saturn console.log(car.getCar); // Honda console.log(car.special); // Toyota
更進一步的,你可使用數字或字符串字面值做爲屬性的名字,或者在另外一個字面值內嵌套上一個字面值。以下的示例中使用了這些可選項。
var car = { manyCars: {a: "Saab", "b": "Jeep"}, 7: "Mazda" }; console.log(car.manyCars.b); // Jeep console.log(car[7]); // Mazda
對象屬性名字能夠是任意字符串,包括空串。若是對象屬性名字不是合法的javascript標識符,它必須用""包裹。屬性的名字不合法,那麼便不能用.訪問屬性值,而是經過類數組標記("[]")訪問和賦值。
var unusualPropertyNames = { "": "An empty string", "!": "Bang!" } console.log(unusualPropertyNames.""); // 語法錯誤: Unexpected string console.log(unusualPropertyNames[""]); // An empty string console.log(unusualPropertyNames.!); // 語法錯誤: Unexpected token ! console.log(unusualPropertyNames["!"]); // Bang!
字符串字面量是由雙引號(")對或單引號(')括起來的零個或多個字符。字符串被限定在同種引號之間;也即,必須是成對單引號或成對雙引號。下面的例子都是字符串字面值:
"foo" 'bar' "1234" "one line \n another line" "John's cat"
你能夠在字符串字面值上使用字符串對象的全部方法——JavaScript會自動將字符串字面值轉換爲一個臨時字符串對象,調用該方法,而後廢棄掉那個臨時的字符串對象。你也能用對字符串字面值使用相似String.length的屬性:
console.log("John's cat".length) // 將打印字符串中的字符個數(包括空格) // 結果爲:10
在ES2015中,還提供了一種模板字符串(template literals),模板字符串提供了一些語法糖來幫你構造字符串。這與Perl、Python還有其餘語言中的字符串插值(string interpolation)的特性很是類似。除此以外,你能夠在經過模板字符串前添加一個tag來自定義模板字符串的解析過程,這能夠用來防止注入攻擊,或者用來創建基於字符串的高級數據抽象。
// Basic literal string creation `In JavaScript '\n' is a line-feed.` // Multiline strings `In JavaScript this is not legal.` // String interpolation var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // Construct an HTTP request prefix is used to interpret the replacements and construction POST`http://foo.org/bar?a=${a}&b=${b} Content-Type: application/json X-Credentials: ${credentials} { "foo": ${foo}, "bar": ${bar}}`(myOnReadyStateChangeHandler);
除非有特別須要使用字符串對象,不然,你應當始終使用字符串字面值。
條件判斷語句指的是根據指定的條件所返回的結果(真或假或其它預約義的),來執行特定的語句。JavaScript 支持兩種條件判斷語句:if...else和switch。
let iceCream = 'chocolate'; if (iceCream === 'chocolate') { alert('我最喜歡巧克力冰激淋了。'); } else { alert('可是巧克力纔是個人最愛呀……'); }
你能夠用 throw 語句拋出一個異常而且用 try...catch 語句捕獲處理它。
從 ECMAScript 6 開始,JavaScript 增長了對 Promise 對象的支持,它容許你對延時和異步操做流進行控制。
Promise 對象有如下幾種狀態:
展示了 Promise 的工做流
function imgLoad(url) { return new Promise(function(resolve, reject) { var request = new XMLHttpRequest(); request.open('GET', url); request.responseType = 'blob'; request.onload = function() { if (request.status === 200) { resolve(request.response); } else { reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); } }; request.onerror = function() { reject(Error('There was a network error.')); }; request.send(); }); }
JavaScript中提供了這些循環語句:
一個for循環會一直重複執行,直到指定的循環條件爲fasle。 JavaScript的for循環和Java與C的for循環是很類似的。
for ([initialExpression]; [condition]; [incrementExpression])
statement
當一個for循環執行的時候,會發生如下事件:
<form name="selectForm"> <p> <label for="musicTypes">Choose some music types, then click the button below:</label> <select id="musicTypes" name="musicTypes" multiple="multiple"> <option selected="selected">R&B</option> <option>爵士</option> <option>布魯斯</option> <option>新紀元</option> <option>古典</option> <option>歌劇</option> </select> </p> <p><input id="btn" type="button" value="選擇了多少個選項?" /></p> </form> <script> function howMany(selectObject) { var numberSelected = 0; for (var i = 0; i < selectObject.options.length; i++) { if (selectObject.options[i].selected) { numberSelected++; } } return numberSelected; } var btn = document.getElementById("btn"); btn.addEventListener("click", function(){ alert('選擇選項的數量是: ' + howMany(document.selectForm.musicTypes)) }); </script>
do...while 語句一直重複直到指定的條件求值獲得假(false)。 一個 do...while 語句看起來像這樣:
do statement while (condition);
statement 在檢查條件以前會執行一次。要執行多條語句(語句塊),要使用塊語句 ({ ... }) 包括起來。 若是 condition 爲真(true),statement 將再次執行。 在每一個執行的結尾會進行條件的檢查。當 condition 爲假(false),執行會中止而且把控制權交回給 do...while 後面的語句。
在下面的例子中, 這個 do 循環將至少重複一次而且一直重複直到 i 再也不小於 5。
do { i += 1; console.log(i); } while (i < 5);
一個 while 語句只要指定的條件求值爲真(true)就會一直執行它的語句塊。一個 while 語句看起來像這樣:
while (condition)statement
若是這個條件變爲假,循環裏的 statement 將會中止執行並把控制權交回給 while 語句後面的代碼。
條件檢測會在每次 statement 執行以前發生。若是條件返回爲真, statement 會被執行並緊接着再次測試條件。若是條件返回爲假,執行將中止並把控制權交回給 while 後面的語句。
要執行多條語句(語句塊),要使用塊語句 ({ ... }) 包括起來。
例子 1
下面的 while 循環只要 n 小於 3就會一直執行:
var n = 0; var x = 0; while (n < 3) { n++; x += n; }
在每次循環裏, n 會增長1並被加到 x 上。因此, x 和 n 的變化是:
在三次完成後, 條件 n < 3 結果再也不爲真,因此循環終止了。
例子 2
避免無窮循環(無限循環)。保證循環的條件結果最終會變成假;不然,循環永遠不會中止。下面這個 while 循環會永遠執行由於條件永遠不會變成假:
while (true) { console.log("Hello, world"); }
函數 用來封裝可複用的功能。若是沒有函數,一段特定的操做過程用幾回就要重複寫幾回,而使用函數則只需寫下函數名和一些簡短的信息
瀏覽器內置函數和用戶定義的函數
一個函數定義(也稱爲函數聲明,或函數語句)由一系列的function關鍵字組成,依次爲:
例如,如下的代碼定義了一個簡單的square函數:
function square(number) { return number * number; }
函數square使用了一個參數,叫做number。這個函數只有一個語句,它說明該函數將函數的參數(即number)自乘後返回。函數的return語句肯定了函數的返回值:
return number * number;
原始參數(好比一個具體的數字)被做爲值傳遞給函數;值被傳遞給函數,若是被調用函數改變了這個參數的值,這樣的改變不會影響到全局或調用函數。
若是你傳遞一個對象(即一個非原始值,例如Array或用戶自定義的對象)做爲參數,而函數改變了這個對象的屬性,這樣的改變對函數外部是可見的,以下面的例子所示:
function myFunc(theObject) { theObject.make = "Toyota"; } var mycar = {make: "Honda", model: "Accord", year: 1998}; var x, y; x = mycar.make; // x獲取的值爲 "Honda" myFunc(mycar); y = mycar.make; // y獲取的值爲 "Toyota" // (make屬性被函數改變了)
雖然上面的函數聲明在語法上是一個語句,但函數也能夠由函數表達式建立。這樣的函數能夠是匿名的;它沒必要有一個名稱。例如,函數square也可這樣來定義:
var square = function(number) { return number * number; }; var x = square(4); // x gets the value 16
然而,函數表達式也能夠提供函數名,而且能夠用於在函數內部代指其自己,或者在調試器堆棧跟蹤中識別該函數:
var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)}; console.log(factorial(3));
當將函數做爲參數傳遞給另外一個函數時,函數表達式很方便。下面的例子演示了一個叫map的函數如何被定義,然後使用一個表達式函數做爲其第一個參數進行調用:
function map(f,a) { var result = [],i; //建立一個新數組 for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result; }
下面的代碼:
function map(f, a) { var result = []; // 建立一個數組 var i; // 聲明一個值,用來循環 for (i = 0; i != a.length; i++) result[i] = f(a[i]); return result; } var f = function(x) { return x * x * x; } var numbers = [0,1, 2, 5,10]; var cube = map(f,numbers); console.log(cube);
返回 [0, 1, 8, 125, 1000]。
在 JavaScript 中,能夠根據條件來定義一個函數。好比下面的代碼,當num 等於 0 的時候纔會定義 myFunc :
var myFunc; if (num == 0){ myFunc = function(theObject) { theObject.make = "Toyota" } }
除了上述的定義函數方法外,你也能夠在運行時用 Function 構造器由一個字符串來建立一個函數 ,很像 eval() 函數。
當一個函數是一個對象的屬性時,稱之爲方法。瞭解更多關於對象和方法的知識 使用對象。
調用函數節
定義一個函數並不會自動的執行它。定義了函數僅僅是賦予函數以名稱並明確函數被調用時該作些什麼。調用函數纔會以給定的參數真正執行這些動做。例如,一旦你定義了函數square,你能夠以下這樣調用它:
square(5);
上述語句經過提供參數 5 來調用函數。函數執行完它的語句會返回值25。
函數必定要處於調用它們的域中,可是函數的聲明能夠被提高(出如今調用語句以後),以下例:
console.log(square(5)); /* ... */ function square(n) { return n*n }
函數域是指函數聲明時的所在的地方,或者函數在頂層被聲明時指整個程序。
提示:注意只有使用如上的語法形式(即 function funcName(){})才能夠。而下面的代碼是無效的。就是說,函數提高僅適用於函數聲明,而不適用於函數表達式。
console.log(square); // square is hoisted with an initial value undefined. console.log(square(5)); // TypeError: square is not a function var square = function (n) { return n * n; }
函數的參數並不侷限於字符串或數字。你也能夠將整個對象傳遞給函數。函數 show_props(其定義參見 用對象編程)就是一個將對象做爲參數的例子。
函數能夠被遞歸,就是說函數能夠調用其自己。例如,下面這個函數就是用遞歸計算階乘:
function factorial(n){ if ((n == 0) || (n == 1)) return 1; else return (n * factorial(n - 1)); }
你能夠計算1-5的階乘以下:
var a, b, c, d, e; a = factorial(1); // 1賦值給a b = factorial(2); // 2賦值給b c = factorial(3); // 6賦值給c d = factorial(4); // 24賦值給d e = factorial(5); // 120賦值給e
還有其它的方式來調用函數。常見的一些情形是某些地方須要動態調用函數,或者函數的實參數量是變化的,或者調用函數的上下文須要指定爲在運行時肯定的特定對象。顯然,函數自己就是對象,所以這些對象也有方法(參考Function )。做爲此中情形之一,apply()方法能夠實現這些目的。
在函數內定義的變量不能在函數以外的任何地方訪問,由於變量僅僅在該函數的域的內部有定義。相對應的,一個函數能夠訪問定義在其範圍內的任何變量和函數。換言之,定義在全局域中的函數能夠訪問全部定義在全局域中的變量。在另外一個函數中定義的函數也能夠訪問在其父函數中定義的全部變量和父函數有權訪問的任何其餘變量。
// 下面的變量定義在全局做用域(global scope)中 var num1 = 20, num2 = 3, name = "Chamahk"; // 本函數定義在全局做用域 function multiply() { return num1 * num2; } multiply(); // 返回 60 // 嵌套函數的例子 function getScore() { var num1 = 2, num2 = 3; function add() { return name + " scored " + (num1 + num2); } return add(); } getScore(); // 返回 "Chamahk scored 5"