最近因爲工做的須要開始開發一些Python的東西,因爲以前一直在使用Javascript,因此會不自覺的使用一些Javascript的概念,語法什麼的,常常掉到坑裏。我以爲對於從Javascript轉到Python,有必要總結一下它們之間的差別。javascript
Python和Javascript都是腳本語言,因此它們有不少共同的特性,都須要解釋器來運行,都是動態類型,都支持自動內存管理,均可以調用eval()來執行腳本等等腳本語言所共有的特性。java
然而它們也有很大的區別,Javascript這設計之初是一種客戶端的腳本語言,主要應用於瀏覽器,它的語法主要借鑑了C,而Python因爲其「優雅」,「明確」,「簡單」的設計而廣受歡迎,被應用於教育,科學計算,web開發等不一樣的場景中。python
Python和Javascript都支持多種不一樣的編程範式,在面向對象的編程上面,它們有很大的區別。Javascript的面向對象是基於原型(prototype)的, 對象的繼承是由原型(也是對象)建立出來的,由原型對象建立出來的對象繼承了原型鏈上的方法。而Python則是中規中矩的基於類(class)的繼承,並自然的支持多態(polymophine)。程序員
OO in Pyhtonweb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
Employee:
'Common base class for all employees'
empCount
=
0
##類成員
def
__init__(
self
, name, salary):
self
.name
=
name
self
.salary
=
salary
Employee.empCount
+
=
1
def
displayCount(
self
):
print
"Total Employee %d"
%
Employee.empCount
def
displayEmployee(
self
):
print
"Name : "
,
self
.name,
", Salary: "
,
self
.salary
## 建立實例
ea
=
Employee(
"a"
,
1000
)
eb
=
Employee(
"b"
,
2000
)
|
OO in Javascriptexpress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
var
empCount = 0;
//構造函數
function
Employee(name, salary){
this
.name = name;
this
.salary = salary;
this
.empCount += 1;
}
Employee.prototype.displayCount =
function
(){
console.log(
"Total Employee "
+ empCount );
}
Employee.prototype.displayEmployee =
function
(){
console.log(
"Name "
+
this
.name +
", Salary "
+
this
.salary );
}
//建立實例
var
ea =
new
Employee(
"a"
,1000);
var
eb =
new
Employee(
"b"
,2000);
|
由於是基於對象的繼承,在Javascript中,咱們沒有辦法使用類成員empCount,只好聲明瞭一個全局變量,固然實際開發中咱們會用更合適的scope。注意Javascript建立對象須要使用new關鍵字,而Python不須要。編程
除了原生的基於原型的繼承,還有不少利用閉包或者原型來模擬類繼承的Javascript OO工具,由於不是語言自己的屬性,咱們就不討論了。設計模式
在Javascript的世界中是沒有多線程的概念的,併發使用過使用事件驅動的方式來進行的, 全部的JavaScript程序都運行在一個線程中。在HTML5中引入web worker能夠併發的處理任務,但沒有改變Javascript單線程的限制。瀏覽器
Python經過thread包支持多線程。安全
在Python中,有的數據類型是不可改變的,也就意味着這種類型的數據不能被修改,全部的修改都會返回新的對象。而在Javascript中全部的數據類型都是能夠改變的。Python引入不可改變類型我認爲是爲了支持線程安全,而由於Javascript是單線程模型,因此沒有必要引入不可改變類型。
固然在Javascript能夠定義一個對象的屬性爲只讀。
1
2
3
|
var
obj = {};Object.defineProperty(obj,
"prop"
, {
value:
"test"
,
writable:
false
});
|
在ECMAScript5的支持中,也能夠調用Object的freeze方法來是對象變得不可修改。
1
|
Object.freeze(obj)
|
Javascript的數據類型比較簡單,有object、string、boolean、number、null和undefined,總共六種
Python中一切均爲對象,像module、function、class等等都是。
Python有五個內置的簡單數據類型bool、int、long、float和complex,另外還有容器類型,代碼類型,內部類型等等。
Javascript有true和false。Python有True和False。它們除了大小寫沒有什麼區別。
Javascript採用UTF16編碼。
Python使用ASCII碼。須要調用encode、decode來進行編碼轉換。使用u做爲前綴能夠指定字符串使用Unicode編碼。
Javascript中全部的數值類型都是實現爲64位浮點數。支持NaN(Not a number),正負無窮大(+/-Infiity)。
Python擁有諸多的數值類型,其中的複數類型很是方便,因此在Python在科研和教育領域很受歡迎。這應該也是其中一個緣由吧。Python中沒有定義NaN,除零操做會引起異常。
Javascript內置了array類型(array也是object)
Python的列表(List)和Javascript的Array比較接近,而元組(Tuple)能夠理解爲不可改變的列表。
除了求長度在Python中是使用內置方法len外,基本上Javascript和Python都提供了相似的方法來操做列表。Python中對列表下標的操做很是靈活也很是方便,這是Javascript所沒有的。例如l[5:-1],l[:6]等等。
Javascript中大量的使用{}來建立對象,這些對象和字典沒有什麼區別,可使用[]或者.來訪問對象的成員。能夠動態的添加,修改和刪除成員。能夠認爲對象就是Javascript的字典或者哈希表。對象的key必須是字符串。
Python內置了哈希表(dictS),和Javascript不一樣的是,dictS能夠有各類類型的key值。
Javascript定義了兩種空值。 undefined表示變量沒有被初始化,null表示變量已經初始化可是值爲空。
Python中不存在未初始化的值,若是一個變量值爲空,Python使用None來表示。
Javascript中變量的聲明和初始化
1
2
3
4
5
|
v1;
v2 =
null
;
var
v3;
var
v4 =
null
;
var
v5 =
'something'
;
|
在如上的代碼中v1是全局變量,未初始化,值爲undefined;v2是全局變量,初始化爲空值;v3爲局部未初始化變量,v4是局部初始化爲空值的變量;v5是局部已初始化爲一個字符處的變量。
Python中變量的聲明和初始化
1
2
|
v1
=
None
v2
=
'someting'
|
Python中的變量聲明和初始化就簡單了許多。當在Python中訪問一個不存在的變量時,會拋出NameError的異常。當訪問對象或者字典的值不存在的時候,會拋出AttributeError或者KeyError。所以判斷一個值是否存在在Javascript和Python中須要不同的方式。
Javascript中檢查某變量的存在性:
1
2
3
4
5
6
7
|
if
(!v ) {
// do something if v does not exist or is null or is false
}
if
(v === undefined) {
// do something if v does not initialized
}
|
注意使用!v來檢查v是否初始化是有歧義的由於有許多種狀況!v都會返回true
Python中檢查某變量的存在性:
1
2
3
4
|
try
:
v
except
NameError
## do something if v does not exist
|
在Python中也能夠經過檢查變量是否是存在於局部locals()或者全局globals()來判斷是否存在該變量。
Javascript能夠經過typeof來得到某個變量的類型:
typeof in Javascript 的例子:
1
2
3
4
5
6
7
8
|
typeof
3
// "number"
typeof
"abc"
// "string"
typeof
{}
// "object"
typeof
true
// "boolean"
typeof
undefined
// "undefined"
typeof
function
(){}
// "function"
typeof
[]
// "object"
typeof
null
// "object"
|
要很是當心的使用typeof,從上面的例子你能夠看到,typeof null竟然是object。由於javscript的弱類型特性,想要得到更實際的類型,還須要結合使用instanceof,constructor等概念。具體請參考這篇文章
Python提供內置方法type來得到數據的類型。
1
2
3
4
5
6
7
8
|
>>>
type
([])
is
list
True
>>>
type
({})
is
dict
True
>>>
type
('')
is
str
True
>>>
type
(
0
)
is
int
True
|
同時也能夠經過isinstance()來判斷類的類型
1
2
3
4
5
6
7
8
|
class
A:
pass
class
B(A):
pass
isinstance
(A(), A)
# returns True
type
(A())
=
=
A
# returns True
isinstance
(B(), A)
# returns True
type
(B())
=
=
A
# returns False
|
可是注意Python的class style發生過一次變化,不是每一個版本的Python運行上述代碼的行爲都同樣,在old style中,全部的實例的type都是‘instance’,因此用type方法來檢查也不是一個好的方法。這一點和Javascript很相似。
當操做不一樣類型一塊兒進行運算的時候,Javascript老是儘量的進行自動的類型轉換,這很方便,固然也很容易出錯。尤爲是在進行數值和字符串操做的時候,一不當心就會出錯。我之前常常會計算SVG中的各類數值屬性,諸如x,y座標之類的,當你一不當心把一個字符串加到數值上的時候,Javascript會自動轉換出一個數值,每每是NaN,這樣SVG就徹底畫不出來啦,由於自動轉化是合法的,找到出錯的地方也很是困難。
Python在這一點上就很是的謹慎,通常不會在不一樣的類型之間作自動的轉換。
Python使用縮進來決定邏輯行的結束很是具備創造性,這也許是Python最獨特的屬性了,固然也有人對此頗具微詞,尤爲是須要修改重構代碼的時候,修改縮進每每會引發不小的麻煩。
Javascript雖然名字裏有Java,它的風格也有那麼一點像Java,但是它和Java就比如雷峯塔和雷鋒同樣,真的沒有半毛錢的關係。到時語法上和C比較相似。這裏必需要提到的是coffeescript做爲構建與Javascript之上的一種語言,採用了相似Python的語法風格,也是用縮進來決定邏輯行。
Python風格
1
2
3
|
def
func(
list
):
for
i
in
range
(
0
,
len
(
list
)):
print
list
[i]
|
Javascript風格
1
2
3
4
5
|
function
funcs(list) {
for
(
var
i=0, len = list.length(); i < len; i++) {
console.log(list[i]);
}
}
|
從以上的兩個代碼的例子能夠看出,Python確實很是簡潔。
Javascript的做用域是由方法function來定義的,也就是說同一個方法內部擁有相同的做用域。這個嚴重區別與C語言使用{}來定義的做用域。Closure是Javascript最有用的一個特性。
Python的做用域是由module,function,class來定義的。
Python的import能夠很好的管理依賴和做用域,而Javascript沒有原生的包管理機制,須要藉助AMD來異步的加載依賴的js文件,requirejs是一個經常使用的工具。
Javascript使用=賦值,擁有判斷相等(==)和全等(===)兩種相等的判斷。其它的邏輯運算符有&& 和||,和C語言相似。
Python中沒有全等,或和與使用的時and 和 or,更接近天然語言。Python中沒有三元運算符 A :B ?C,一般的寫法是
1
|
(A
and
B)
or
C
|
由於這樣寫有必定的缺陷,也能夠寫做
1
|
B
if
A
else
C
|
Python對賦值操做的一個重要的改進是不容許賦值操做返回賦值的結果,這樣作的好處是避免出如今應該使用相等判斷的時候錯誤的使用了賦值操做。由於這兩個操做符實在太像了,並且從天然語言上來講它們也沒有區別。
Python不支持++運算符,沒錯你不再須要根據++符號在變量的左右位置來思考究竟是先加一再賦值呢仍是先賦值再加一。
利用元組(tuple),Python能夠一次性的給多個變量賦值
1
|
(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY)
=
range
(
7
)
|
Python的函數參數支持命名參數和可選參數(提供默認值),使用起來很方便,Javascript不支持可選參數和默認值(能夠經過對arguments的解析來支持)
1
2
|
def
info(
object
, spacing
=
10
, collapse
=
1
):
... ...
|
Javascript的一個方便的特性是能夠當即調用一個剛剛聲明的匿名函數。也有人稱之爲自調用匿名函數。
下面的代碼是一個module模式的例子,使用閉包來保存狀態實現良好的封裝。這樣的代碼能夠用在無需重用的場合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var
counter = (
function
(){
var
i = 0;
return
{
get:
function
(){
return
i;
},
set:
function
( val ){
i = val;
},
increment:
function
() {
return
++i;
}
};
}());
|
Python沒有相應的支持。
在我接觸到的Python代碼中,大量的使用這樣的生成器的模式。
Python生成器的例子
1
2
3
4
5
6
7
8
|
# a generator that yields items instead of returning a list
def
firstn(n):
num
=
0
while
num < n:
yield
num
num
+
=
1
sum_of_first_n
=
sum
(firstn(
1000000
))
|
Javascript1.7中引入了一些列的新特性,其中就包括生成器和迭代器。然而大部分的瀏覽器除了Mozilla(Mozilla基本上是在本身玩,下一代的Javascript標準應該是ECMAScript5)都不支持這些特性
Javascript1.7 迭代器和生成器的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
function
fib() {
var
i = 0, j = 1;
while
(
true
) {
yield i;
var
t = i;
i = j;
j += t;
}
};
var
g = fib();
for
(
var
i = 0; i < 10; i++) {
console.log(g.next());
}
|
Python的映射表達式能夠很是方便的幫助用戶構造列表、字典、集合等內置數據類型。
下面是列表映射表達式使用的例子:
1
2
3
4
5
6
|
>>> [x
+
3
for
x
in
range
(
4
)]
[
3
,
4
,
5
,
6
]
>>> {x
+
3
for
x
in
range
(
4
)}
{
3
,
4
,
5
,
6
}
>>> {x: x
+
3
for
x
in
range
(
4
)}
{
0
:
3
,
1
:
4
,
2
:
5
,
3
:
6
}
|
Javascript1.7開始也引入了Array Comprehension
1
2
|
var
numbers = [1, 2, 3, 4];
var
doubled = [i * 2
for
(i of numbers)];
|
Lamda表達式是一種匿名函數,基於著名的λ演算。許多語言諸如C#,Java都提供了對lamda的支持。Pyhton就是其中之一。Javascript沒有提供原生的Lamda支持。可是有第三方的Lamda包。
1
|
g
=
lambda
x : x
*
3
|
Decorator是一種設計模式,大部分語言均可以支持這樣的模式,Python提供了原生的對該模式的支持,算是一種對程序員的便利把。
Decorator的用法以下。
1
2
3
|
@classmethod
def
foo (arg1, arg2):
....
|
更多decorator的內容,請參考https://wiki.python.org/moin/PythonDecorators
本人對Javascript和Python的認識有限,歡迎你們提出寶貴意見。