1. 程式人生 > >Web開發初探之JavaScript 快速入門

Web開發初探之JavaScript 快速入門

> 本文改編和學習自 [A JavaScript Primer For Meteor](https://www.discovermeteor.com/blog/javascript-for-meteor/) 和 MDN Web教程 > > 前文 [Web開發初探](https://www.cnblogs.com/RioTian/p/13668124.html) ## 概述 本文以介紹 JavaScript 為主,初學者掌握本文的內容後,將能夠對 JavaScript 有大體瞭解。 JavaScript(縮寫:JS)是一門完備的 [動態程式語言]()。當應用於 [HTML]() 文件時,可為網站提供動態互動特性。由布蘭登·艾克( Brendan Eich,Mozilla 專案、Mozilla 基金會和 Mozilla 公司的聯合創始人)發明。 JavaScript 的應用場合極其廣泛,簡單到幻燈片、照片庫、浮動佈局和響應按鈕點選,複雜到遊戲、2D/3D 動畫、大型資料庫驅動程式等等。 JavaScript 相當簡潔,卻非常靈活。開發者們基於 JavaScript 核心編寫了大量實用工具,可以使 開發工作事半功倍。其中包括: - 瀏覽器應用程式介面([API](https://developer.mozilla.org/zh-CN/docs/Glossary/API))—— 瀏覽器內建的 API 提供了豐富的功能,比如:動態建立 HTML 和設定 CSS 樣式、從使用者的攝像頭採集處理視訊流、生成3D 影象與音訊樣本等等。 - 第三方 API —— 讓開發者可以在自己的站點中整合其它內容提供者(Twitter、Facebook 等)提供的功能。 - 第三方框架和庫 —— 用來快速構建網站和應用。 > JavaScript是一門充滿爭議的程式語言:它以 Java 命名,但實際上和 Java 毫無關係。JavaScript 的創造 [只用了 10 天時間](https://www.w3.org/community/webed/wiki/A_Short_History_of_JavaScript),但在20年時間裡卻發展成世界上最流行的 Web 開發語言。如果為 JavaScript 今日的地位和流行程度找一個原因,那毫無疑問是容易上手的語言特性。當然,精通 JavaScript 是一項艱鉅的任務,但學會足夠開發 Web 應用和遊戲的知識卻很簡單,如果你已經有了一定程式設計基礎,熟悉 JavaScript 語言特性不會花費你多長時間。 ## 邊讀邊嘗試 如果你能看到這篇文章,那麼你已經具備了全功能的 JavaScript 開發環境 —— 我說的就是你正在使用的瀏覽器! 在本頁面中讀到的所有例子,你都可以把它們輸入到瀏覽器的控制檯裡並檢視執行結果,如果你不清楚怎麼做,可以閱讀文件 [如何在不同瀏覽器中開啟控制檯的指南](http://webmasters.stackexchange.com/a/77337)。 準備好了嗎?讓我們開始學習 JavaScript 吧! ## 變數(Variable) **變數** 是儲存值的容器。在 JavaScript 中,我們像這樣宣告一個變數,先輸入關鍵字 `let` 或 `var`,然後輸入合適的名稱: ```js var a; let myVariable; ``` 保留字 `var` 之後緊跟著的,就是一個變數名,接下來我們可以為變數賦值: ```js var a = 12; ``` 在閱讀其他人的 JavaScript 程式碼時,你也會看到下面這樣的變數宣告: ```js a = 12; ``` > **注:**行末的分號表示當前語句結束,不過只有在單行內需要分割多條語句時,這個分號才是必須的。然而,一些人認為每條語句末尾加分號是一種好的風格。 > > **注:**幾乎任何內容都可以作為變數名,但還是有一些限制:如型別名無法作為變數名(詳情請參閱 [變數命名規則](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_Types#變數))。如果你不確定,還可以 [驗證變數名](https://mothereff.in/js-variables) 是否有效。 > > **注:**JavaScript 對大小寫敏感,`myVariable` 和 `myvariable` 是不同的。如果程式碼出現問題了,先檢查一下大小寫! > > **注:**想要了解更多關於 `var` 和 `let` 的不同點,可以參閱 [var 與 let 的區別](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/First_steps/Variables#var_與_let_的區別)。 > > **注:**注意變數可以有不同的 [資料型別]() : 那麼變數有什麼用呢?我們說,程式設計時它們無所不在。如果值無法改變,那麼就無法做任何動態的工作,比如傳送個性化的問候,或是改變在圖片庫當前展示的圖片。 ## 註釋 類似於 CSS、C++,JavaScript 中可以添加註釋。 ```js /* 這裡的所有內容 都是註釋。 */ ``` 如果註釋只有一行,可以更簡單地將註釋放在兩個斜槓之後,就像這樣: ```js // 這是一條註釋。 ``` ## 函式 [函式]() 用來封裝可複用的功能。如果沒有函式,一段特定的操作過程用幾次就要重複寫幾次,而使用函式則只需寫下函式名和一些簡短的資訊。 比如:在 JavaScript 裡我們像這樣宣告函式: ```js var myAwesomeFunction = function (myArgument) { // do something } ``` 像這樣呼叫函式: ```js myAwesomeFunction(something); ``` 我們看到函式宣告也和變數宣告一樣遵從 `var something = somethingElse` 的模式。因為在 JavaScript 裡,函式和變數本質上是一樣的,我們可以像下面這樣把一個函式當做引數傳入另一個函式中: ```js square = function (a) { return a * a; } applyOperation = function (f, a) { return f(a); } applyOperation (square, 10); // 100 ``` ## 返回值 函式的返回值是由 `return` 打頭的語句定義的,我們這裡要了解的是函式體內 `return` 語句之後的內容是不會被執行的。 ```js myFunction = function (a) { return a * 3; explodeComputer(); // will never get executed (hopefully!) } ``` > **注:**`return` 語句告訴瀏覽器當前函式返回 `result` 變數。這是一點很有必要,因為函式內定義的變數只能在函式內使用。這叫做變數的 [作用域]()。 ## if JavaScript 中條件判斷語句 `if` 是這樣用的: ```js if (foo) { return bar; } ``` ## if / Else `if` 後的值如果為 false,會執行 `else` 中的語句: ```js if (foo) { function1(); } else { function2(); } ``` `if` / `else` 條件判斷還可以像這樣寫成一行: ```js foo ? function1() : function2(); //三目運算子:條件:條件True時返回值:條件False時返回值 ``` 當 `foo` 的值為 true 時,表示式會返回 `function1()` 的執行結果,反之會返回 `function2()` 的執行結果。當我們需要根據條件來為變數賦值時,這種寫法就非常方便: ```js var n = foo ? 1 : 2; ``` 上面的語句可以表述為:當 `foo` 是 true 時,將 `n` 的值賦為 1,否則賦為 2。 當然我們還可以使用 `else if` 來處理更多的判斷型別: ```js if (foo) { function1(); } else if (bar) { function2(); } else { function3(); } ``` ## JavaScript 陣列(Array) JavaScript 裡像這樣宣告陣列: ```js a = [123, 456, 789]; ``` 像這樣訪問陣列中的成員:(從0開始索引) ```js a[1]; // 456 ``` ## JavaScript 物件(Object) 我們像這樣宣告一個物件(object): ```js myProfile = { name: "Jare Guo", email: "[email protected]", 'zip code': 12345, isInvited: true } ``` 在物件宣告的語法(`myProfile = {...}`)之中,有一組用逗號相隔的鍵值對。每一對都包括一個 key(字串型別,有時候會用雙引號包裹)和一個 value(可以是任何型別:包括 string,number,boolean,變數名,陣列,物件甚至是函式)。我們管這樣的一對鍵值叫做物件的屬性(property),key 是屬性名,value 是屬性值。 你可以在 value 中巢狀其他物件,或者由一組物件組成的陣列: ```js myProfile = { name: "Jare Guo", email: "[email protected]", city: "Xiamen", points: 1234, isInvited: true, friends: [ { name: "Johnny", email: "[email protected]" }, { name: "Nantas", email: "[email protected]" } ] } ``` 訪問物件的某個屬性非常簡單,我們只要使用 dot 語法就可以了,還可以和陣列成員的訪問結合起來: ```js myProfile.name; // Jare Guo myProfile.friends[1].name; // Nantas ``` JavaScript 中的物件無處不在,在函式的引數傳遞中也會大量使用,比如在 Cocos Creator 中,我們就可以像這樣定義 FireClass 物件: ```js var MyComponent = cc.Class({ extends: cc.Component }); ``` `{extends: cc.Component}` 這就是一個用做函式引數的物件。在 JavaScript 中大多數情況我們使用物件時都不一定要為他命名,很可能會像這樣直接使用。 ## 匿名函式 我們之前試過了用變數宣告的語法來定義函式: ```js myFunction = function (myArgument) { // do something } ``` 再複習一下將函式作為引數傳入其他函式呼叫中的用法: ```js square = function (a) { return a * a; } applyOperation = function (f, a) { return f(a); } applyOperation(square, 10); // 100 ``` 我們還見識了 JavaScript 的語法是多麼喜歡偷懶,所以我們就可以用這樣的方式代替上面的多個函式宣告: ```js applyOperation = function (f, a) { return f(a); } applyOperation( function(a){ return a*a; }, 10 ) // 100 ``` 我們這次並沒有宣告 `square` 函式,並將 `square` 作為引數傳遞,而是在引數的位置直接寫了一個新的函式體,這樣的做法被稱為匿名函式,在 JavaScript 中是最為廣泛使用的模式。 ## 鏈式語法 下面我們介紹一種在陣列和字串操作中常用的語法: ```js var myArray = [123, 456]; myArray.push(789) // 123, 456, 789 var myString = "abcdef"; myString.replace("a", "z"); // "zbcdef" ``` 上面程式碼中的點符號表示“呼叫 `myString` 字串物件的 `replace` 函式,並且傳遞 `a` 和 `z` 作為引數,然後獲得返回值。 使用點符號的表示式,最大的優點是你可以把多項任務連結在一個表示式裡,當然前提是每個呼叫的函式必須有合適的返回值。我們不會過多介紹如何定義可連結的函式,但是使用它們是非常簡單的,只要使用以下的模式:`something.function1().function2().function3()` 鏈條中的每個環節都會接到一個初始值,呼叫一個函式,然後把函式執行結果傳遞到下一環節: ```js var n = 5; n.double().square(); // 100 ``` ## this `this` 可能是 JavaScript 中最難以理解和掌握的概念了。 簡單地說,`this` 關鍵字能讓你訪問正在處理的物件:就像變色龍一樣,`this` 也會隨著執行環境的變化而變化。 解釋 `this` 的原理是很複雜的,不妨讓我們使用兩種工具來幫助我們在實踐中理解 `this` 的值: 首先是最普通又最常用的 `console.log()`,它能夠將物件的資訊輸出到瀏覽器的控制檯裡。在每個函式體開始的地方加入一個 `console.log()`,確保我們瞭解當時執行環境下正在處理的物件是什麼。 ```js myFunction = function (a, b) { console.log(this); // do something } ``` 另外一個方法是將 `this` 賦值給另外一個變數: ```js myFunction = function (a, b) { var myObject = this; // do something } ``` 乍一看好像這樣子並沒有什麼作用,實際上它允許你安全的使用 `myObject` 這個變數來指代最初執行函式的物件,而不用擔心在後面的程式碼中 `this` 會變成其他東西。 關於 JavaScript 裡 `this` 的詳細原理說明,請參考這篇文章 [this 的值到底是什麼?一次說清楚](http://zhuanlan.zhihu.com/p/23804247)。 ## 運算子 [運算子](https://developer.mozilla.org/en-US/docs/Glossary/Operator) 是一類數學符號,可以根據兩個值(或變數)產生結果。以下表格中介紹了一些最簡單的運算子,可以在瀏覽器控制檯裡嘗試一下後面的示例。 > **譯註:**這裡說“根據**兩個**值(或變數)產生結果”是不嚴謹的,計算兩個變數的運算子稱為“二元運算子”,還有一元運算子和三元運算子,下表中的“取非”就是一元運算子。 | 運算子 | 解釋 | 符號 | 示例 | | :--------- | :----------------------------------------------------------- | :------------ | :----------------------------------------------------------- | | 加 | 將兩個數字相加,或拼接兩個字串。 | `+` | `6 + 9;"Hello " + "world!";` | | 減、乘、除 | 這些運算子操作與基礎算術一致。只是乘法寫作星號,除法寫作斜槓。 | `-`, `*`, `/` | `9 - 3;8 * 2; //乘法在JS中是一個星號9 / 3;` | | 賦值運算子 | 為變數賦值(你之前已經見過這個符號了) | `=` | `let myVariable = '李雷';` | | 等於 | 測試兩個值是否相等,並返回一個 `true`/`false` (布林)值。 | `===` | `let myVariable = 3;myVariable === 4; // false` | | 不等於 | 和等於運算子相反,測試兩個值是否不相等,並返回一個 `true`/`false` (布林)值。 | `!==` | `let myVariable = 3;myVariable !== 3; // false` | | 取非 | 返回邏輯相反的值,比如當前值為真,則返回 `false`。 | `!` | 原式為真,但經取非後值為 `false`: `let myVariable = 3;!(myVariable === 3); // false` | 運算子種類遠不止這些,不過目前上表已經夠用了。完整列表請參閱 [表示式和運算子](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators)。 > **注:**不同型別資料之間的計算可能出現奇怪的結果,因此必須正確引用變數,才能得出預期結果。比如在控制檯輸入 `"35" + "25"`,為什麼不能得到 `60`?因為引號將數字轉換成了字串,所以結果是連線兩個字串而不是把兩個數字相加。輸入 `35 + 25` 才能得到正確結果。 `=` 是賦值運算子,`a = 12` 表示把 “12” 賦值給變數 `a`。 如果你需要比較兩個值,可以使用 `==`,例如 `a == 12`。 JavaScript 中還有個獨特的 `===` 運算子,它能夠比較兩邊的值和型別是否全都相同。(型別是指 string, number 這些): ```js a = "12"; a == 12; // true a === 12; // false ``` 大多數情況下,我們都推薦使用 `===` 運算子來比較兩個值,因為希望比較兩個不同型別但有著相同值的情況是比較少見的。 下面是 JavaScript 判斷兩個值是否不相等的比較運算子: ```js a = 12; a !== 11; // true ``` `!` 運算子還可以單獨使用,用來對一個 boolean 值取反: ```js a = true; !a; // false ``` `!` 運算子總會得到一個 boolean 型別的值,所以可以用來將非 boolean 型別的值轉為 boolean 型別: ```js a = 12; !a; // false !!a; // true ``` 或者: ```js a = 0; !a; // true !!a; // false ``` ## 程式碼風格 最後,下面這些程式碼風格上的規則能幫助我們寫出更清晰明確的程式碼: - 使用駝峰命名法:定義 `myRandomVariable` 這樣的變數名,而不是 `my_random_variable` - 在每一行結束時寫一個 `;`,儘管在 JavaScript 裡行尾的 `;` 是可以忽略的 - 在每個關鍵字前後都加上空格,如 `a = b + 1`,而不是 `a = b + 1` ## 組合我們學到的知識 以上基礎的 JavaScript 語法知識已經介紹完了,下面我們來看看能否理解實際的指令碼程式碼: ```js var Comp = cc.Class({ extends: cc.Component, properties: { target: { default: null, type: cc.Entity } }, onStart: function () { this.target = cc.Entity.find('/Main Player/Bip/Head'); }, update: function () { this.transform.worldPosition = this.target.transform.worldPosition; } }); ``` 這段程式碼向引擎定義了一個新元件,這個元件具有一個 `target` 引數,在執行時會初始化為指定的物件,並且在執行的過程中每一幀都將自己設定成和 `target` 相同的座標。 讓我們分別看下每一句的作用(我會高亮有用的語法模式): `var Comp = cc.Class({`:這裡我們使用 `cc` 這個物件,通過 **點語法** 來呼叫物件的 `Class()` 方法(該方法是 `cc` 物件的一個屬性),呼叫時傳遞的引數是一個匿名的 **JavaScript 物件**(`{}`)。 `target: { default: null, type: cc.Entity }`:這個鍵值對聲明瞭一個名為 `target` 的屬性,值是另一個 JavaScript 匿名物件。這個物件定義了 target 的預設值和值型別。 `extends: cc.Component`:這個鍵值對宣告這個 Class 的父類是 cc.Component。cc.Component 是 Cocos Creator 的內建型別。 `onStart: function () {`:這一對鍵值定義了一個成員方法,叫做 `onStart`,它的值是一個匿名函式。 `this.target = cc.Entity.find('`:在這一句的上下文中,`this` 表示正在被建立的 Component 元件,這裡通過 `this.target` 來訪問 `target` 屬性。 ## 繼續學習 這篇簡短的教程從任何角度上說都無法代替系統的 JavaScript 學習,但這裡介紹的幾種語法模式已經能夠幫助你理解絕大部分 Javascript 文件和教程中的程式碼了,至少從語法上完全可以理解。 如果你像我一樣喜歡通過實踐學習,那麼現在就可以開始跟隨教程和文件學習在 [MDN上進階學習](https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript)了 ## JavaScript Resources 以下是 JavaScript 的一些入門教程: - [JavaScript 標準參考教程](http://javascript.ruanyifeng.com/) - [JavaScript 祕密花園](http://bonsaiden.github.io/JavaScript-Garden/zh/)