JS and NG - ntut iLab 2015/07/14

90
JavaScript AngularJS 技術研討會 李柏鋐 (BOHONG LI) 2015 / 07 / 14 1

Transcript of JS and NG - ntut iLab 2015/07/14

JavaScript 與 AngularJS技術研討會

李柏鋐 (BOHONG LI)

2015 / 07 / 14

1

大綱

•JavaScript•歷史簡介•基礎使用介紹•進階功能

•AngularJS•基礎介紹•進階功能

2

JavaScript 是物件導向程式語言只是物件的實作方式採用原型繼承

3

JavaScript 歷史演進

4

JS 歷史

•由Brendan Eich創造• 只花10天就將JS做出來,比做期末專案還厲害!

• 因為時間很短,所以乾脆做一個可塑性高的語言• 根本就是到處留洞

•因為微軟也弄了一個很像的東西-JScript

•歐洲電腦製造商協會(ECMA)要求統一

•最後產生ECMAScript 標準

5

JS 歷史 – cont.

•大概從IE 5.5開始就支援ECMAScript 3了• 再之前的就不考古了

•接著一直想要將亂七八糟的語言特性掰正…• -> ECMAScript 4

• 結果沒有成功…… 這個版本就消失了

•妥協後,修改一些功能• -> ECMAScript 5 橫空出世!!

• 這時候大概是Google開始搞傳說中的AJAX時代(Gmail),各種網頁的都開始流行使用AJAX技術,到後來FB的出現

6

JS 歷史 – cont.

•因為ECMAScript 5修的還不錯,而且有各種神框架,舉凡• jQuery• CommonJS• RequireJS• ExtJS• Ember• React

•所以JS越來越流行了

•因為使用的人多反應的聲音多,也就讓ECMAScript改版的速度加速演進

7

JS 歷史 – cont.

•到了 2015 年 6月ECMAScript 第六版ECMAScript2015 正式通過,這次的改版將整個JS規格重新定義

•加入眾所期望很久的各種功能• 新的語法: let , const , class, module , for…of …

• 新的基本型別: Symbol

• 新的資料結構:Typed Array , Map , Set

• 新的內建類別: Promise , Proxy , Reflect

• 強化原有架構: String , Number , Math , RegExp , Object , Array 全員強化

8

JS 歷史 – cont.

•不過由於瀏覽器支援度尚未達標,預計大約半年後會完全支援

•微軟於Windows 10的Edge瀏覽器中已經開始支援

• Visual Studio 2015 也完全支援新的語法

•但是,請在框架改版之後再用

9

JS 歷史 – cont.

敬請期待AngularJS 2.0 (?)

10

JavaScript 基本介紹採用ECMAScript 5

11

原生資料型別

•null

•undefined

•number

•boolean

•string

12

Null

•代表沒有值

•空的

•一個變數可以被指定為null代表他是空的,沒有值

13

Undefined

•當一個變數被宣告,但還未給任何值的時候就是undefined

•你無法對undefined做任何事,當你這麼做的時候,會噴一個錯誤出來

14

Boolean

•代表著true與 false其中一種值

15

Number

•代表著數字,不管是正數負數整數或是小數

•用C語言來說這就是個Double雙精確浮點數

•他實做了IEEE 754標準所規範的64位元數字編碼

•也當然實做了標準中所定義的NaN(Not a Number)

•當計算過程中出現了無法成為數字的東西,例如虛數或是字串,就會產生這個結果

• NaN 不等於NaN 這是規定!

• isNaN 他會幫你做隱含轉換……有點雷

16

Number – cont. isNaN的問題

•像是 isNaN(“haha”) 會回傳true

• isNaN(“”) 會回傳false

•如果真要測試是否為NaN可用以下這個方式

17

Number – cont.

•當Number 在做位元運算時,會先轉換成32位元有號整數,運算完再轉回來。• 明明就有整數還不開來用…

18

String

•所有的字串都是Unicode ,是16 位元

•但是一些意外的錯估,後來出現了4 bytes代表一個字的時候……

•在遇到這種情況時,文字的長度會算錯、取字元時會拿不到東西• 像是用String.charAt 取字元的時候

•這些問題在ECMAScript 2015 有解決

19

原生資料型別都有包裹器(讓他成為物件),除了null, undefined以外每個成功的男人背後都有一個偉大的女人

20

包裹器 (wrapper)將原生型別變成物件

21

原生型別包裹器

•與往常一樣,使用new 產生一個instance

22

千萬別用包裹器!用了被雷到我不管

23

原生型別包裹器

•用了包裹器,typeof 的結果都是object了!• 只要用了金坷垃小麥畝產一千八

•可是瑞凡,String物件提供好多好棒棒的方法耶

24

String wrapper method

• Length

• charAt

• Indexof

• Replace

• Slice

• Substr

• Trim

• toLowerCase

• toLocaleUpperCase

25

沒關係,你可以直接在原生型別上呼叫字串物件才能用的方法

26

Call string method on primitive value

•真是太神奇了

•其實他幫你做自動型別轉換了…

27

Call string method on primitive value 原理

•運作原理就是:1. 先幫你將原生型別使用包裹器包

裝2. 再呼叫物件的方法3. 再解回原生型別

28

其他淺規則 - 隱含轉換

• JS的隱含轉換規則非常詭異,又不好記……

•尤其在date物件上世界竟然是逆轉的

•所以建議少用隱含轉換,比較時請使用三個等於的運算子

•三個等於代表兩個變數型別要先一樣,再比值

29

分號插入機制

• JS 很神你忘記加分號他會替你補……

•但這補分號的方式又有規則,可能不小心會踩到雷

• return , throw , break , continue , ++ , --

•以上這幾個東西單獨出現在一行時要多加注意

•像是++運算子是否前後忘記加變數?

30

分號插入機制 – cont.

•上面提到的return不能單獨在一行是因為JS有個隱含的分號插入規則是• 當此行與下一行合在一起的時候不會出現錯誤,就不會插入分號

• 但是在return , throw , break , continue , ++ , -- 上是不會看下一行,直接插入分號

31

你以為前面那些已經是JS最雷了嗎?

32

不小心就會變成全域變數

•大家都知道全域變數不好

•盡量不要用全域變數

•但是你不小心可能就會宣告了全域變數而不知道• 忘記加上var是很危險的,雖然程式還是可以動,但是sum變成了全域變數

33

避免忘記加var

•在ECMAScript 5 中可以使用嚴格模式讓執行環境檢查出這種忘記加var 的狀況,並丟Error出來

•使用方式不過在檔案開頭加上一字串• 其實也可以在每個function第一行加上

34

Variable Hoisting 變數提升

•這點有點像C語言

•還記得C語言的變數宣告一定要寫在最上面嗎?

• JS 也是如此!

35

Variable Hoisting – cont.

36

也因為有這特性

•就有人建議將所有變數都先宣告在最上面,

•並且只用一個var 搞定

•這就是 single var pattern• 還可以順便寫註解

37

變數Scope

•眼尖的人可以發現,明明宣告在for迴圈內的變數,卻會被放到前面去

•因為JS中變數的活動範圍(Scope)是以function做為分界,這也是為什麼會說function是一級Class了

38

但是 (but)什麼!!!!

39

變數 Scope 例外情形

•前述的變數Scope有個例外

•這個例外就發生在例外處理上

• catch的exception變數只在catch中有用

•但是catch中宣告其他變數則會與前面一樣

40

物件與陣列

•宣告時盡量使用{} 與 [] 的方式,• 不要用 new Object() , new Array()

41

Closures 與 Immediate function

• Closure 指的是 function 中有function

• Immediate function 是指function宣告後馬上執行

42

Function 命名的一些現象

•當把一個具名function 指定給一個變數時,該名稱只有在該function裡面才可作用

43

Function 中的 “this”

• Function 之內使用到的this 會綁定到呼叫者給傳送給函數的接收者

•一般呼叫函式時,接收者為綁定到全域

•全域這個Scope又是綁定到 window 去(在瀏覽器中)

•所以一般呼叫函式時,函式中的this為window…

44

但是用了嚴格模式後又是不同世界了Use strict mode is another world

45

使用了嚴格模式後的 “this”

•使用了嚴格模式後,一般呼叫函式this 所綁定的是undefined

46

函式的三種業務

•在JS中,函式是所謂第一級物件•Functions are first class object in JS

•所以Function有各種業務•當作一般的函式•剛好碰巧可以當作物件的成員方法•還可以順便當作建構子使用

47

函式的三種業務 - cont.

•第一種當作一般的函式是一件很正常的事情

•第二可以當作物件的成員函式純屬意外• 這只是當你使用物件呼叫函式時,this 就不小心綁定到了該物件

•第三種最奇妙,可以當作建構子使用• 當你在函式前面加上了new,又是不同的事情了

48

函式做為建構子?

•當一個函式被當作建構子呼叫時• 會產生一個新的物件,然後綁定到函式的this

• 最後預設會回傳剛剛所產生的那個this

•重點• 自動產生this

• 自動回傳this

•但是• 你也可以自己改寫回傳值

49

函式做為建構子?

50

Function 的呼叫

•函式呼叫分三種• call

• apply

• bind

51

Function 的呼叫 – cont.

•這三種功能都有一個特點:• 可以指定函式被呼叫的時候this是什麼

• Func.call(thisArg[,arg1 [,arg2[, …]]])

• Func.apply(thisArg, argsArray)

• Func.bind(thisArg[,arg1 [,arg2[, …]]]);

52

Function 的呼叫 – cont.

•乍看之下call 與 bind 很像• 但是卻不一樣

• Call 會直接呼叫函式

• Bind 會回傳新的函式

53

Function 的呼叫 – cont.

•所以說 Bind 通常會用在callback function中,當你的callback function中有使用到this時,你不會知道到時候你被呼叫的時候,呼叫者是誰,也就無法決定this 是什麼…就會導致不可預期的錯誤

•或許你可以用一些神祕的方法達成功能,像是

• var that = this;

•然後在callback 中都用that 也行

54

再講物件導向

• JavaScript是物件導向語言

•所以理所當然要有封裝、繼承、多型

55

物件封裝

•直接寫物件就好了,根本不用什麼Class

56

物件繼承

•透過神奇prototype 達到繼承• prototype 是串起整個JS繼承架構的關鍵

• 每個Object都會有prototype

57

58

物件繼承

•當然,child.prototype 把father new出來後,你想怎麼改他沒人有意見

59

關於prototype

•將無狀態的method放置prototype中•無狀態的method指的是一個method傳給他固定的參數,不會因為時空背景前後文不同,而有不同的結果,他只關心他的輸入,與他要做的事,並產生輸出。

•因為放置在this當中,每new一個新的物件物件當中就會有一個一模一樣的函式占用記憶體空間

•而且根據測試,在prototype的函式效能比較好• 雖然他要從繼承鍊中去找函式

60

物件多型

•在JS中,你愛呼叫什麼方法就呼叫,反正沒有型別檢查

•查不到你要呼叫的東西就噴錯誤給你看而已

61

62

結語

•可能是這些狀況太詭異,所以在新的版本中引進了class 的保留字,可以用來宣告物件

•還引入了let 取代var的變數宣告方式• Let 的 scope比較好預測

63

其他JS編寫技巧

•變數的初始化

•模組化的作法

• Callback 地獄

64

變數初始化

• 使用者呼叫函式可以選擇不傳參數給你• 會變成undefined

• 也可以多傳很多給你,就當作沒看到• 但是一切都會記在arguments這個變數中

• 有時候你需要給參數預設值

• 注意• 當你的參數可以接收空字串或是0 這種會被隱含轉換為

false 的東西時• 就會發生不可預料的狀況.

• 解法:可以判斷是否為undefined

• 別讓undefined 有詭異的意義

65

模組化

•使用立即執行函式將模組包起來區隔變數Scope

66

Callback 地獄

67

解法

•可以將函式改為遞迴呼叫,或是用promises

68

JavaScript 還有很多很詭異很可怕的東西其他的請參考 JavaScript Pattern 與 Effective JavaScript :駕馭JavaScript的68個具體做法

69

步入AngularJS

70

AngularJS 核心概念

• Model-View-Controller 概念

• Data-binding 資料綁定

• Dependency Injection 依賴注入

• Directives 提供強大的html擴充

71

MVC

72

Data binding

• Controller 中所控制的Model資料可以與View進行雙向綁定

•當View資料更新或是Model資料更新時,就可以馬上反應

73

Dependency injection

•可以方便抽換想要使用的物件

•方便進行TDD(Test-Driven development)開發

•需要用到的東西由Module 統一控制,不需要自己去產生

74

Directive

•擴充HTML的功能

•像是大家常用到的ion-view 或是 ng-app 皆為directive

•可將常用功能寫成Directive方便使用

75

NG 的應用問題

76

1. 不要使用global function做controller

•以前可以用global function做為controller ,在官網可以看到很多例子,但是這個功能是做來給官網Demo用的

•請用正統的方式宣告

77

一些Controller不能做的事

•不要在Controller中產生HTML的語法,用directive達成

•格式化輸入的資料 建議使用angularJS Form Controller 達成,也就是說一個form 就一個controller

•輸出資料的格式變更,使用Filter 功能,如果沒有你想要的自己寫

•在Controller中共享狀態,使用Service的功能達成,因為Service通常都是Singleton

78

Module 的問題

•第一次宣告Module的時候需要進行DI

•第二次開始使用,不能指定DI

79

AngualrJS 調用外部函式庫時

•因為Angular自己有一套運行的生命週期,只有Angular內的方法NG才會知道,如果是外部的Library (像是socket.io , 操作DOM, strophe)皆為外部Library

•可以將外部Library包裝成NG可以知道的功能,利用Service 的方式包裝,並且使用$on 或是$boardcast 進行呼叫

•如果在Controller中用到外部函式更改了一些東西最後可以呼叫$apply 讓NG知道有東西被變更了

80

盡量使用NG包裝好的Service

•礙於NG自己有一套生命週期管理,所以多使用NG包裝好的Service可以減少不知名的錯誤,像是資料有更新View不知道

DOM API NG Service

window $window

setTimeout $timeout

setInterval $interval

window.location $location

console $log

document $document

81

AngularJS 的Promise

•在NG中是使用$q,為promise的簡單實作

•使用方式:

82

AngularJS 的Promise

• 1. 使用$q.defer() 創造一個promise • Defer : 延遲

• 2. 呼叫了一些非同步未來才會完成的方法後直接回傳promise

• 3. 在非同步的callback中使用resolve 或是reject 告訴promise 事情處理的怎麼樣• Resolve : 事情解決了,並且可以帶參數呼叫

callback

• Reject:剛剛要做的事情被拒絕了,發生了一些問題,並且附上理由

83

AngularJS Promise的使用

• Promise.then( resolveCallbackFn, rejectCallbackFn , notifyFn)

• then會回傳一個新的Promise,所以你可以串接then

• Promise.then(resolveCallbackFn, …).thne( resolveCallbackFn, …).then…..

84

Promise串接的目的

•有時又Promise執行完進行的resolve不一定是真的resolve

•像是$http呼叫WS回傳結果後,說不定其實是有問題的,像是使用者未登入,但是對$http來說是呼叫成功,會使用resolve

•因此可以在第一個then中做資料處理,再傳遞到下一層的Promise

85

RESTful

•為Representational state transfer 縮寫

•是一種WS的API定義規則

•與SOAP或XML-RPC比起來相對簡單

• RESTful 是使用HTTP Vers 與網址進行API的呼叫

•可以方便的定義CRUD

86

HTTP Vers

• HTTP 常用的動詞為 GET 與 POST

•而比較少用到的為 PUT 與 DELETE

•在RESTful 中使用這四種動詞

87

API 模式

• C create• POST /shops

• R read• Read all data

• GET /shops

• Read a specific ID (primary key)• GET /shops/id

• U update• PUT /shops/id

• D delete• Delete /shops/id

88

使用ngResource 連接API

• $resource(‘apiurl’)• $resource(‘http://apps.csie.ntut.edu.tw/shops/:id’)

• 會回傳一個物件包含以下方法• Get

• Save

• Query

• Remove

• Delete

89

範例

90