[TOC]
在我們第一次開始寫程序的時候,都是以 Hello World 開始的。或者:
~~~
printf("hello,world");
~~~
又或許:
~~~
alert('hello,world');
~~~
過去的十幾年里,試過用二十幾種不同的語言,每個都是以 hello,world 作為開頭。在一些特定的軟件,如 Nginx,則是?**It Works**。
這是一個很長的故事,這個程序最早出現于1972年,由貝爾實驗室成員布萊恩·柯林漢撰寫的內部技術文件《A Tutorial Introduction to the Language B》之中。不久,同作者于1974年所撰寫的《Programming in C: A Tutorial》,也延用這個范例;而以本文件擴編改寫的《C語言程序設計》也保留了這個范例程式。工作時,我們也會使用類似于 hello,world 的 boilerplate 來完成基本的項目創建。
同時需要注意的一點是,在每個大的項目開始之前我們應該去找尋好開發環境。搭建環境是一件非常重要的事,它決定了你能不能更好地工作。畢竟環境是生產率的一部分。高效的程序員和低效程序員間的十倍差距,至少有三倍是因為環境差異。
因此在這一章里,我們將講述幾件事情:
1. 使用怎樣的操作系統
2. 如何去選擇工具
3. 如何搭建相應操作系統上的環境
4. 如何去學習一門語言
## 工具只是輔助
一個好的工具確實有助于編程,但是他只會給我們帶來的是幫助。我們寫出來的代碼還是和我們的水平保持著一致的。
什么是好的工具,這個說法就有很多了,但是有時候我們往往沉迷于事物的表面。有些時候 Vim 會比 Visual Studio 強大,當你只需要修改的是一個配置文件的時候,簡單且足夠快捷——在我們還未用 VS 打開的時候,我們已經用 Vim 做完這個活了。
> “好的裝備確實能帶來一些幫助,但事實是,你的演奏水平是由你自己的手指決定的。” – 《REWORK》
### WebStorm 還是 Sublime?
作為一個 IDE 有時候忽略的因素會過多,一開始的代碼由類似于 Sublime text 之類的編輯器開始會比較合適。于是我們又開始陷入 IDE 及 Editor 之戰了,無聊的時候討論一下這些東西是有點益處的。相互了解一下各自的優點,也是不錯的,偶爾可以換個環境試試。
剛開始學習的時候,我們只需要普通的工具,或者我們習慣了的工具去開始我們的工作。我們要的是把主要精力放在學習的東西上,而不是工具。剛開始學習一種新的語言的時候,我們不需要去討論哪個是最好的開發工具,如 Java,有時候可能是 Eclipse,有時候可能是 Vim,如果我們為的只是去寫一個 hello,world。在 Eclipse 上浪費太多的時間是不可取的,因為他用起來的效率可不比你在鍵盤上敲打來得快,當你移動你的手指去動你的鼠標的時候,我想你可以用那短短的時間完成編譯,運行了。
#### 工具是為了效率
尋找工具的目的和尋找捷徑是一樣的,我們需要更快更有效率地完成我們的工作,換句話說,我們為了獲取更多的時間用于其他的事情。而這個工具的用途是要看具體的事物的,如果我們去寫一個小說、博客的時候,word 或者 web editor 會比 tex studio 來得快,不是么。我們用 TEX 來排版的時候會比我們用 WORD 排版的時候來得更快,所以這個工具是相對而論的。有時候用一個順手的工具會好很多,但是不一定會是事半功倍的。我們應該將我們的目標專注于我們的內容,而不是我們的工具上。
我們用 Windows 自帶的畫圖就可以完成裁剪的時候,我們就沒必要運行起 GIMP 或者 Photoshop 去完成這個簡單的任務。效率在某些時候的重要性,會比你選擇的工具有用得多,學習的開始就是要去了解那些大眾推崇的東西。
#### 了解、熟悉你的工具
Windows 的功能很強大,只是大部分人用的是只是小小一部分。而不是一小部分,即使我們天天用著,我們也沒有學習到什么新的東西。和這個就如同我們的工具一樣,我們天天用著他們,如果我們只用 Word 來寫寫東西,那么我們可以用 Abiword 來替換他。但是明顯不太可能,因為強大的工具對于我們來說有些更大的吸引力。
如果你負擔得起你手上的工具的話,那么就盡可能去了解他能干什么。即使他是一些無關僅要的功能,比如 Emacs 的煮咖啡。有一本手冊是最好不過的,手冊在手邊可以即時查閱,不過出于環保的情況下,就不是這樣子的。手冊沒有辦法即時同你的軟件一樣更新,電子版的更新會比你手上用的那個手冊更新得更快。
Linux 下面的命令有一大堆,只是我們常用的只有一小部分——20%的命令能夠完成80%的工作。如同 CISC 和 RISC 一樣,我們所常用的指令會讓我們忘卻那些不常用的指令。而那些是最實用的,如同我們日常工作中使用的 Linux 一樣,記憶過多的不實用的東西,不比把他們記在筆記上實在。我們只需要了解有那些功能,如何去用他。
### 語言也是一種工具
越來越多的框架和語言出現、更新得越來越快。特別是這樣一個高速發展的產業,每天都在涌現新的名詞。如同我們選擇語言一樣,選擇合適的有時候會比選得順手的來得重要。然而,這個可以不斷地被推翻。
當我們熟悉用 Python、Ruby、PHP 等去構建一個網站的時候,JavaScript 用來做網站后臺,這怎么可能——于是 Node.js 火了。選擇工具本身是一件很有趣的事,因為有著越來越多的可能性。
過去 PHP 是主流的開發,不過現在也是,PHP 為 WEB 而生。有一天 Ruby on Rails 出現了,一切就變了,變得高效,變得更 Powerful。MVC 一直很不錯,不是么?于是越來越多的框架出現了,如 Django,Laravel 等等。不同的語言有著不同的框架,JavaScript 上也有著合適的框架,如 AngularJS。不同語言的使用者們用著他們合適的工具,因為學習新的東西,對于多數的人來說就是一種新的挑戰。在學面向對象語言的時候,人們很容易把程序寫成過程式的。
沒有合適的工具,要么創造一個,要么選擇一個合適的。
#### 小結
學習 Django 的時候習慣了有一個后臺,于是開始使用 Laravel 的時候,尋找 Administartor。需要編譯的時候習慣用 IDE,不需要的時候用 Editor,只是因為有效率,嵌入式的時候 IDE 會有效率一點。
以前不知道 WebStorm 的時候,習慣用 DW 來格式化 HTML,Aptana 來格式化 JavaScript。
以前,習慣用 WordPress 來寫博客,因為可以有移動客戶端,使用電腦時就不喜歡打開瀏覽器去寫。
等等
等
## 提高效率的工具
在提交效率的 N 種方法里:有一個很重要的方法是使用快捷鍵。熟練掌握快捷鍵可以讓我們隨著自己的感覺編寫程序——有時候如果我們手感不好,是不是就說明今天不適合寫代碼!笑~~
由于我們可能使用不同的操作系統來完成不同的工具。下面就先說說一些通用的、不限操作的工具:
### 快速啟動軟件
在我還不和道有這樣的工具的時候,我都是把圖標放在下面的任務欄里:

Windows任務欄
直到有一天,我知道有這樣的工具。這里不得不提到一本書《卓有成效的程序員》,在書中提到了很多提高效率的工具。使用快捷鍵是其中的一個,而還有一個是使用快速啟動軟件。于是,我在 Windows 上使用了 Launcy:

Launchy
通過這個軟件,我們可以在電腦上通過輸入軟件名,然后運行相關的軟件。我們不再需要點擊某個菜單,再從菜單里選中某個軟件打開。
### IDE
盡管在上一篇中,我們說過 IDE 和編輯器沒有什么好爭論的。但是如果是從頭開始搭建環境的話,IDE 是最好的——編輯器還需要安裝相應的插件。所以,這也就是為什么面試的時候會用編輯器的原因。
IDE 的全稱是集成開發環境,顧名思義即它集成了你需要用到的一些工具。而如果是編輯器的話,你需要自己去找尋合適的工具來做這件事。不過,這也意味著使用編輯器會有更多的自由度。如果你沒有足夠的時間去打造自己的開發環境就使用 IDE 吧。
一般來說,他們都應該有下面的一些要素:
* **shortcut(快捷鍵)**
* **Code HighLight(代碼高亮)**
* **Auto Complete(自動補全)**
* **Syntax Check(語法檢查)**
而如果是編輯器的話,就需要自己去找尋這些相應的插件。
IDE 一般是針對特定語言才產生的,并且優化更好。而,編輯器則需要自己去搭配。這也意味著如果你需要在多個語言上工作時,并且喜歡折騰,你可以考慮使用編輯器。
### DEBUG 工具
不得不提及的是在有些 IDE 自帶了 Debug 工具,這點可能使得使用 IDE 更有優勢。在簡單的項目是,我們可能不需要這樣的 Debug 工具。因為我們對我們的代碼庫比較熟悉,一個簡單的問題一眼就知道是哪里的問題。而對于那些復雜的項目來說,可能就沒有那么簡單了。特別是當你來到一個新的大中型項目,一個簡單的邏輯在實現上可能要經過一系列的函數才能處理完。
這時候我們就需要 Debug 工具——對于前端開發來說,我們可能使用 Chrome 的 Dev Tools。但是對于后端來說,我們就需要使用別的工具。如下圖所示的是 Intellij Idea 的 Debug 界面:

Intellij Idea Debug
在 Debug 的過程中,我們可以根據代碼的執行流程一步步向下執行。這也意味著,當出現 Bug 的時候我們可以更容易找到 Bug。這就是為什么他叫 Debug 工具的原因了。
### 終端或命令提示符
在開始寫代碼的時候,使用 GUI 可能是難以戒掉的一個習慣。但是當你習慣了使用終端之后,或者說使用終端的工具,你會發現這是另外一片天空。對于 GUI 應用上同樣的菜單來說,在終端上也會有同樣的工具——只是你覺得記住更多的命令。而且不同的工具對于同一實現可能會不同的規范,而 GUI 應用則會有一致的風格。不過,總的來說使用終端是一個很有益的習慣——從速度、便捷性。忘了提到一點,當你使用 Linux 服務器的時候,你不得不使用終端。

Linux 終端截圖
使用終端的優點在于我們可以擺脫鼠標的操作——這可以讓我們更容易集中精力于完成任務。而這也是兩種不同的選擇,便捷還是更快。雖是如此,但是這也意味著學習 Linux 會越來越輕松。

Linux 與 Windows 的學習曲線
雖然這是以 Linux 和 Windows 作了兩個不同的對比,但是兩個系統在終端工具上的差距是很大的。Linux 自身的哲學鼓勵使用命令行來完成任務,這也意味著在 Linux 上會有更多的工具可以在命令行下使用。雖然 Windows 上也可以——如使用 CygWin 來完成,但是這看上去并不是那么讓人滿意!
### 包管理
雖然包管理不僅僅存在于操作系統中,還存在著語言的包管理工具。在操作系統中安裝軟件,最方便的東西莫過于包管理了。引自 OpenSUSE 官網的說明及圖片:

包管理
Linux 發行版無非就是一堆軟件包 (package) 形式的應用程序加上整體地管理這些應用程序的工具。通常這些 Linux 發行版,包括 OpenSUSE,都是由成千上萬不同的軟件包構成的。
* 軟件包: 軟件包不止是一個文件,內含構成軟件的所有文件,包括程序本身、共享庫、開發包以及使用說明等。
* 元數據 (metadata) 包含于軟件包之中,包含軟件正常運行所需要的一些信息。軟件包安裝之后,其元數據就存儲于本地的軟件包數據庫之中,以用于軟件包檢索。
* 依賴關系 (dependencies) 是軟件包管理的一個重要方面。實際上每個軟件包都會涉及到其他的軟件包,軟件包里程序的運行需要有一個可執行的環境(要求有其他的程序、庫等),軟件包依賴關系正是用來描述這種關系的。
我們經常會使用各式各樣的包管理工具,來加速我們地日常使用。而不是 Google 某個軟件,然后下載,接著安裝。
## 環境搭建
由于我近期工具在 Mac OS X 上,所以先以 Mac OS X 為例。
### OS X
**[Homebrew](http://brew.sh/)**
> 包管理工具,官方稱之為 The missing package manager for OS X。
**[Homebrew Cask](https://caskroom.github.io/)**
> brew-cask 允許你使用命令行安裝 OS X 應用。
**[iTerm2](https://www.iterm2.com/)**
> iTerm2 是最常用的終端應用,是 Terminal 應用的替代品。
**[Zsh](http://www.zsh.org/)**
Zsh 是一款功能強大終端(shell)軟件,既可以作為一個交互式終端,也可以作為一個腳本解釋器。它在兼容 Bash 的同時 (默認不兼容,除非設置成 emulate sh) 還有提供了很多改進,例如:
* 更高效
* 更好的自動補全
* 更好的文件名展開(通配符展開)
* 更好的數組處理
* 可定制性高
**[Oh My Zsh](http://ohmyz.sh/)**
> Oh My Zsh 同時提供一套插件和工具,可以簡化命令行操作。
**[Sublime Text 2](https://www.sublimetext.com/)**
> 強大的文件編輯器。
**[MacDown](http://macdown.uranusjr.com/)**
> MacDown 是 Markdown 編輯器。
**[CheatSheet](https://www.mediaatelier.com/CheatSheet/)**
> CheatSheet 能夠顯示當前程序的快捷鍵列表,默認的快捷鍵是長按?。
**[SourceTree](https://www.sourcetreeapp.com/)**
> SourceTree 是 Atlassian 公司出品的一款優秀的 Git 圖形化客戶端。
**[Alfred](https://www.alfredapp.com/)**
> Mac 用戶不用鼠標鍵盤的必備神器,配合大量 Workflows,習慣之后可以大大減少操作時間。
上手簡單,調教成本在后期自定義 Workflows,不過有大量雷鋒使用者提供的現成擴展,訪問這里挑選喜歡的,并可以極其簡單地根據自己的需要修改。
**[Vimium](https://vimium.github.io/)**
> Vimium 是一個 Google Chrome 擴展,讓你可以純鍵盤操作 Chrome。
相關參考:
* [Mac web developer apps](https://gist.github.com/erikreagan/3259442)
* [強迫癥的 Mac 設置指南](https://github.com/macdao/ocds-guide-to-setting-up-mac)
### Windows
**[Chocolatey](https://chocolatey.org/)**
> Chocolatey 是一個軟件包管理工具,類似于 Ubuntu 下面的 apt-get,不過是運行在 Windows 環境下面。
**[Wox](http://www.getwox.com/)**
> Wox 是一個高效的快速啟動器工具,通過快捷鍵呼出,然后輸入關鍵字來搜索程序進行快速啟動,或者搜索本地硬盤的文件,打開百度、Google 進行搜索,甚至是通過一些插件的功能實現單詞翻譯、關閉屏幕、查詢剪貼板歷史、查詢編程文檔、查詢天氣等更多功能。它最大的特點是可以支持中文拼音的模糊匹配。
**[PowerShell](https://msdn.microsoft.com/en-us/powershell/mt173057.aspx)**
> Windows PowerShell 是微軟公司為 Windows 環境所開發的殼程序(shell)及腳本語言技術,采用的是命令行界面。這項全新的技術提供了豐富的控制與自動化的系統管理能力。
**[cmder](http://cmder.net/)**
> cmder 把 conemu,msysgit 和 clink 打包在一起,讓你無需配置就能使用一個真正干凈的 Linux 終端!她甚至還附帶了漂亮的 monokai 配色主題。
**[Total Commander](http://www.ghisler.com/)**
> Total Commander 是一款應用于 Windows 平臺的文件管理器 ,它包含兩個并排的窗口,這種設計可以讓用戶方便地對不同位置的“文件或文件夾”進行操作,例如復制、移動、刪除、比較等,相對 Windows 資源管理器而言方便很多,極大地提高了文件操作的效率,被廣大軟件愛好者親切地簡稱為:TC 。
### GNU/Linux
**[Zsh](http://www.zsh.org/)**
Zsh 是一款功能強大終端(shell)軟件,既可以作為一個交互式終端,也可以作為一個腳本解釋器。它在兼容 Bash 的同時 (默認不兼容,除非設置成 emulate sh) 還有提供了很多改進,例如:
* 更高效
* 更好的自動補全
* 更好的文件名展開(通配符展開)
* 更好的數組處理
* 可定制性高
**[Oh My Zsh](http://ohmyz.sh/)**
> Oh My Zsh 同時提供一套插件和工具,可以簡化命令行操作。
**[ReText](https://github.com/retext-project/retext)**
> ReText 是一個使用 Markdown 語法和 reStructuredText (reST) 結構的文本編輯器,編輯的內容支持導出到 PDF、ODT 和 HTML 以及純文本,支持即時預覽、網頁生成以及 HTML 語法高亮、全屏模式,可導出文件到 Google Docs 等。
**[Launchy](http://www.launchy.net/)**
> Launchy 是一款免費開源的協助您摒棄 Windows “運行”的 Dock 式替代工具,既方便又實用,自帶多款皮膚,作為美化工具也未嘗不可。
環境搭建完畢!現在,就讓我們來看看如何學好一門語言!
## 學好一門語言的藝術
### 一次語言學習體驗
在我們開始學習一門語言或者技術的時候,我們可能會從一門 “hello,world” 開始。
好了,現在我是 Scala 語言的初學者,接著我用搜索引擎去搜索『Scala』來看看『Scala』是什么鬼:
> Scala 是一門類 Java 的編程語言,它結合了面向對象編程和函數式編程。
接著又開始看『Scala ‘hello,world’』,然后找到了這樣的一個示例:
~~~
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
~~~
GET 到了5%的知識。
看上去這門語言相比于 Java 語言來說還行。然后我找到了一本名為『Scala 指南』的電子書,有這樣的一本目錄:
* 表達式和值
* 函數是一等公民
* 借貸模式
* 按名稱傳遞參數
* 定義類
* 鴨子類型
* 柯里化
* 范型
* Traits
* …
看上去還行, 又 GET 到了5%的知識點。接著,依照上面的代碼和搭建指南在自己的電腦上安裝了 Scala 的環境:
~~~
brew install scala
~~~
Windows 用戶可以用:
~~~
choco install scala
~~~
然后開始寫一個又一個的 Demo,感覺自己 GET 到了很多特別的知識點。
到了第二天忘了!

Bro Wrong
接著,你又重新把昨天的知識過了一遍,還是沒有多大的作用。突然間,你聽到別人在討論什么是**這個世界上最好的語言**——你開始加入討論了。
于是,你說出了 Scala 這門語言可以:
* 支持高階函數。lambda,閉包…
* 支持偏函數。 match..
* mixin,依賴注入..
* 等等
雖然隔壁的 Python 小哥贏得了這次辯論,然而你發現你又回想起了 Scala 的很多特性。

最流行的語言
你發現隔壁的 Python 小哥之所以贏得了這場辯論是因為他把 Python 語言用到了各個地方——機器學習、人工智能、硬件、Web開發、移動應用等。而你還沒有用 Scala 寫過一個真正的應用。
讓我想想我能做什么?我有一個博客。對,我有一個博客,可以用 Scala 把我的博客重寫一遍:
1. 先找一 Scala 的 Web 框架,Play 看上去很不錯,就這個了。這是一個 MVC 框架,原來用的 Express 也是一個 MVC 框架。Router 寫這里,Controller 類似這個,就是這樣的。
2. 既然已經有 PyJS,也會有 Scala-js,前端就用這個了。
好了,博客重寫了一遍了。
感覺還挺不錯的,我決定向隔壁的 Java 小弟推銷這門語言,以解救他于火海之中。
『讓我想想我有什么殺手锏?』
『這里的知識好像還缺了一點,這個是什么?』
好了,你已經 GET 到了90%了。如下圖所示:

Learn
希望你能從這張圖上 GET 到很多點。
### 輸出是最好的輸入
上面那張圖『學習金字塔』就是在說明——輸出是最好的輸入。
如果你不試著去寫點博客、整理資料、準備分享,那么你可能并沒有意識到你缺少了多少東西。雖然你已經有了很多的實踐,然并卵。
因為你一直在完成功能、完成工作,你總會有意、無意地漏掉一些知識,而你也沒有意識到這些知識的重要性。

Output is Input
從我有限的(500+)博客寫作經驗里,我發現多數時候我需要更多地參考資料才能更好也向人們展示這個過程。為了輸出我們需要更多的輸入,進而加速這個過程。
而如果是寫書的時候則是一個更高水平的學習,你需要發現別人在他們的書中欠缺的一些知識點。并且你還要展示一些在別的書中沒有,而這本書會展現這個點的知識,這意味著你需要挖掘得更深。
所以,如果下次有人問你如何學一門新語言、技術,那么答案就是寫一本書。
### 如何應用一門新的技術
對于多數人來說,寫書不是一件容易的事,而應用新的技術則是一件迫在眉睫的事。
通常來說,技術出自于對現有的技術的改進。這就意味著,在掌握現有技術的情況下,我們只需要做一些小小的改動就更可以實現技術升級。
而學習一門新的技術的最好實踐就是用這門技術對現有的系統行重寫。
第一個系統(v1):?`Spring MVC`?+?`Bootstrap`?+?`jQuery`
那么在那個合適的年代里, 我們需要單頁面應用,就使用了Backbone。然后,我們就可以用 Mustache + HTML 來替換掉 JSP。
第二個系統(v2):?`Spring MVC`?+?`Backbone`?+?`Mustache`
在這時我們已經實現了前后端分離了,這時候系統實現上變成了這樣。
第二個系統(v2.2):?`RESTful Services`?+?`Backbone`?+?`Mustache`
或者
第二個系統(v2.2):?`RESTful Services`?+?`AngularJS 1.x`
Spring 只是一個 RESTful 服務,我們還需要一些問題,比如 DOM 的渲染速度太慢了。
第三個系統(v3):?`RESTful Services`?+?`React`
系統就是這樣一步步演進過來的。
盡管在最后系統的架構已經不是當初的架構,而系統本身的業務邏輯變化并沒有發生太大的變化。
特別是對于如博客這一類的系統來說,他的一些技術實現已經趨于穩定,而且是你經常使用的東西。所以,下次試試用新的技術的時候,可以先從對你的博客的重寫開始。
## Web 編程基礎
### 從瀏覽器到服務器
如果你的操作系統帶有 cURL 這個軟件(在 GNU/Linux、Mac OS 都自帶這個工具,Windows 用戶可以從[http://curl.haxx.se/download.html](http://curl.haxx.se/download.html)下載到),那么我們可以直接用下面的命令來看這看這個過程(-v 參數可以顯示一次 http 通信的整個過程):
~~~
curl -v https://www.phodal.com
~~~
我們就會看到下面的響應過程:
~~~
* Rebuilt URL to: https://www.phodal.com/
* Trying 54.69.23.11...
* Connected to www.phodal.com (54.69.23.11) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* Server certificate: www.phodal.com
* Server certificate: COMODO RSA Domain Validation Secure Server CA
* Server certificate: COMODO RSA Certification Authority
* Server certificate: AddTrust External CA Root
> GET / HTTP/1.1
> Host: www.phodal.com
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Server: phodal/0.19.4
< Date: Tue, 13 Oct 2015 05:32:13 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 170
< Connection: keep-alive
<
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>phodal/0.19.4</center>
</body>
</html>
* Connection #0 to host www.phodal.com left intact
~~~
我們嘗試用 cURL 去訪問我的網站,會根據訪問的域名找出其 IP,通常這個映射關系是來源于 ISP 緩存 DNS(英語:Domain Name System)服務器[^DNSServer]。
以“*”開始的前8行是一些連接相關的信息,稱為**響應首部**。我們向域名[https://www.phodal.com/](https://www.phodal.com/)發出了請求,接著 DNS服務器告訴了我們網站服務器的 IP,即54.69.23.11。出于安全考慮,在這里我們的示例,我們是以 HTTPS 協議為例,所以在這里連接的端口是 443。因為使用的是 HTTPS 協議,所以在這里會試圖去獲取服務器證書,接著獲取到了域名相關的證書信息。
隨后以“>”開始的內容,便是向Web服務器發送請求。Host 即是我們要訪問的主機的域名,GET / 則代表著我們要訪問的是根目錄,如果我們要訪問?[https://www.phodal.com/about/](https://www.phodal.com/about/)頁面在這里,便是 GET 資源文件 /about。緊隨其后的是 HTTP 的版本號(HTTP/1.1)。User-Agent 通常指向的是使用者行為的軟件,通常會加上硬件平臺、系統軟件、應用軟件和用戶個人偏好等等的一些信息。Accept 則指的是告知服務器發送何種媒體類型。
這個過程,大致如下圖所示:

DNS 到服務器的過程
在圖中,我們會發現解析 DNS 的時候,我們需要先本地 DNS 服務器查詢。如果沒有的話,再向根域名服務器查詢——這個域名由哪個服務器來解析。直至最后拿到真正的服務器IP才能獲取頁面。
當我們拿到相應的 HTML、JS、CSS 后,我們就開始渲染這個頁面了。
#### HTTP 協議
說到這里,我們不得不說說 HTTP 協議——超文本傳輸協議。它也是一個基于文本的傳輸協議,這就是為什么你在上面看到的都是文本的傳輸過程。
### 從 HTML 到頁面顯示
而瀏覽器接收到文本的時候,就要開始著手將 HTML 變成屏幕。下圖是 Chrome 渲染頁面的一個時間線:

Chrome 渲染的 Timeline
及其整個渲染過程如下圖所示:

Render HTML
(PS: 需要注意的是這里用的是 WebKit 內核的渲染過程,即 Chrome 和 Safari 等瀏覽器所使用的內核。)
從上面的兩圖可以看出來第一步都 Parser HTML,而 Paser HTML 實質上就是將其將解析為 DOM Tree。與此同時,CSS 解析器會解析 CSS 會產生 CSS 規則樹。
隨后會根據生成的 DOM 樹和 CSS 規則樹來構建 Render Tree,接著生成 Render Tree的布局,最后就是繪制出 Render Tree。
詳細的內容還得參見相關的書籍~~。
相關內容:
* 《[How browsers work](http://taligarsiel.com/Projects/howbrowserswork1.htm)》
## HTML
讓我們先從身邊的語言下手,也就是現在無處不在的 HTML+Javascript+CSS。
之所以從 HTML 開始,是因為我們不需要配置一個復雜的開發環境,也許你還不知道開發環境是什么東西,不過這也沒關系,畢竟這些知識需要慢慢的接觸才能有所了解,尤其是對于普通的業余愛好者來說,當然,對于專業選手而言自然不是問題。HTML 是 Web 的核心語言,也算是比較基礎的語言。
### hello,world
hello,world 是一個傳統,所以在這里也遵循這個有趣的傳統,我們所要做的事情其實很簡單,雖然也有一點點 hack 的感覺。——讓我們先來新建一個文件并命名為“helloworld.html”。
(PS:大部分人應該都是在 Windows 環境下工作的,所以你需要新建一個文本,然后重命名,或者你需要一個編輯器,在這里我們推薦用?**Sublime Text**?。破解不破解,注冊不注冊都不會對你的使用有太多的影響。)
1. 新建文件
2. 輸入
~~~
hello,world
~~~
3. 保存為->“helloworld.html”,
4. 雙擊打開這個文件。 正常情況下都應該是用你的默認瀏覽器打開。只要是一個正常工作的現代瀏覽器,都應該可以看到上面顯示的是“Hello,world”。
這才是最短的 hello,world 程序,但是呢?在 Ruby 中會是這樣子的
~~~
2.0.0-p353 :001 > p "hello,world"
"hello,world"
=> "hello,world"
2.0.0-p353 :002 >
~~~
等等,如果你了解過 HTML 的話,會覺得這一點都不符合語法規則,但是他工作了,沒有什么比安裝完 Nginx 后看到 It works! 更讓人激動了。
遺憾的是,它可能無法在所有的瀏覽器上工作,所以我們需要去調試其中的 bug。
#### 調試 hello,world
我們會發現我們的代碼在瀏覽器中變成了下面的代碼,如果你和我一樣用的是 Chrome,那么你可以右鍵瀏覽器中的空白區域,點擊審查元素,就會看到下面的代碼。
~~~
<html>
<head></head>
<body>hello,world</body>
</html>
~~~
這個才是真正能在大部分瀏覽器上工作的代碼,所以復制它到編輯器里吧。
#### 說說 hello,world
我很不喜歡其中的,但是我也沒有找到別的方法來代替它們,所以這是一個設計得當的語言。甚至大部分人都說這算不上是一門真正的語言,不過 HTML 的原義是
> 超文本標記語言
所以我們可以發現其中的關鍵詞是標記——markup,也就是說 html 是一個 markup,head 是一個 markup,body 也是一個 markup。
然而,我們真正工作的代碼是在 body 里面,至于為什么是在這里面,這個問題就太復雜了。打個比方來說:
1. 我們所使用的漢語是人類用智慧創造的,我們所正在學的這門語言同樣也是人類創造的。
2. 我們在自己的語言里遵循著?**桌子是桌子,凳子是凳子**?的原則,很少有人會問為什么。
### 中文?
所以我們也可以把計算機語言與現實世界里用于交流溝通的語言劃上一個等號。而我們所要學習的語言,并不是我們最熟悉的漢語語言,所以我們便覺得這些很復雜,但是如果我們試著用漢語替換掉上面的代碼的話
~~~
<語言>
<頭><結束頭>
<身體>你好,世界<結束身體>
<結束語言>
~~~
這看上去很奇怪,只是因為是直譯過去的原因,也許你會覺得這樣會好理解一點,但是輸入上可就一點兒也不方便,因為這鍵盤本身就不適合我們去輸入漢字,同時也意味著可能你輸入的會有問題。
讓我們把上面的代碼代替掉原來的代碼然后保存,打開瀏覽器會看到下面的結果
~~~
<語言> <頭><結束頭> <身體>你好,世界<結束身體> <結束語言>
~~~
更不幸的結果可能是
~~~
<璇█> <澶?><緇撴潫澶?> <韜綋>浣犲ソ錛屼笘鐣?<緇撴潫韜綋> <緇撴潫璇█>
~~~
這是一個編碼問題,對中文支持不友好。
我們把上面的代碼改為和標記語言一樣的結構
~~~
<語言>
<頭></頭>
<身體>你好,世界</身體>
<結束語言>
~~~
于是我們看到的結果便是
~~~
<語言> <頭> <身體>你好,世界
~~~
被 Chrome 瀏覽器解析成什么樣了?
~~~
<html><head></head><body><語言>
<頭><!--頭-->
<身體>你好,世界<!--身體-->
<!--語言-->
</body></html>
~~~
以`<!--`開頭,`-->`結尾的是注釋,寫給人看的代碼,不是給機器看的,所以機器不會去理解這些代碼。
但是當我們把代碼改成
~~~
<whatwewanttosay>你好世界</whatwewanttosay>
~~~
瀏覽器上面顯示的內容就變成了
~~~
你好世界
~~~
或許你會覺得很神奇,但是這一點兒也不神奇,雖然我們的中文語法也遵循著標記語言的標準,但是我們的瀏覽器不支持中文標記。
結論:
1. 瀏覽器對中文支持不友好。
2. 瀏覽器對英文支持友好。
剛開始的時候不要對中文編程有太多的想法,這是很不現實的:
1. 現有的系統都是基于英語語言環境構建的,對中文支持不是很友好。
2. 中文輸入的速度在某種程度上來說沒有英語快。
我們離開話題已經很遠了,但是這里說的都是針對于那些不滿于英語的人來說的,只有當我們可以從頭構建一個中文系統的時候才是可行的,而這些就要將 CPU、軟件、硬件都包含在內,甚至我們還需要考慮重新設計 CPU 的結構,在某種程度上來說會有些不現實。或許,需要一代又一代人的努力。忘記那些吧,師夷之長技以制夷。
### 其他 HTML 標記
添加一個標題,
~~~
<html>
<head>
<title>標題</title>
</head>
<body>hello,world</body>
</html>
~~~
我們便可以在瀏覽器的最上方看到“標題”二字,就像我們常用的淘寶網,也包含了上面的東西,只是還包括了更多的東西,所以你也可以看懂那些我們可以看到的淘寶的標題。
~~~
<html>
<head>
<title>標題</title>
</head>
<body>
hello,world
<h1>大標題</h1>
<h2>次標題</h2>
<h3>...</h3>
<ul>
<li>列表1</li>
<li>列表2</li>
</ul>
</body>
</html>
~~~
更多的東西可以在一些書籍上看到,這邊所要說的只是一次簡單的語言入門,其他的東西都和這些類似。
### 小結
#### 美妙之處
我們簡單地上手了一門不算是語言的語言,瀏覽器簡化了這其中的大部分過程,雖然沒有 C 和其他語言來得有專業感,但是我們試著去開始寫代碼了。我們可能在未來的某一篇中可能會看到類似的語言,諸如 Python,我們所要做的就是
~~~
$ python file.py
=>hello,world
~~~
然后在終端上返回結果。只是因為在我看來學會 HTML 是有意義的,簡單的上手,然后再慢慢地深入,如果一開始我們就去理解指針,開始去理解類。我們甚至還知道程序是怎么編譯運行的時候,在這個過程中又發生了什么。雖然現在我們也沒能理解這其中發生了什么,但是至少展示了
1. 中文編程語言在當前意義不大,不現實,效率不高兼容性差
2. 語言的語法是固定的。(ps:雖然我們也可以進行擴充,我們將會在后來支持上述的中文標記。)
3. 已經開始寫代碼,而不是還在配置開發環境。
4. 隨身的工具才是最好的,最常用的 code 也才是實在的。
#### 更多
我們還沒有試著去解決“某商店里的糖一顆5塊錢,小明買了3顆糖,小明一共花了多少錢”的問題。也就是說我們學會的是一個還不能解決實際問題的語言,于是我們還需要學點東西,比如 JavaScript, CSS。我們可以將 JavaScript 理解為解決問題的語言,HTML 則是前端顯示,CSS 是配置文件,這樣的話,我們會在那之后學會成為一個近乎專業的程序員。我們剛剛學習了一下怎么在前端顯示那些代碼的行為,于是我們還需要 JavaScript。
## CSS
如果說 HTML 是建筑的框架,CSS 就是房子的裝修。那么 JavaScript 呢,我聽到的最有趣的說法是小三——還是先讓我們回到代碼上來吧。
下面就是我們之前說到的代碼,CSS 將 Red 三個字母變成了紅色。
~~~
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p id="para" style="color:red">Red</p>
</body>
<script type="text/javascript" src="app.js"></script>
</html>
~~~
只是,
~~~
var para=document.getElementById("para");
para.style.color="blue";
~~~
將字體變成了藍色,CSS+HTML 讓頁面有序的工作著,但是 JavaScript 卻打亂了這些秩序,有著唯恐世界不亂的精彩,也難怪被冠以小三之名了——或許終于可以理解,為什么以前人們對于 JavaScript 沒有好感了——不過這里要講的是正室,也就是 CSS,這時還沒有 JavaScript。

Red Fonts
### 簡介
這不是一篇專業講述 CSS 的書籍,所以我不會去說 CSS 是怎么來的,有些東西我們既然可以很容易從其他地方知道,也就不需要花太多時間去重復。諸如重構等這些的目的之一也在于去除重復的代碼,不過有些重復是不可少的,也是有必要的,而通常這些東西可能是由其他地方復制過來的。
到目前為止我們沒有依賴于任何特殊的硬件或者是軟件,對于我們來說我們最基本的需求就是一臺電腦,或者可以是你的平板電腦,當然也可以是你的智能手機,因為他們都有個瀏覽器,而這些都是能用的,對于我們的 CSS 來說也不會有例外的。
CSS(Cascading Style Sheets),到今天我也沒有記得他的全稱,CSS 還有一個中文名字是層疊式樣式表,事實上翻譯成什么可能并不是我們關心的內容,我們需要關心的是他能做些什么。作為三劍客之一,它的主要目的在于可以讓我們方便靈活地去控制 Web 頁面的外觀表現。我們可以用它做出像淘寶一樣復雜的界面,也可以像我們的書本一樣簡單,不過如果要和我們書本一樣簡單的話,可能不需要用到 CSS。HTML 一開始就是依照報紙的格式而設計的,我們還可以繼續用上面說到的編輯器,又或者是其他的。如果你喜歡 DreamWeaver 那也不錯,不過一開始使用 IDE 可無助于我們寫出良好的代碼。
忘說了,CSS 也是有版本的,和 Windows,Linux 內核等等一樣,但是更新可能沒有那么頻繁,HTML 也是有版本的,JavaScript 也是有版本的,復雜的東西不是當前考慮的內容。
#### 代碼結構
對于我們的上面的 Red 示例來說,如果沒有一個好的結構,那么以后可能就是這樣子。
~~~
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p style="font-size: 22px;color: #f00;text-align: center;padding-left: 20px;">如果沒有一個好的結構</p>
<p style="font-size: 44px;color: #3ed;text-indent: 2em;padding-left: 2em;">那么以后可能就是這樣子。。。。</p>
</body>
</html>
~~~
雖然我們看到的還是一樣的:

No Style
于是我們就按各種書上的建議重新寫了上面的代碼
~~~
<!DOCTYPE html>
<html>
<head>
<title>CSS example</title>
<style type="text/css">
.para{
font-size: 22px;
color: #f00;
text-align: center;
padding-left: 20px;
}
.para2{
font-size: 44px;
color: #3ed;
text-indent: 2em;
padding-left: 2em;
}
</style>
</head>
<body>
<p class="para">如果沒有一個好的結構</p>
<p class="para2">那么以后可能就是這樣子。。。。</p>
</body>
</html>
~~~
總算比上面好看也好理解多了,這只是臨時的用法,當文件太大的時候,正式一點的寫法應該如下所示:
~~~
<!DOCTYPE html>
<html>
<head>
<title>CSS example</title>
<style type="text/css" href="style.css"></style>
</head>
<body>
<p class="para">如果沒有一個好的結構</p>
<p class="para2">那么以后可能就是這樣子。。。。</p>
</body>
</html>
~~~
我們需要
~~~
<!DOCTYPE html>
<html>
<head>
<title>CSS example</title>
<link href="./style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p class="para">如果沒有一個好的結構</p>
<p class="para2">那么以后可能就是這樣子。。。。</p>
</body>
</html>
~~~
然后我們有一個像 app.js 一樣的 style.css 放在同目錄下,而他的內容便是
~~~
.para{
font-size: 22px;
color: #f00;
text-align: center;
padding-left: 20px;
}
.para2{
font-size: 44px;
color: #3ed;
text-indent: 2em;
padding-left: 2em;
}
~~~
這代碼和 JS 的代碼有如此多的相似
~~~
var para={
font_size: '22px',
color: '#f00',
text_align: 'center',
padding_left: '20px',
}
~~~
而22px、20px以及#f00都是數值,因此:
~~~
var para={
font_size: 22px,
color: #f00,
text_align: center,
padding_left: 20px,
}
~~~
目測差距已經盡可能的小了,至于這些話題會在以后討論到,如果要讓我們的編譯器更正確的工作,那么我們就需要非常多這樣的符號,除非你樂意去理解:
~~~
(dotimes (i 4) (print i))
~~~
總的來說我們減少了符號的使用,但是用 lisp 便帶入了更多的括號,不過這是一種簡潔的表達方式,也許我們可以在其他語言中看到。
~~~
\d{2}/[A-Z][a-z][a-z]/\d{4}
~~~
上面的代碼,是為了從一堆數據中找出“某日/某月/某年”。如果一開始不理解那是正則表達式,就會覺得那個很復雜。
這門語言可能是為設計師而設計的,但是設計師大部分還是不懂編程的,不過相對來說這門語言還是比其他語言簡單易懂一些。
### 樣式與目標
如下所示,就是我們的樣式
~~~
.para{
font-size: 22px;
color: #f00;
text-align: center;
padding-left: 20px;
}
~~~
我們的目標就是
> 如果沒有一個好的結構
所以樣式和目標在這里牽手了,問題是他們是如何在一起的呢?下面就是 CSS 與 HTML 溝通的重點所在了:
### 選擇器
我們用到的選擇器叫做類選擇器,也就是 class,或者說應該稱之為 class 選擇器更合適。與類選擇器最常一起出現的是 ID 選擇器,不過這個適用于比較高級的場合,諸如用 JS 控制 DOM 的時候就需要用到 ID 選擇器。而基本的選擇器就是如下面的例子:
~~~
p.para{
color: #f0f;
}
~~~
將代碼添加到 style.css 的最下面會發現“如果沒有一個好的結構”變成了粉紅色,當然我們還會有這樣的寫法
~~~
p>.para{
color: #f0f;
}
~~~
為了產生上面的特殊的樣式,雖然不好看,但是我們終于理解什么叫層疊樣式了,下面的代碼的權重比上面高,也因此有更高的優先規則。
而通常我們可以通過一個
~~~
p{
text-align: left;
}
~~~
這樣的元素選擇器來給予所有的 p 元素一個左對齊。
還有復雜一點的復合型選擇器,下面的是 HTML 文件
~~~
<!DOCTYPE html>
<html>
<head>
<title>CSS example</title>
<link href="./style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p class="para">如果沒有一個好的結構</p>
<div id="content">
<p class="para2">那么以后可能就是這樣子。。。。</p>
</div>
</body>
</html>
~~~
還有 CSS 文件
~~~
.para{
font-size: 22px;
color: #f00;
text-align: center;
padding-left: 20px;
}
.para2{
font-size: 44px;
color: #3ed;
text-indent: 2em;
padding-left: 2em;
}
p.para{
color: #f0f;
}
div#content p {
font-size: 22px;
}
~~~
### 更有趣的 CSS
一個包含了 para2 以及 para_bg 的例子
~~~
<div id="content">
<p class="para2 para_bg">那么以后可能就是這樣子。。。。</p>
</div>
~~~
我們只是添加了一個黑色的背景
~~~
.para_bg{
background-color: #000;
}
~~~
重新改變后的網頁變得比原來有趣了很多,所謂的繼承與合并就是上面的例子。
我們還可以用 CSS3 做出更多有趣的效果,而這些并不在我們的討論范圍里面,因為我們討論的是 be a geek。
或許我們寫的代碼都是那么的簡單,從 HTML 到 JavaScript,還有現在的 CSS,只是總有一些核心的東西,而不是去考慮那些基礎語法,基礎的東西我們可以在實踐的過程中一一發現。但是我們可能發現不了,或者在平時的使用中考慮不到一些有趣的用法或者說特殊的用法,這時候可以通過觀察一些精致設計的代碼中學習到。復雜的東西可以變得很簡單,簡單的東西也可以變得很復雜。
## JavaScript
JavaScript 現在已經無處不在了,也許你正打開的某個網站,他便可能是 node.js+json+javascript+mustache.js 完成的,雖然你還沒理解上面那些是什么,也正是因為你不理解才需要去學習更多的東西。但是你只要知道 JavaScript 已經無處不在了,它可能就在你手機上的某個 app 里,就在你瀏覽的網頁里,就運行在你 IDE 中的某個進程里。
### hello,world
這里我們還需要有一個 helloworld.html,JavaScript 是專為網頁交互而設計的腳本語言,所以我們一點點來開始這部分的旅途,先寫一個符合標準的 helloworld.html
~~~
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
~~~
然后開始融入我們的 JavaScript,向 HTML 中插入JavaScript 的方法,就需要用到 HTML 中的 標簽,我們先用頁面嵌入的方法來寫 helloworld。
~~~
<!DOCTYPE html>
<html>
<head>
<script>
document.write('hello,world');
</script>
</head>
<body></body>
</html>
~~~
按照標準的寫法,我們還需要聲明這個腳本的類型
~~~
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
document.write('hello,world');
</script>
</head>
<body></body>
</html>
~~~
沒有顯示 hello,world ?試試下面的代碼
~~~
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
document.write('hello,world');
</script>
</head>
<body>
<noscript>
disable Javascript
</noscript>
</body>
</html>
~~~
### JavaScriptFul
我們需要讓我們的代碼看上去更像是 js,同時是以 js 結尾。就像 C 語言的源碼是以 C 結尾的,我們也同樣需要讓我們的代碼看上去更正式一點。于是我們需要在 helloworld.html 的同一文件夾下創建一個 app.js 文件,在里面寫著
~~~
document.write('hello,world');
~~~
同時我們的 helloworld.html 還需要告訴我們的瀏覽器 js 代碼在哪里
~~~
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<noscript>
disable Javascript
</noscript>
</body>
</html>
~~~
#### 從數學出發
讓我們回到第一章講述的小明的問題,**從實際問題下手編程,更容易學會編程**。小學時代的數學題最喜歡這樣子了——某商店里的糖一個5塊錢,小明買了3個糖,小明一共花了多少錢。在編程方面,也許我們還算是小學生。最直接的方法就是直接計算 3x5=?
~~~
document.write(3*5);
~~~
document.write 實際也我們可以理解為輸出,也就是往頁面里寫入 3*5 的結果,在有雙引號的情況下會輸出字符串。我們便會在瀏覽器上看到15,這便是一個好的開始,也是一個糟糕的開始。
#### 設計和編程
對于實際問題,如果我們只是止于所要得到的結果,很多年之后,我們就成為了 code monkey。對這個問題進行再一次設計,所謂的設計有些時候會把簡單的問題復雜化,有些時候會使以后的擴展更加簡單。這一天因為這家商店的糖價格太高了,于是店長將價格降為了4塊錢。
~~~
document.write(3*4);
~~~
于是我們又得到了我們的結果,但是下次我們看到這些代碼的時候沒有分清楚哪個是糖的數量,哪個是價格,于是我們重新設計了程序
~~~
tang=4;
num=3;
document.write(tang*num);
~~~
這才能叫得上是程序設計,或許你注意到了“;”這個符號的存在,我想說的是這是另外一個標準,我們不得不去遵守,也不得不去 fuck。
#### 函數
記得剛開始學三角函數的時候,我們會寫
~~~
sin 30=0.5
~~~
而我們的函數也是類似于此,換句話說,因為很多搞計算機的先驅都學好了數學,都把數學世界的規律帶到了計算機世界,所以我們的函數也是類似于此,讓我們從一個簡單的開始。
~~~
function hello(){
return document.write("hello,world");
}
hello();
~~~
當我第一次看到函數的時候,有些小激動終于出現了。我們寫了一個叫 hello 的函數,它返回了往頁面中寫入 hello,world 的方法,然后我們調用了 hello 這個函數,于是頁面上有了 hello,world。
~~~
function sin(degree){
return document.write(Math.sin(degree));
}
sin(30);
~~~
在這里 degree 就稱之為變量。 于是輸出了 -0.9880316240928602,而不是 0.5,因為這里用的是弧度制,而不是角度制。
~~~
sin(30)
~~~
的輸出結果有點類似于sin 30。寫括號的目的在于,括號是為了方便解析,這個在不同的語言中可能是不一樣的,比如在 Ruby 中我們可以直接用類似于數學中的表達:
~~~
2.0.0-p353 :004 > Math.sin 30
=> -0.9880316240928618
2.0.0-p353 :005 >
~~~
我們可以在函數中傳入多個變量,于是我們再回到小明的問題,就會這樣去編寫代碼。
~~~
function calc(tang,num){
result=tang*num;
document.write(result);
}
calc(3,4);
~~~
但是從某種程度上來說,我們的 calc 做了計算的事又做了輸出的事,總的來說設計上有些不好。
#### 重新設計
我們將輸出的工作移到函數的外面,
~~~
function calc(tang,num){
return tang*num;
}
document.write(calc(3,4));
~~~
接著我們用一種更有意思的方法來寫這個問題的解決方案
~~~
function calc(tang,num){
return tang*num;
}
function printResult(tang,num){
document.write(calc(tang,num));
}
printResult(3, 4)
~~~
看上去更專業了一點點,如果我們只需要計算的時候我們只需要調用 calc,如果我們需要輸出的時候我們就調用 printResult 的方法。
#### object 和函數
我們還沒有說清楚之前我們遇到過的 document.write 以及 Math.sin 的語法為什么看上去很奇怪,所以讓我們看看他們到底是什么,修改 app.js 為以下內容
~~~
document.write(typeof document);
document.write(typeof Math);
~~~
typeof document 會返回 document 的數據類型,就會發現輸出的結果是
~~~
object object
~~~
所以我們需要去弄清楚什么是 object。對象的定義是
> 無序屬性的集合,其屬性可以包含基本值、對象或者函數。
創建一個 object,然后觀察這便是我們接下來要做的
~~~
store={};
store.tang=4;
store.num=3;
document.write(store.tang*store.num);
~~~
我們就有了和 document.write 一樣的用法,這也是對象的美妙之處,只是這里的對象只是包含著基本值,因為
~~~
typeof story.tang="number"
~~~
一個包含對象的對象應該是這樣子的。
~~~
store={};
store.tang=4;
store.num=3;
document.writeln(store.tang*store.num);
var wall=new Object();
wall.store=store;
document.write(typeof wall.store);
~~~
而我們用到的 document.write 和上面用到的 document.writeln 都是屬于這個無序屬性集合中的函數。
下面代碼說的就是這個無序屬性集合中的函數。
~~~
var IO=new Object();
function print(result){
document.write(result);
};
IO.print=print;
IO.print("a obejct with function");
IO.print(typeof IO.print);
~~~
我們定義了一個叫 IO 的對象,聲明對象可以用
~~~
var store={};
~~~
又或者是
~~~
var store=new Object{};
~~~
兩者是等價的,但是用后者的可讀性會更好一點,我們定義了一個叫print的函數,他的作用也就是 document.write,IO 中的print 函數是等價于 print() 函數,這也就是對象和函數之間的一些區別,對象可以包含函數,對象是無序屬性的集合,其屬性可以包含基本值、對象或者函數。
復雜一點的對象應該是下面這樣的一種情況。
~~~
var Person={name:"phodal",weight:50,height:166};
function dream(){
future;
};
Person.future=dream;
document.write(typeof Person);
document.write(Person.future);
~~~
而這些會在我們未來的實際編程過程中用得更多。
### 面向對象
開始之前先讓我們簡化上面的代碼,
~~~
Person.future=function dream(){
future;
}
~~~
看上去比上面的簡單多了,不過我們還可以簡化為下面的代碼。。。
~~~
var Person=function(){
this.name="phodal";
this.weight=50;
this.height=166;
this.future=function dream(){
return "future";
};
};
var person=new Person();
document.write(person.name+"<br>");
document.write(typeof person+"<br>");
document.write(typeof person.future+"<br>");
document.write(person.future()+"<br>");
~~~
只是在這個時候 Person 是一個函數,但是我們聲明的 person 卻變成了一個對象?**一個Javascript函數也是一個對象,并且,所有的對象從技術上講也只不過是函數。**?這里的“”是 HTML 中的元素,稱之為 DOM,在這里起的是換行的作用,我們會在稍后介紹它,這里我們先關心下 this。this 關鍵字表示函數的所有者或作用域,也就是這里的 Person。
上面的方法顯得有點不可取,換句話說和一開始的
~~~
document.write(3*4);
~~~
一樣,不具有靈活性,因此在我們完成功能之后,我們需要對其進行優化,這就是程序設計的真諦——解決完實際問題后,我們需要開始真正的設計,而不是解決問題時的編程。
~~~
var Person=function(name,weight,height){
this.name=name;
this.weight=weight;
this.height=height;
this.future=function(){
return "future";
};
};
var phodal=new Person("phodal",50,166);
document.write(phodal.name+"<br>");
document.write(phodal.weight+"<br>");
document.write(phodal.height+"<br>");
document.write(phodal.future()+"<br>");
~~~
于是,產生了這樣一個可重用的 JavaScript 對象, this 關鍵字確立了屬性的所有者。
### 其他
JavaScript 還有一個很強大的特性,也就是原型繼承,不過這里我們先不考慮這些部分,用盡量少的代碼及關鍵字來實際我們所要表達的核心功能,這才是這里的核心,其他的東西我們可以從其他書本上學到。
所謂的繼承,
~~~
var Chinese=function(){
this.country="China";
}
var Person=function(name,weight,height){
this.name=name;
this.weight=weight;
this.height=height;
this.futrue=function(){
return "future";
}
}
Chinese.prototype=new Person();
var phodal=new Chinese("phodal",50,166);
document.write(phodal.country);
~~~
完整的 JavaScript 應該由下列三個部分組成:
* 核心(ECMAScript)——核心語言功能
* 文檔對象模型(DOM)——訪問和操作網頁內容的方法和接口
* 瀏覽器對象模型(BOM)——與瀏覽器交互的方法和接口
我們在上面講的都是 ECMAScript,也就是語法相關的,但是 JS 真正強大的,或者說我們最需要的可能就是對 DOM 的操作,這也就是為什么 jQuery 等庫可以流行的原因之一,而核心語言功能才是真正在哪里都適用的,至于 BOM,真正用到的機會很少,因為沒有完善的統一的標準。
一個簡單的 DOM 示例,
~~~
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<noscript>
disable Javascript
</noscript>
<p id="para" style="color:red">Red</p>
</body>
<script type="text/javascript" src="app.js"></script>
</html>
~~~
我們需要修改一下 helloworld.html 添加
~~~
<p id="para" style="color:red">Red</p>
~~~
同時還需要將 script 標簽移到 body 下面,如果沒有意外的話我們會看到頁面上用紅色的字體顯示 Red,修改 app.js。
~~~
var para=document.getElementById("para");
para.style.color="blue";
~~~
接著,字體就變成了藍色,有了 DOM 我們就可以對頁面進行操作,可以說我們看到的絕大部分的頁面效果都是通過 DOM 操作實現的。
#### 美妙之處
這里說到的 JavaScript 僅僅只是其中的一小小部分,忽略掉的東西很多,只關心的是如何去設計一個實用的 app,作為一門編程語言,他還有其他強大的內制函數,要學好需要一本有價值的參考書。這里提到的只是其中的不到20%的東西,其他的80%或者更多會在你解決問題的時候出現。
* 我們可以創建一個對象或者函數,它可以包含基本值、對象或者函數。
* 我們可以用 JavaScript 修改頁面的屬性,雖然只是簡單的示例。
* 我們還可以去解決實際的編程問題。