Web開發初探之JavaScript 快速入門

本文改編和學習自 A JavaScript Primer For Meteor 和 MDN Web教程

前文 Web開發初探

概述

本文以介紹 JavaScript 為主,初學者掌握本文的內容後,將能夠對 JavaScript 有大體了解。

JavaScript(縮寫:JS)是一門完備的 動態程式語言。當應用於 HTML 文檔時,可為網站提供動態交互特性。由布蘭登·艾克( Brendan Eich,Mozilla 項目、Mozilla 基金會和 Mozilla 公司的聯合創始人)發明。

JavaScript 的應用場合極其廣泛,簡單到幻燈片、照片庫、浮動布局和響應按鈕點擊,複雜到遊戲、2D/3D 動畫、大型資料庫驅動程式等等。

JavaScript 相當簡潔,卻非常靈活。開發者們基於 JavaScript 核心編寫了大量實用工具,可以使 開發工作事半功倍。其中包括:

  • 瀏覽器應用程式介面(API)—— 瀏覽器內置的 API 提供了豐富的功能,比如:動態創建 HTML 和設置 CSS 樣式、從用戶的攝影機採集處理影片流、生成3D 影像與音頻樣本等等。
  • 第三方 API —— 讓開發者可以在自己的站點中整合其它內容提供者(Twitter、Facebook 等)提供的功能。
  • 第三方框架和庫 —— 用來快速構建網站和應用。

JavaScript是一門充滿爭議的程式語言:它以 Java 命名,但實際上和 Java 毫無關係。JavaScript 的創造 只用了 10 天時間,但在20年時間裡卻發展成世界上最流行的 Web 開發語言。如果為 JavaScript 今日的地位和流行程度找一個原因,那毫無疑問是容易上手的語言特性。當然,精通 JavaScript 是一項艱巨的任務,但學會足夠開發 Web 應用和遊戲的知識卻很簡單,如果你已經有了一定編程基礎,熟悉 JavaScript 語言特性不會花費你多長時間。

邊讀邊嘗試

如果你能看到這篇文章,那麼你已經具備了全功能的 JavaScript 開發環境 —— 我說的就是你正在使用的瀏覽器!

在本頁面中讀到的所有例子,你都可以把它們輸入到瀏覽器的控制台里並查看運行結果,如果你不清楚怎麼做,可以閱讀文檔 如何在不同瀏覽器中打開控制台的指南

準備好了嗎?讓我們開始學習 JavaScript 吧!

變數(Variable)

變數 是存儲值的容器。在 JavaScript 中,我們像這樣聲明一個變數,先輸入關鍵字 letvar,然後輸入合適的名稱:

var a;
let myVariable;

保留字 var 之後緊跟著的,就是一個變數名,接下來我們可以為變數賦值:

var a = 12;

在閱讀其他人的 JavaScript 程式碼時,你也會看到下面這樣的變數聲明:

a = 12;

註:行末的分號表示當前語句結束,不過只有在單行內需要分割多條語句時,這個分號才是必須的。然而,一些人認為每條語句末尾加分號是一種好的風格。

註:幾乎任何內容都可以作為變數名,但還是有一些限制:如類型名無法作為變數名(詳情請參閱 變數命名規則)。如果你不確定,還可以 驗證變數名 是否有效。

註:JavaScript 對大小寫敏感,myVariablemyvariable 是不同的。如果程式碼出現問題了,先檢查一下大小寫!

註:想要了解更多關於 varlet 的不同點,可以參閱 var 與 let 的區別

註:注意變數可以有不同的 數據類型

那麼變數有什麼用呢?我們說,編程時它們無所不在。如果值無法改變,那麼就無法做任何動態的工作,比如發送個性化的問候,或是改變在圖片庫當前展示的圖片。

注釋

類似於 CSS、C++,JavaScript 中可以添加註釋。

/*
這裡的所有內容
都是注釋。
*/

如果注釋只有一行,可以更簡單地將注釋放在兩個斜杠之後,就像這樣:

// 這是一條注釋。

函數

函數 用來封裝可復用的功能。如果沒有函數,一段特定的操作過程用幾次就要重複寫幾次,而使用函數則只需寫下函數名和一些簡短的資訊。

比如:在 JavaScript 里我們像這樣聲明函數:

var myAwesomeFunction = function (myArgument) {
    // do something
}

像這樣調用函數:

myAwesomeFunction(something);

我們看到函數聲明也和變數聲明一樣遵從 var something = somethingElse 的模式。因為在 JavaScript 里,函數和變數本質上是一樣的,我們可以像下面這樣把一個函數當做參數傳入另一個函數中:

square = function (a) {
    return a * a;
}
applyOperation = function (f, a) {
    return f(a);
}
applyOperation (square, 10); // 100

返回值

函數的返回值是由 return 打頭的語句定義的,我們這裡要了解的是函數體內 return 語句之後的內容是不會被執行的。

myFunction = function (a) {
    return a * 3;
    explodeComputer(); // will never get executed (hopefully!)
}

註:return 語句告訴瀏覽器當前函數返回 result 變數。這是一點很有必要,因為函數內定義的變數只能在函數內使用。這叫做變數的 作用域

if

JavaScript 中條件判斷語句 if 是這樣用的:

if (foo) {
    return bar;
}

if / Else

if 後的值如果為 false,會執行 else 中的語句:

if (foo) {
    function1();
}
else {
    function2();
}

if / else 條件判斷還可以像這樣寫成一行:

foo ? function1() : function2();
//三目運算符:條件:條件True時返回值:條件False時返回值

foo 的值為 true 時,表達式會返回 function1() 的執行結果,反之會返回 function2() 的執行結果。當我們需要根據條件來為變數賦值時,這種寫法就非常方便:

var n = foo ? 1 : 2;

上面的語句可以表述為:當 foo 是 true 時,將 n 的值賦為 1,否則賦為 2。

當然我們還可以使用 else if 來處理更多的判斷類型:

if (foo) {
    function1();
}
else if (bar) {
    function2();
}
else {
    function3();
}

JavaScript 數組(Array)

JavaScript 里像這樣聲明數組:

a = [123, 456, 789];

像這樣訪問數組中的成員:(從0開始索引)

a[1]; // 456

JavaScript 對象(Object)

我們像這樣聲明一個對象(object):

myProfile = {
    name: "Jare Guo",
    email: "[email protected]",
    'zip code': 12345,
    isInvited: true
}

在對象聲明的語法(myProfile = {...})之中,有一組用逗號相隔的鍵值對。每一對都包括一個 key(字元串類型,有時候會用雙引號包裹)和一個 value(可以是任何類型:包括 string,number,boolean,變數名,數組,對象甚至是函數)。我們管這樣的一對鍵值叫做對象的屬性(property),key 是屬性名,value 是屬性值。

你可以在 value 中嵌套其他對象,或者由一組對象組成的數組:

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 語法就可以了,還可以和數組成員的訪問結合起來:

myProfile.name; // Jare Guo
myProfile.friends[1].name; // Nantas

JavaScript 中的對象無處不在,在函數的參數傳遞中也會大量使用,比如在 Cocos Creator 中,我們就可以像這樣定義 FireClass 對象:

var MyComponent = cc.Class({
    extends: cc.Component
});

{extends: cc.Component} 這就是一個用做函數參數的對象。在 JavaScript 中大多數情況我們使用對象時都不一定要為他命名,很可能會像這樣直接使用。

匿名函數

我們之前試過了用變數聲明的語法來定義函數:

myFunction = function (myArgument) {
    // do something
}

再複習一下將函數作為參數傳入其他函數調用中的用法:

square = function (a) {
    return a * a;
}
applyOperation = function (f, a) {
    return f(a);
}
applyOperation(square, 10); // 100

我們還見識了 JavaScript 的語法是多麼喜歡偷懶,所以我們就可以用這樣的方式代替上面的多個函數聲明:

applyOperation = function (f, a) {
    return f(a);
}
applyOperation(
    function(a){
      return a*a;
    },
    10
) // 100

我們這次並沒有聲明 square 函數,並將 square 作為參數傳遞,而是在參數的位置直接寫了一個新的函數體,這樣的做法被稱為匿名函數,在 JavaScript 中是最為廣泛使用的模式。

鏈式語法

下面我們介紹一種在數組和字元串操作中常用的語法:

var myArray = [123, 456];
myArray.push(789) // 123, 456, 789
var myString = "abcdef";
myString.replace("a", "z"); // "zbcdef"

上面程式碼中的點符號表示「調用 myString 字元串對象的 replace 函數,並且傳遞 az 作為參數,然後獲得返回值。

使用點符號的表達式,最大的優點是你可以把多項任務鏈接在一個表達式里,當然前提是每個調用的函數必須有合適的返回值。我們不會過多介紹如何定義可鏈接的函數,但是使用它們是非常簡單的,只要使用以下的模式:something.function1().function2().function3()

鏈條中的每個環節都會接到一個初始值,調用一個函數,然後把函數執行結果傳遞到下一環節:

var n = 5;
n.double().square(); // 100

this

this 可能是 JavaScript 中最難以理解和掌握的概念了。

簡單地說,this 關鍵字能讓你訪問正在處理的對象:就像變色龍一樣,this 也會隨著執行環境的變化而變化。

解釋 this 的原理是很複雜的,不妨讓我們使用兩種工具來幫助我們在實踐中理解 this 的值:

首先是最普通又最常用的 console.log(),它能夠將對象的資訊輸出到瀏覽器的控制台里。在每個函數體開始的地方加入一個 console.log(),確保我們了解當時運行環境下正在處理的對象是什麼。

myFunction = function (a, b) {
    console.log(this);
    // do something
}

另外一個方法是將 this 賦值給另外一個變數:

myFunction = function (a, b) {
    var myObject = this;
    // do something
}

乍一看好像這樣子並沒有什麼作用,實際上它允許你安全的使用 myObject 這個變數來指代最初執行函數的對象,而不用擔心在後面的程式碼中 this 會變成其他東西。

關於 JavaScript 里 this 的詳細原理說明,請參考這篇文章 this 的值到底是什麼?一次說清楚

運算符

運算符 是一類數學符號,可以根據兩個值(或變數)產生結果。以下表格中介紹了一些最簡單的運算符,可以在瀏覽器控制台里嘗試一下後面的示例。

譯註:這裡說「根據兩個值(或變數)產生結果」是不嚴謹的,計算兩個變數的運算符稱為「二元運算符」,還有一元運算符和三元運算符,下表中的「取非」就是一元運算符。

運算符 解釋 符號 示例
將兩個數字相加,或拼接兩個字元串。 + 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 ! 原式為真,但經取非後值為 falselet myVariable = 3;!(myVariable === 3); // false

運算符種類遠不止這些,不過目前上表已經夠用了。完整列表請參閱 表達式和運算符

註:不同類型數據之間的計算可能出現奇怪的結果,因此必須正確引用變數,才能得出預期結果。比如在控制台輸入 "35" + "25",為什麼不能得到 60?因為引號將數字轉換成了字元串,所以結果是連接兩個字元串而不是把兩個數字相加。輸入 35 + 25 才能得到正確結果。

= 是賦值運算符,a = 12 表示把 「12」 賦值給變數 a

如果你需要比較兩個值,可以使用 ==,例如 a == 12

JavaScript 中還有個獨特的 === 運算符,它能夠比較兩邊的值和類型是否全都相同。(類型是指 string, number 這些):

a = "12";
a == 12; // true
a === 12; // false

大多數情況下,我們都推薦使用 === 運算符來比較兩個值,因為希望比較兩個不同類型但有著相同值的情況是比較少見的。

下面是 JavaScript 判斷兩個值是否不相等的比較運算符:

a = 12;
a !== 11; // true

! 運算符還可以單獨使用,用來對一個 boolean 值取反:

a = true;
!a; // false

! 運算符總會得到一個 boolean 類型的值,所以可以用來將非 boolean 類型的值轉為 boolean 類型:

a = 12;
!a; // false
!!a; // true

或者:

a = 0;
!a; // true
!!a; // false

程式碼風格

最後,下面這些程式碼風格上的規則能幫助我們寫出更清晰明確的程式碼:

  • 使用駝峰命名法:定義 myRandomVariable 這樣的變數名,而不是 my_random_variable
  • 在每一行結束時寫一個 ;,儘管在 JavaScript 里行尾的 ; 是可以忽略的
  • 在每個關鍵字前後都加上空格,如 a = b + 1,而不是 a = b + 1

組合我們學到的知識

以上基礎的 JavaScript 語法知識已經介紹完了,下面我們來看看能否理解實際的腳本程式碼:

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上進階學習

JavaScript Resources

以下是 JavaScript 的一些入門教程: