React簡史
A declarative, efficient, and flexible JavaScript library for building user interfaces. https://facebook.github.io/react/
一個聲明式的,高效的,和用于構建用戶界面的靈活的JavaScript庫。
聲明式編程
編程語言的主要類型
Common programming paradigms include imperative which allows side effects, functional which disallows side effects, declarative which does not state the order in which operations execute (常見的編程語言類型包括允許有副作用的命令式編程,不允許副作用的函數式編程和不描述操作執行順序的聲明式編程)
A programming paradigm is a fundamental style of computer programming. There are four main paradigms: imperative, declarative, functional (which is considered a subset of the declarative paradigm) and object-oriented.
Declarative programming : is a programming paradigm that expresses the logic of a computation(What do) without describing its control flow(How do). Some well-known examples of declarative domain specific languages (DSLs) include CSS, regular expressions, and a subset of SQL (SELECT queries, for example) Many markup languages such as HTML, MXML, XAML, XSLT… are often declarative. The declarative programming try to blur the distinction between a program as a set of instructions and a program as an assertion about the desired answer.
Imperative programming : is a programming paradigm that describes computation in terms of statements that change a program state. The declarative programs can be dually viewed as programming commands or mathematical assertions.
Functional programming : is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state. In a pure functional language, such as Haskell, all functions are without side effects, and state changes are only represented as functions that transform the state.
( 出處:維基百科)
編程語言主要有四種類型
聲明式編程:專注于”做什么”而不是”如何去做”。在更高層面寫代碼,更關心的是目標,而不是底層算法實現的過程。 ex: css, 正則表達式,sql 語句,html, xml…
命令式編程(過程式編程) : 專注于”如何去做”,這樣不管”做什么”,都會按照你的命令去做。解決某一問題的具體算法實現。
函數式編程:把運算過程盡量寫成一系列嵌套的函數調用。 函數式編程強調沒有”副作用”,意味著函數要保持獨立,所有功能就是返回一個新的值,沒有其他行為,尤其是不得修改外部變量的值。 所謂”副作用”(side effect),指的是函數內部與外部互動(最典型的情況,就是修改全局變量的值),產生運算以外的其他結果。
(英語:Declarative programming)是一種編程范型,與命令式編程相對立。聲明式語言包括數據庫查詢語言(SQL,XQuery),正則表達式,邏輯編程,函數式編程和組態管理系統。
聲明式編程語言:prolog
特點:你只需向它提供一些事實(fact)和推論(inference),讓它為你判斷。它像一個手藝高超的糕點師,只要你說出你喜歡的蛋糕的特征,糕點師會幫你挑選原料并按照你提供的規則為你烤出糕點。
聲明式編程語言:SQL
也許你還不能明白,但有一個地方,你也許已經用到了聲明式編程,那就是SQL。
你可以把 SQL 當做一個處理數據的聲明式查詢語言。完全用SQL寫一個應用程序?這不可能。但如果是處理相互關聯的數據集,它就顯的無比強大了。
像下面這樣的查詢語句:
SELECT * from dogs
INNER JOIN owners
WHERE dogs.owner_id = owners.id
如果我們用命令式編程方式實現這段邏輯:
//dogs = [{name: 'Fido', owner_id: 1}, {...}, ... ]
//owners = [{id: 1, name: 'Bob'}, {...}, ...] var dogsWithOwners = []
var dog, owner
for(var di=0; di < dogs.length; di++) {
dog = dogs[di]
for(var oi=0; oi < owners.length; oi++) {
owner = owners[oi]
if (owner && dog.owner_id == owner.id) {
dogsWithOwners.push ({
dog: dog,
owner: owner
})
}
}}
}
我可沒說SQL是一種很容易懂的語言,也沒說一眼就能把它們看明白,但基本上還是很整潔的。
SQL代碼不僅很短,不不僅容易讀懂,它還有更大的優勢。因為我們歸納抽離了how,我們就可以專注于what,讓數據庫來幫我們優化how。
聲明式編程通過函數、推論規則或項重寫(term-rewriting)規則,來描述變量之間的關系。它的語言運行器(編譯器或解釋器)采用了一個固定的算法,以從這些關系產生結果。
聲明式編程語言通常用作解決人工智能和約束滿足問題。
命令式編程
java、c、c++、rubby等都屬此類。其就像一本烹飪菜譜,你需要精確的告訴計算機如何去完成一項工作:列出原料購物清單,并描述烤蛋糕的詳細步驟。
命令式編程:命令“機器”如何去做事情(how),這樣不管你想要的是什么(what),它都會按照你的命令實現。
聲明式編程:告訴“機器”你想要的是什么(what),讓機器想出如何去做(how)。
聲明式編程和命令式編程的代碼例子
舉個簡單的例子,假設我們想讓一個數組里的數值翻倍。
我們用命令式編程風格實現,像下面這樣:
var numbers = [1,2,3,4,5]
var doubled = []
for(var i = 0; i < numbers.length; i++) {
var newNumber = numbers[i] * 2
doubled.push (newNumber)
}
console.log (doubled) //=> [2,4,6,8,10]
我們直接遍歷整個數組,取出每個元素,乘以二,然后把翻倍后的值放入新數組,每次都要操作這個雙倍數組,直到計算完所有元素。
而使用聲明式編程方法,我們可以用 Array.map 函數,像下面這樣:
var numbers = [1,2,3,4,5]
var doubled = numbers.map (function (n) {
return n * 2
})
console.log (doubled) //=> [2,4,6,8,10]
map利用當前的數組創建了一個新數組,新數組里的每個元素都是經過了傳入map的函數(這里是function (n) { return n*2 })的處理。
map函數所做的事情是將直接遍歷整個數組的過程歸納抽離出來,讓我們專注于描述我們想要的是什么(what)。注意,我們傳入map的是一個純函數;它不具有任何副作用(不會改變外部狀態),它只是接收一個數字,返回乘以二后的值。
在一些具有函數式編程特征的語言里,對于 list 數據類型的操作,還有一些其他常用的聲明式的函數方法。例如,求一個list里所有值的和,命令式編程會這樣做:
var numbers = [1,2,3,4,5]
var total = 0 for(var i = 0; i < numbers.length; i++) {
total += numbers[i]
}
console.log (total) //=> 15
而在聲明式編程方式里,我們使用reduce函數:
var numbers = [1,2,3,4,5]
var total = numbers.reduce (function (sum, n) {
return sum + n
});
console.log (total) //=> 15
reduce函數利用傳入的函數把一個list運算成一個值。它以這個函數為參數,數組里的每個元素都要經過它的處理。每一次調用,第一個參數(這里是sum)都是這個函數處理前一個值時返回的結果,而第二個參數(n)就是當前元素。這樣下來,每此處理的新元素都會合計到sum中,最終我們得到的是整個數組的和。
同樣,reduce函數歸納抽離了我們如何遍歷數組和狀態管理部分的實現,提供給我們一個通用的方式來把一個list合并成一個值。我們需要做的只是指明我們想要的是什么.
函數式編程
函數式編程的三大特性:
immutable data 不可變數據:像Clojure一樣,默認上變量是不可變的,如果你要改變變量,你需要把變量copy出去修改。這樣一來,可以讓你的程序少很多Bug。因為,程序中的狀態不好維護,在并發的時候更不好維護。(你可以試想一下如果你的程序有個復雜的狀態,當以后別人改你代碼的時候,是很容易出bug的,在并行中這樣的問題就更多了)
first class functions:這個技術可以讓你的函數就像變量一樣來使用。也就是說,你的函數可以像變量一樣被創建,修改,并當成變量一樣傳遞,返回或是在函數中嵌套函數。這個有點像Javascript的Prototype(參看Javascript的面向對象編程)
尾遞歸優化:我們知道遞歸的害處,那就是如果遞歸很深的話,stack受不了,并會導致性能大幅度下降。所以,我們使用尾遞歸優化技術——每次遞歸時都會重用stack,這樣一來能夠提升性能,當然,這需要語言或編譯器的支持。Python就不支持。
函數式編程的幾個技術
map & reduce :這個技術不用多說了,函數式編程最常見的技術就是對一個集合做Map和Reduce操作。這比起過程式的語言來說,在代碼上要更容易閱讀。(傳統過程式的語言需要使用for/while循環,然后在各種變量中把數據倒過來倒過去的)這個很像C++中的STL中的foreach,find_if,count_if之流的函數的玩法。
pipeline:這個技術的意思是,把函數實例成一個一個的action,然后,把一組action放到一個數組或是列表中,然后把數據傳給這個action list,數據就像一個pipeline一樣順序地被各個函數所操作,最終得到我們想要的結果。
recursing 遞歸 :遞歸最大的好處就簡化代碼,他可以把一個復雜的問題用很簡單的代碼描述出來。注意:遞歸的精髓是描述問題,而這正是函數式編程的精髓。
currying:把一個函數的多個參數分解成多個函數, 然后把函數多層封裝起來,每層函數都返回一個函數去接收下一個參數這樣,可以簡化函數的多個參數。在C++中,這個很像STL中的bind_1st或是bind2nd。
higher order function 高階函數:所謂高階函數就是函數當參數,把傳入的函數做一個封裝,然后返回這個封裝函數?,F象上就是函數傳進傳出,就像面向對象對象滿天飛一樣。
還有函數式的一些好處:
parallelization 并行:所謂并行的意思就是在并行環境下,各個線程之間不需要同步或互斥。
lazy evaluation 惰性求值:這個需要編譯器的支持。表達式不在它被綁定到變量之后就立即求值,而是在該值被取用的時候求值,也就是說,語句如
x:=expression; (把一個表達式的結果賦值給一個變量)明顯的調用這個表達式被計算并把結果放置到 x 中,但是先不管實際在 x 中的是什么,直到通過后面的表達式中到 x 的引用而有了對它的值的需求的時候,而后面表達式自身的求值也可以被延遲,最終為了生成讓外界看到的某個符號而計算這個快速增長的依賴樹。
determinism 確定性:所謂確定性的意思就是像數學那樣 f(x) = y ,這個函數無論在什么場景下,都會得到同樣的結果,這個我們稱之為函數的確定性。而不是像程序中的很多函數那樣,同一個參數,卻會在不同的場景下計算出不同的結果。所謂不同的場景的意思就是我們的函數會根據一些運行中的狀態信息的不同而發生變化。
React安裝
就像寫普通的html/css/js代碼一樣,引入如下js即可:
<!-- React -->
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
Hello,World
直接上代碼helloWorld.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<!-- jQuery 2.2.3 -->
<script src="../public/plugins/jQuery/jquery-2.2.3.min.js"></script>
<!-- Bootstrap 3.3.6 -->
<script src="../public/bootstrap/js/bootstrap.min.js"></script>
<!-- Bootstrap 3.3.6 -->
<link rel="stylesheet" href="../public/bootstrap/css/bootstrap.min.css">
<!-- BootstrapDialog -->
<link href="../public/components/bootstrap3-dialog/bootstrap-dialog.min.css" rel="stylesheet" type="text/css"/>
<script src="../public/components/bootstrap3-dialog/bootstrap-dialog.min.js"></script>
<!-- React -->
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
</head>
<body>
<div id="helloWorld"></div>
<script type="text/javascript">
function sayHelloWorld() {
BootstrapDialog.show({
title: 'React Demo',
message: 'Hello,World! 現在時間是:' + new Date(),
type: BootstrapDialog.TYPE_DEFAULT,
closable: false,
cssClass: 'dialog_mar',
buttons: [{
label: '確認',
cssClass: 'con_btn',
action: function (dialogRef) {
dialogRef.close();
location.reload();
}
}, {
label: '取消',
action: function (dialogRef) {
dialogRef.close();
}
}]
});
}
</script>
<script type="text/babel">
var HelloWorld = React.createClass({
getInitialState: function () {
return {};
},
sayHello: function () {
// alert('Hello,World!');
sayHelloWorld();
},
render: function () {
var helloWorldStyle = {
textAlign: 'center',
padding: '4em'
};
var btnStyle = {
padding: '4em',
fontSize: '4em'
};
return (
<div style={helloWorldStyle}>
<button onClick={this.sayHello} style={btnStyle}>說: Hello,World!</button>
</div>
);
}
});
ReactDOM.render(<HelloWorld/>, document.getElementById('helloWorld'));
</script>
</body>
</html>
運行效果:
https://jason-chen-2017.github.io/Jason-Chen-2017/reactDemo/helloWorld.html