做为一个半瓶醋的各种Language coder,我感到压力很大,经常在几种语言之间倒来切去,最终决定整理一个帮助对比回忆的文档。
这不是手册也不是入门指南,不能让你理解或入门任何一门语言!!
代码测试环境
Ubuntu 10.10 i386 Python 2.6.6 PHP 5.3.3 Firefox 3.6.13更新日志
参考链接和书目
Python | PHP | Javascript | |
起源 |
Python的创始人为Guido van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为 ABC 语言的一种继承。之所以选中 Python(大蟒蛇的意思)作为程序的名字,是因为他是一个Monty Python的飞行马戏团的爱好者。 了解更多 |
PHP,全称为PHP Hypertext Preprocessor,超文本预处理器。 PHP起源于1995年,由当时年仅17岁的Rasmus Lerdorf编写完成,是使用Perl技术为基础的服务器端脚本。主要的用途是跟踪收集浏览个人网站简历的信息,由于它主要的功能是表单的转换、信息收集工作,因此被Lerdorf命名为Personal Home Page Tools/Form Interpreter,简称PHP/FI。 了解更多 |
1995年,Javascript 1.0伴随着网景公司的Netscape Navigator 2.0而诞生。到现在它几乎是所有浏览器必须支持的语言。 了解更多 |
特点 | Python是一门通用编程语言,可用于Web开发,GUI开发,网络编程,数据分析等各种应用。另外python语法简洁,类型方面没有歧义,更容易入门。 | PHP在web开发领域几乎无人能敌,有人说它2小时可以入门。但是如果想真正理解它却并非易事。 | 一个只用JS验证过表单的Coder几乎无法理解JS程序员能写出像Gmail这种应用.JS做为一门注释里出现Fuck最多的语言,不仅是因为本身的古怪语法,也因为它有各种不同的解释引擎。 |
Python | PHP | Javascript | |
续行符 | \ | 木有,直接换行 | 木有,直接换行 |
注释 |
#我是单行注释
"我也是单行注释"
"""
我是多行注释
使用未赋值的字符串做注释
"""
对于字符串型的注释
如果注释出现在文件开头,那么它将成为一个模块文档如果出现在函数定义之后,成为一个函数文档 如果出现在class定义之后,成为一个类的说明文档 文档在运行时是可以访问的
>>> def foo():
... '''
... i am foo
... void foo(void);
... '''
... pass
...
>>> print foo.__doc__
i am foo
void foo(void);
|
C style: // /* */ | C style: // /* */ |
空行 |
for i in xrange(100):
pass
|
for($i = 0; $i < 100; $i++);
|
for(var i = 0; i < 100; i++);
|
Python | PHP | Javascript | |
说明 | 一切皆对象
>>> (2.0).is_integer()
True
|
PHP中的基本类型和对象是孤立的 | 一切皆对象
>>> (1).toString()
"1"
|
强类型? | 是>>> '12' == 12 False >>> "test" + 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: cannot concatenate 'str' and 'int' objects |
不是
php > var_dump('12' == 12);
bool(true)
php > var_dump('12' === 12);
bool(false)
|
不是
>>> "12" == 12
true
>>> "12" === 12
false
|
对于PHP和JS使用"==="真等于符是一种好习惯 |
Python | PHP | Javascript | |
说明 | python的整型分"标准整型"和"长整型" | 在JS中所有数字都是由浮点型表示 | |
范围 |
标准整型: 跟宿主系统有关系,在32位机器上范围:-2^31 ~ 2^31-1 长整型: 长整型的长度只跟机器所支持的虚拟内存大小有关
#长整型直接量需要在后面加字符"L"
long1 = -0xFFFFFL
long2 = 312432L
2.4版本以后标准整型溢出之后会自动转换为长整
|
跟宿主系统有关系,在32位机器上范围:-2^31 ~ 2^31-1 整型溢出后会自动转换为浮点(float) |
-2^53 -> 2^53 |
特殊常量 |
#import sys
#最大的标准整型
print sys.maxint
|
PHP_INT_MAX //常量,表示整型最大值 |
Infinity //无穷大 NaN //非数字值 Number.MAX_VALUE //可表示最大数字 Number.MIN_VALUE //可表示最小数字 Number.POSITIVE_INFINITY //正无穷大 Number.NEGATIVE_INFINITY //负无穷大 |
16进制直接量 | 0xff or 0XFF | 0xff or 0XFF | 0xff or 0XFF |
8进制直接量 | 0377 == 255//0开头 | 0377 == 255//0开头 | ECMAScript标准不支持8进制直接量,但是浏览器js引擎却支持了。
0377 == 255 //0开头
|
Python | PHP | Javascript | |
范围 | 范围约为-10^308.25 ~ 10^308.25 | 跟宿主系统有关,通常范围约为-10^308.25 ~ 10^308.25 | 范围约为-10^308.25 ~ 10^308.25 |
Python | PHP | Javascript | |
表示 | True False True和False都不是关键字,你甚至可以颠倒是非
True, False = False, True
|
true false | true false |
自动转换 |
下面的值被认为是false:
|
下面的值被认为是false:
|
下面的值被认为是false:
|
Python | PHP | Javascript | |
双引号 | 支持 | 支持 | 支持 |
单引号 | 支持 | 支持 对于PHP,在单引号字符串中的变量 和特殊含义的字符将 不会 被替换 |
支持 |
here document |
python中使用三个单引号或者三个双引号
print '''
test
test
'''
print """
test
test
"""
|
Heredoc也支持转义和变量替换
$a = 'var 1';
$b = 'var b';
$str = >>>EOD
Example of string
spanning multiple lines
using heredoc syntax.
a = ${a}
b = ${b}
EOD;
PHP中还有一种Nowdoc的方式,了解更多
|
不支持 |
转义字符 |
以r或R打头的字符串不会做以下转义,这种字符串称为原始字符串
>>> r'abc\"def\t'
'abc\\"def\\t'
\0 C里的'\0'
\a 响铃
\b 退格
\t
\n
\v 纵向制表
\f 换页
\r
\e ESC
\"
\'
\\
\XX 八进制字符
\xXX 十六进制字符
\ 连字符
|
单引号和Nowdoc形式定义的字符串不会做以下转义
\n
\r
\t
\v
\f
\\
\$
\"
\XXX 八进制字符
\xXX 十六进制字符
|
\r
\"
\'
\\
\xXX 十六进制字符
\xXXXX 十六进制unicode字符
|
连接操作符 |
c = 'a' + 'b'
|
$c = 'a' . 'b';
|
var c = 'a' + 'b';
|
下标访问 |
>>> 'abc'[0]
'a'
|
php > $a = 'abc';
//推荐写法
php > echo $a[0];
a
php > echo $a{0};
a
|
>>> 'abc'.charAt(0);
"a"
//ECMAScript 5也有定义下标的语法,你可以用最新的firefox测试
>>> 'abc'[0]
"a"
|
取长度 |
>>> len("中文")
6
>>> len(u"中文")
2
|
echo strlen('中文');
//6
echo mb_strlen('中文', 'UTF-8');
//2
|
>>> '中文'.length
2
|
转换为数字 |
#默认会当作10进制处理
>>> int('012')
12
#指定做8进制解析
>>> int('012', 8)
10
|
php > echo '012' - 0;
12
php > echo (integer)'012';
12
php > echo intval('012');
12
php > echo intval('012', 8);
10
|
注意JS的陷阱
>>> '012' - 0
12
>>> parseInt('012')
10
//打印10, JS竟然替我们做了一个艰难的决定。。。
>>> parseInt('012', 10)
12
|
编码 |
python中有两种字符串类型str和unicode str是一种字节串,可以理解为C语言里的char[] str型的字符串的编码跟python脚本文件的编码一致 unicode是一种unicode编码字符串,跟文件编码无关
>>> cstr = '普通字符串'
>>> ustr = u'unicode字符串'
>>> len(cstr)
15
>>> len(ustr)
10
>>> cstr[0]
'\xe6'
>>> ustr[8]
u'\u7b26'
str和unicode转换
ustr = u'我是unicode字符串'
#编码成utf8编码的str型字符串
utfstr = ustr.encode('utf-8')
#编码成gb2312编码的str型字符串
gbstr = ustr.encode('gb2312')
#将gb2312编码的str型字符串解码成unicode型的ustr2
ustr2 = gbstr.decode('gb2312')
str和unicode的强制转换
#str和unicode型字符串做连接操作会将str强制转换成unicode
>>> u'a' + 'b'
u'ab'
#相当于执行了u'a' + 'b'.decode(sys.getdefaultencoding())
#sys.getdefaultencoding()用于获取默认编码
#如果被格式化的参数中有unicode串,则其他参数也要强制转换到unicode
>>> '%s%s' % (u'a', 'b')
u'ab'
>>> '%s%s' % (u'a', '中文')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode
byte 0xe4 in position 0: ordinal not in range(128)
>>> sys.getdefaultencoding()
'ascii'
#出错原因在于'中文'.decode('ascii')
#通过ascii解码'中文'两个字是不可能的
了解更多
|
PHP中的string是一种字节串,编码跟PHP文件的编码一致
|
JS中的字符串是unicode字符串,跟文件编码无关。
alert('中文'.charCodeAt(0));
//不论utf8或gb2312编码的环境中都将打印20013
server端收到数据编码总是跟网页编码一致,这跟JS的字符串编码无关
|
Python | PHP | Javascript | |
说明 |
Python有两种称为列表(list)和元组(tuple)的序列类型 用以实现索引数组,一种可变一种不可变,这里以列表为例。 Python还有一种字典(dict)类型,用于实现hash数组 |
PHP中不区分索引数组和Hash数组,即全是Hash
php > $a = array();
php > $a[0] = 'test';
php > $a[1] = 'test2';
php > $a['1'] = 'test3';
php > echo $a[1];
test3
php > echo $a['1'];
test3
|
JS跟PHP类似,没有真正的索引数组,全是Hash
>>> a = ['动','感','超','人'];
["动", "感", "超", "人"]
>>> b = {'0':'动','1':'感','2':'超','3':'人'};
Object { 0="动", 1="感", more...}
>>> a[2]
"超"
>>> b[2]
"超"
>>> a['2']
"超"
>>> b['2']
"超"
|
定义 |
#列表直接量
#列表也可以存储混合类型的数据
>>> a = [1,2,3,"4"]
>>> a
[1, 2, 3, '4']
#通过工厂函数初始化
>>> a = list((1,2,3,4,5))
>>> a
[1, 2, 3, 4, 5]
>>> len(a)
5
>>> a.append('addon')
>>> len(a)
6
#字典直接量
#字典的key可以是任意可hash的不可变类型
>>> b = {'k1':'i am k1',100:'i am 100'}
>>> b
{'k1': 'i am k1', 100: 'i am 100'}
#通过工厂初始化
>>> d = dict(a = 1, b = 2)
>>> d
{'a': 1, 'b': 2}
>>> a[100]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> b['c']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'c'
#访问不存在的索引,或者键值,python将会抛出异常
|
php > $a = array('k1'=>1,'k2'=>2,30=>3,40=>4);
php > echo count($a);
4
php > var_dump($a);
array(4) {
["k1"]=>
int(1)
["k2"]=>
int(2)
[30]=>
int(3)
[40]=>
int(4)
}
php > $a = array(0=>1,30=>3,40=>4);
//说明数组的长度并不是最大的索引值,foreach遍历更安全
php > echo count($a);
3
php > echo $a[100];
PHP Notice: Undefined offset: 100 in php shell code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
//访问不存在的key只会有Notice产生,生产环境中一般会配置将Notice忽略
|
//直接量
>>> a = [1,2,3,4];
[1, 2, 3, 4]
//调用构造函数
>>> a = new Array();
[]
>>> a[99] = 'i am 100';
"i am 100"
>>> a.length
100
>>> a['k1'] = 'i am k1';
"i am k1"
>>> a.length
100
>>> delete a[99]
true
>>> a.length
100
//说明JS中数组的长度只跟赋值过的最大索引值有关
>>> a[0]
undefined
>>> a[100]
undefined
//所有未赋值的索引调用都将返回undefined
另:JS中所有可以转换为字符串的对象都可以做为Hash Key
|
Python | PHP | Javascript | |
变量声明 | 变量不需要声明 | 变量不需要声明 |
function foo()
{
var i; //变量声明
i = 0;
j = 0;//变量可以不声明,但是j将变成一个全局变量
}
|
判断变量是否定义 |
try:
print xxxx
except NameError,ex:
print 'xxxx is undefined'
|
php > var_dump(isset($xxxxx));
bool(false)
|
if (typeof xxxx != 'undefined')
|
赋值 |
理解赋值之前我们需要理解: 在这三种脚本语言中,变量名和变量本身是独立的,只能说变量名可以代表一个变量 |
||
Python中的赋值为赋引用
>>> L1 = ['list em']
>>> L2 = L1
>>> L2.append('add another')
>>> L1
['list em', 'add another']
>>> L2
['list em', 'add another']
L2 = L1并不会copy L1给L2,只是创建了L2到变量的引用
python中的赋值操作没有返回值
>>> a = (b = 'c')
File "<stdin>", line 1
a = (b = 'c')
^
SyntaxError: invalid syntax
|
由于PHP中普通类型和对象是独立的,就把对象的内容提到前面来了,所以有点复杂。。 PHP中的赋值比较复杂 普通赋值相当于变量复制(copy on write)
php > $a = array('i am a string');
php > $b = $a;
//创建了新变量$b并copy $a的值给它
php > $b[] = 'add another';
php > var_dump($a);
array(1) {
[0]=>
string(13) "i am a string"
}
php > var_dump($b);
array(2) {
[0]=>
string(13) "i am a string"
[1]=>
string(11) "add another"
}
对象赋值为赋引用
//Human的实例在对象编程部分,小穿越一下
$hm = new Human('han meimei');
$hm2 = $hm;
$hm2->name = 'li lei';
echo $hm->name;
输出:
li lei
创建变量"引用"的赋值可以认为创建了变量名的副本
php > $a = 'i am a';
php > $b = &$a;
//这个操作并不是变量赋值,而是创建变量a的引用
php > $b = 'i am b';
//$b和$a是等效的
php > echo $a;
i am b
|
JS中的赋值为赋引用
>>> a = [1,2,3]
[1, 2, 3]
>>> b = a
[1, 2, 3]
>>> b.push(4)
4
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
|
多重赋值(a = b = 1) | 支持 | 支持 | 支持 |
多元赋值 |
python中利用了元组的特性
(x, y, z) = (1, 2, 3)
|
PHP中可利用list操作符
list($x, $y, $z) = array(1, 2, 3);
|
不支持 |
判断变量类型 |
>>> isinstance(3,int)
True
>>> isinstance('abc',str)
True
>>> isinstance([1,2],list)
True
|
php > var_dump(is_integer(3));
bool(true)
php > var_dump(is_string('abc'));
bool(true)
php > var_dump(is_array(array(1,2)));
bool(true)
了解更多
|
>>> typeof 3 == 'number'
true
>>> typeof 'abc' == 'string'
true
>>> typeof []
"object"
//对于数组来说 typeof 会返回 object,所以不能用此方法判断
//所以要采取下面这种方式
>>> Object.prototype.toString.call([1,2]) === '[object Array]'
true
|
获取变量类型 |
>>> type(3)
<type 'int'>
>>> type('abc')
<type 'str'>
>>> type([1,2])
<type 'list'>
|
php > echo gettype(3);
integer
php > echo gettype('abc');
string
php > echo gettype(array(1,2));
array
|
参考上面 |
变量格式化输出 |
>>> '%s is not %d' % ('a', 5)
'a is not 5'
|
php > printf("%s is not %d", 'a', 5);
a is not 5
|
没有自带函数 | 调试打印 | dir() str() | var_dump() print_r() | console.log() alert() |
Python | PHP | Javascript | |
块级作用域? | 木有 | 木有 | 木有 |
访问全局变量 |
a = 'global var'
#python中可以直接通过作用域搜索访问到全局变量
def foo1():
print a
#这里你并没有改变全局变量a,而是定义了一个局部变量a
a = 'modify global var'
def foo2():
#可以明确声明一个全局变量
global a
#修改全局变量
a = 'modify global var'
|
$a = 'global var';
function foo()
{
//如果一个变量没有在函数内定义PHP并不会去搜索全局作用域
//如果需要访问全局变量,必须用global声明一个全局变量
global $a;
echo $a;
//通过全局变量数组访问
echo $GLOBALS['a'];
}
$GLOBALS,$_POST,$_GET等这些变量被PHP称之为超全局变量,函数中不用声明就可以使用
|
var a = 'global var';
function foo()
{
//JS中通过作用域链搜索也可以直接访问全局变量
alert(a);
//也可以直接修改全局变量,这是也为什么未声明变量的赋值会创建全局变量的原因
a = 'modify global var';
}
|
打包(命名空间) |
python中使用目录结构来构建命名空间
$ tree ./
./
├── d
│ ├── hello.py
│ └── __init__.py
├── foo.py
└── test.py
1 directory, 4 files
$ cat foo.py
#!/usr/bin/env python
name = 'my name is foo'
def print_name():
print name
$ cat d/hello.py
#!/usr/bin/env python
def echo():
print 'i am hello.py'
$ cat test.py
#!/usr/bin/env python
import foo
import d.hello as hello
print foo.name
foo.print_name()
hello.echo()
$ python test.py
my name is foo
my name is foo
i am hello.py
|
PHP中使用namespace关键字构造命名空间
$ cat test.php
<?php
namespace Hello;
function hi(){echo "i am hello\n";}
namespace Hello\World;
function hi(){echo "i am hello World\n";}
namespace Test;
\Hello\hi();
\Hello\World\hi();
use \Hello\World as HelloWorld;
HelloWorld\hi();
?>
$ php test.php
i am hello
i am hello World
i am hello World
|
JS中通过闭包包装
var com = {foo:{}};
(function(ns)
{
function privSayHi()
{
alert('hi');
}
ns.hi = function()
{
privSayHi();
};
})(com.foo);
function test()
{
var hi = com.foo.hi;
//相当于 import com.foo.hi as hi
hi();
}
test();
|
Python | PHP | Javascript | |
条件表达式(三元操作符) |
#python 2.5 or later
smaller = x if x < y else y
|
$smaller = $x < $y ? $x : $y;
|
var smaller = x < y ? x : y;
|
for(;;) | 不支持 | 支持 | 支持 |
for in |
for i in xrange(len(arr)):
print arr[i]
#python 使用for in来遍历可迭代对象
|
对于PHP使用foreach代替 for(;;)是一种推荐写法
//php没有for in 但是有foreach来遍历迭代
foreach($arr as $i => $v)
echo $v;
|
JS中也有for in循环,但是它的行为怪异,遍历顺序不定,甚至在不同的浏览器里也会有不同的表现
for (var x in [1,2,3])
alert(x);
|
跳出外层循环 | python还没有语法支持 |
//通过在break后面跟一个数字,可以跳出指定层次的循环
foreach($a as $v)
foreach($v as $vv)
break 2;
了解更多
|
JS则可以使用break加标签名的方式跳出
outerloop:
for (var i = 0; i < 100; ++i)
for (var j = 0; j < 100; ++j)
break outerloop;
|
Python | PHP | Javascript | |
传值?传引用? |
在这之前请理解每种语言的变量赋值方式 传值或传引用只是看起来的表面现象,传值不一定慢 PHP的变量复制会采用copy on write策略:传值也仅仅传一个"指针"副本,不会真的拷贝一份,当你真的需要修改变量时才会执行copy动作。 |
||
Python总是"传引用"
gstr = 'global string'
gls = ['global list',1,2]
def m_str(v):
#这里仅仅是是改变变量名副本v的引用关系,不影响gstr
v = 'modify global string'
#可以理解为
# v = gstr 使变量名v指向gstr
# v = 'modify global string' 改变变量名v的引用
# gstr不受影响
#Python的赋值方式使它的传引用现在看来像是传值
def m_hs(v):
#变量名v未改变,改变的是v引用的list型
变量的第一个元素的引用关系
v[0] = 'modify global list'
#可以理解为
# v = gls python的赋值为赋引用所以不会创建gls的副本
# v[0] = 'modify global list'
m_str(gstr)
m_hs(gls)
print gstr
print gls
输出:
global string
['modify global list', (1, 2)]
|
对于PHP,传递普通变量名为传值,传递引用型变量名为传引用
<?php
$a = array('i am global str');
function foo($b)
{
$b[] = 'add another';
}
//理解为
//$b = $a
//普通赋值会创建新的变量$b,$a不受影响
function foo2(&$b)
{
$b[] = 'add another';
}
//理解为
//$b = &$a;
//$b是一个引用型变量名,和变量名$a是等效的
//$b[] = 'add another';
foo($a);
var_dump($a);
foo2($a);
var_dump($a);
?>
输出:
array(1) {
[0]=>
string(15) "i am global str"
}
array(2) {
[0]=>
string(15) "i am global str"
[1]=>
string(11) "add another"
}
传递对象的变量名为"传引用"
//Human的例子见对象编程部分
$hm = new Human('han meimei');
function cname($hm)
{
$hm->name = 'li lei';
}
cname($hm);
print $hm->name;
输出:
li lei
引用型变量名使得PHP的引用传参是在真的引用
<?php
$a = 'i am a';
function test(&$b)
{
$b = 'i am b';
}
test($a);
var_dump($a);
?>
输出:
string(6) "i am b"
|
JS总是"传引用"的, 虽然权威指南说JS是部分类型传值,部分类型传引用,但是那样并不好理解
var sa = 'i am a string';
var aa = [1,2,3,4];
function foo(a)
{
a = 'i am another string';
}
//可以理解为
//var a = sa;
//a = 'i am another string';
//a的赋值只是改变了变量名a的引用到'i am another string';
//sa不受影响
function foo2(b)
{
b[0] = 'test';
}
//可以理解为
//var b = aa;
//赋值为赋引用,b现在指向aa
//b[0] = 'test';
foo(sa);
foo2(aa);
console.log(sa);
console.log(aa);
输出:
i am a string
["test", 2, 3, 4]
|
|
允许重复定义? | 允许,产生覆盖 | 不允许,产生Fatal error | 允许,产生覆盖 |
嵌套定义? |
Python中嵌套定义的函数会变成外部函数作用域的闭包函数
>>> def foo():
... def foo2():
... print 'i am foo2'
... foo2()
...
>>> foo()
i am foo2
>>> foo2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo2' is not defined
|
PHP中允许嵌套定义,但是定义的函数不能和全局函数重名
<?php
function test()
{
function foo()
{
echo 'i am foo';
}
foo();
}
test();
?>
输出:
i am foo
<?php
function foo(){echo 'i am foo';}
function test()
{
function foo()
{
echo 'i am foo too';
}
foo();
}
test();
?>
输出
PHP Fatal error: Cannot redeclare foo() (pr
eviously declared in /tmp/test.php:2) in /tm
p/test.php on line 5
PHP Stack trace:
PHP 1. {main}() /tmp/test.php:0
PHP 2. test() /tmp/test.php:13
嵌套函数无法访问外部函数作用域
<?php
function test()
{
$hi = 'i am test';
function foo()
{
echo $hi;
}
foo();
}
test();
?>
输出:
PHP Notice: Undefined variable: hi in /tmp/test.php on line 8
PHP Stack trace:
PHP 1. {main}() /tmp/test.php:0
PHP 2. test() /tmp/test.php:14
PHP 3. foo() /tmp/test.php:11
|
跟Python类似也会构成闭包函数,详见闭包部分 |
默认返回值 | None
>>> def foo():
... pass
...
>>> print foo()
None
|
null
php > function test(){}
php > var_dump(test());
NULL
php > var_dump(test() === null);
bool(true)
|
undefined
>>> function test(){};
undefined
>>> test();
undefined
|
传参 |
>>> def foo(a, b):
... print a,b
...
>>> foo('a', 'b')
a b
#python还有一种指定参数名的灵活调用方式
#可以不用按照顺序传参
>>> foo(b='b', a='a')
a b
#python会严格检查传参数目
>>> foo('a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arg
uments (1 given)
|
php > function foo($a, $b){echo $a . $b;}
php > foo('a', 'b');
ab
//PHP也会检查参数个数,出错时产生Warning
php > foo('a');
PHP Warning: Missing argument 2 for foo(), called
in php shell code on line 1 and defined in php she
ll code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
PHP 2. foo() php shell code:1
PHP Notice: Undefined variable: b in php shell co
de on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
PHP 2. foo() php shell code:1
a
|
>>> function foo(a,b){console.log(a + b);}
>>> foo('a', 'b');
ab
//JS对参数个数完全不做检查
>>> foo('a');
aundefined
>>> foo('a', 'b', 'c');
ab
|
默认参数 |
>>> def foo(a, b ='b'):
... print a,b
...
>>> foo('a')
a b
|
php > function foo($a, $b='b'){echo $a . $b;}
php > foo('a');
ab
|
没有语法支持 |
变长参数 |
Python有两种支持 非关键字变参:
>>> def foo(a, b, *m):
... print a,b,''.join(m)
...
>>> foo('a','b','c','d')
a b cd
关键字传参的变参
>>> def foo(a, b, **m):
... for k in m.keys():
... print k,m[k]
...
>>> foo('a','b',c='c',d='d')
c c
d d
|
来自PHP manual的范例
<?php
function foo()
{
$numargs = func_num_args();
echo "Number of arguments: $numargs<br />\n";
if ($numargs >= 2) {
echo "Second argument is: " . func_get_arg(1) . "<br />\n";
}
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
foo(1, 2, 3);
?>
输出:
Number of arguments: 3<br />
Second argument is: 2<br />
Argument 0 is: 1<br />
Argument 1 is: 2<br />
Argument 2 is: 3<br />
|
>>> function foo(){for(var i = 0;i < arguments.length;i++) console.log(arguments[i]);}
>>> foo('a','b','c');
a
b
c
|
前向引用 |
Python中的函数在定义之前无法使用
foo()
def foo():
print 'i am foo'
输出
Traceback (most recent call last):
File "test.py", line 2, in
|
可以
<?php
foo();
function foo()
{
echo 'i am foo';
}
?>
输出:
i am foo
|
可以
foo();
function foo()
{
console.log('i am foo');
}
输出:
i am foo
|
动态调用 |
Python中函数是可以引用的
>>> def foo():
... print 'i am foo'
...
>>> a = [1,2,foo]
>>> a[2]()
i am foo
|
PHP中通过function foo();形式定义的全局函数是不可以赋值给变量的 但是我们依然有两种方式可以动态调用
php > function foo($a){echo 'i am ' . $a;}
php > call_user_func('foo', 'test');
i am test
php > $a = 'foo';
php > $a('test');
i am test
|
JS中的函数也是可以直接引用的
>>> function foo(){console.log('i am foo');}
>>> window['foo']();
i am foo
>>> a = foo;
foo()
>>> a();
i am foo
|
闭包 |
>>> def counter():
... c = [0]
... def add():
... c[0] += 1
... return c[0]
... return add
...
>>> c = counter()
>>> c()
1
>>> c()
2
>>> c()
3
|
PHP从5.3.0开始支持闭包 匿名函数如果要访问外部函数作用域的变量必须通过use声明
<?php
function counter()
{
$c = 0;
return function() use (&$c)
{
return ++$c;
};
}
$c = counter();
var_dump($c());
var_dump($c());
var_dump($c());
?>
输出:
int(1)
int(2)
int(3)
|
实际编码中使用闭包最频繁的莫过于JS
function counter()
{
var c = 0;
return function()
{
return ++c;
};
}
var c = counter();
console.log(c());
console.log(c());
console.log(c());
输出:
1
2
3
|
Python | PHP | Javascript | |
说明 | 仅以PHP5以后的对象编程为例 | JS的对象编程恐怕是最无厘头的,拿出来单独写一个文档都够了,仅通过下面的示例无法了解原理 | |
定义 |
class Human(object):
def __init__(self, name):
self.name = name
def say(self, msg):
print '%s:%s' % (self.name, msg)
hm = Human('li lei')
hm.say('hi han meimei~')
输出:
li lei:hi han meimei~
|
<?php
class Human
{
function __construct($name)
{
$this->name = $name;
}
function say($msg)
{
printf('%s:%s', $this->name, $msg);
}
}
$hm = new Human('li lei');
$hm->say('hi han meimei~');
?>
输出:
li lei:hi han meimei~
|
function Human(name)
{
this.name = name;
}
Human.prototype = {
say:function(msg)
{
console.log(this.name + ':' + msg);
}
};
var hm = new Human('li lei');
hm.say('hi han meimei~');
输出:
li lei:hi han meimei~
|
实例类型判断 |
hm = Girl('han meimei')
print isinstance(hm, Girl)
print isinstance(hm, Human)
输出:
True
True
|
$hm = new Girl('han meimei');
var_dump(is_a($hm, 'Girl'));
var_dump(is_a($hm, 'Human'));
输出:
bool(true)
bool(true)
|
var hm = new Girl('han meimei');
console.log(hm instanceof Girl);
console.log(hm instanceof Human);
输出:
true
true
|
访问控制 (private,public) |
默认情况下对象的属性和方法都是可见的,可以通过在名字前加'__'双下划线使其变成私有
class Human(object):
def __init__(self, name):
self.__name = name
def say(self, msg):
print "%s:%s" % (self.__name, msg)
|
PHP中可以通过private和public关键字修饰
class Human
{
private $name = '';
function __construct($name)
{
$this->name = $name;
}
function say($msg)
{
echo sprintf('%s:%s', $this->name, $msg);
}
}
|
对于JS,闭包再一次帮了它
function Human(name)
{
this.name = function(v)
{
if (typeof v == 'string') name = v;
return name;
};
}
Human.prototype = {
say:function(msg)
{
console.log(this.name() + ':' + msg);
}
};
|
访问控制(protected) | 不支持 | 使用protected关键字 | 不支持 |
静态成员 |
python中使用staticmethod函数修饰符
class Human(object):
def __init__(self, name):
self.name = name
def say(self, msg):
print "%s:%s" % (self.name, msg)
@staticmethod
def get_name(hm):
return hm.name
hm = Human('li lei')
print Human.get_name(hm)
|
class Human
{
function __construct($name)
{
$this->name = $name;
}
function say($msg)
{
echo sprintf('%s:%s', $this->name, $msg);
}
static function get_name($hm)
{
return $hm->name;
}
}
$hm = new Human('han meimei');
echo Human::get_name($hm);
|
JS的静态方法直接当作构造函数的属性就可以了
Human.get_name = function(hm)
{
return hm.name;
};
|
继承 |
class Girl(Human):
def __init__(self, name):
super(Girl, self).__init__(name)
self.sex = 'girl'
hm = Girl('han meimei')
hm.say('hi li lei~')
输出:
han meimei:hi li lei~
|
class Girl extends Human
{
function __construct($name)
{
parent::__construct($name);
$this->sex = 'girl';
}
}
$hm = new Human('han meimei');
$hm->say('hi li lei~');
输出:
han meimei:hi li lei~
|
对于原型继承,一句两句说不清
function Girl(name)
{
Human.call(this, name);
this.sex = 'girl';
}
Girl.prototype = new Human();
var hm = new Girl('han meimei');
hm.say('hi li lei~');
输出:
han meimei:hi li lei~
|
多重继承 | 支持
class foo(P1, P2):
pass
|
没有语法支持 | 没有语法支持 |
判断继承关系 |
print issubclass(Girl, Girl)
print issubclass(Girl, Human)
print issubclass(Girl, object)
输出:
True
True
True
|
//PHP中没有一个所有类的根类,所以这里再多定义一层
//PHP通过类的实例来判断继承关系
class YoungGirl extends Girl{}
$hm = new YoungGirl('han meimei');
var_dump(is_subclass_of($hm, 'YoungGirl'));
var_dump(is_subclass_of($hm, 'Girl'));
var_dump(is_subclass_of($hm, 'Human'));
输出:
bool(false)
bool(true)
bool(true)
|
//仅适用于例子中的继承方式
console.log(Girl.prototype instanceof Girl);
console.log(Girl.prototype instanceof Human);
console.log(Girl.prototype instanceof Object);
输出:
false
true
true
|
接口 | 没有,靠自觉 |
interface fooInterface
{
function sayHi();
}
class foo implements fooInterface
{
function sayHi(){ echo 'hi';}
}
|
没有,靠自觉 |
重载 | 由于三种语言均没有显示类型声明,所以没有像C++和Java一样的重载 | ||
特殊方法 |
python定义了许多可以定制类行为的特殊方法
__init__ 构造函数
__del__ 析构函数
__str__ 用于str()
__unicode__ 用于unicode()
__nonzero__ 用于布尔转换
__len__ 用于len()
__cmp__ 对象比较
__getattr__ 获取不存在的属性时调用
....
查看更多
|
PHP中称这些特殊方法为魔术方法
__construct 构造函数
__destruct 析构函数
__call 调用不存在的方法时调用
__get 获取不存在的属性时调用
__set 设置不存在的属性时调用
__toString 转换成字符串时调用
....
查看更多
|
JS中影响对象行为的特殊方法寥寥
toString 将对象转换为字符串时调用
valueOf 将对象转换为数字时调用
|
Python | PHP | Javascript |
CHANGELOG ------------------------------------------------------------------------ r41 | emptyhua | 2011-01-24 15:11:36 +0800 (Mon, 24 Jan 2011) | 1 line 对象编程部分更新 ------------------------------------------------------------------------ r40 | emptyhua | 2011-01-20 15:15:59 +0800 (Thu, 20 Jan 2011) | 1 line 增加了更新日志,对象编程部分更新,这部分都不知该怎么表达了。。 ------------------------------------------------------------------------ r39 | emptyhua | 2011-01-18 16:42:58 +0800 (Tue, 18 Jan 2011) | 1 line 增加了部分对象编程 ------------------------------------------------------------------------ r38 | emptyhua | 2011-01-17 16:30:33 +0800 (Mon, 17 Jan 2011) | 1 line 增加PPJ文档 ------------------------------------------------------------------------