JavaScript根据函数名字符串调用函数的方法

最近遇到一个问题,JavaScript如何通过函数名的字符串来调用这个函数,到stackoverflow上逛了圈,收获良多,这里总结下:

如果你是要直接调用全局的函数,可以用如下方式:

//定义一个名为foo的函数
function foo() 
{
    alert(1);
}
//第一种调用方式
window['foo']();
//第二种调用方式
eval('foo()');

如果你想要在一个对象里面调用对象自己的属性函数,可以用如下方式:

var test = {
	foo : function(a) {
		alert(a);
	},
	bar : function() {
		var property = 'foo';
		var parameter = ['this is a test!'];
		var fn = this[property];
		if(typeof fn === 'function') {
			fn.apply(this, parameter);
		}
	}
};
test.bar();

上面这段代码是我写的一个小例子,其中的

fn.apply(this, parameter);

有几个好处,第一点就是可以让你调用的foo这个属性函数能够使用到当前的this,如果不用apply是无法调用到当前的this的。第二点就是传递参数变得很自由,如果属性函数需要传入多个参数可以用数组传入。

上面这段小代码就是我在“基于Requirejs和Backbonejs,将Zend Framework 2官方Demo改为RESTful架构的应用”里面做到自动路由分发的核心代码。

PHP判断某个数组中是否存在指定的key

PHP利用array_key_exists()函数判断某个数组中是否存在指定的key,如果该key存在,则返回true,否则返回false。

$search = array('first' => 1, 'second' => 4);
if (array_key_exists('first', $search)) {
    $search['first']++;
}

值得注意的是,以上代码其实可以使用isset来实现:

$search = array('first' => 1, 'second' => 4);
if (isset($search['first'])) {
    $search['first']++;
}

使用isset的好处是isset的速度比array_key_exists()函数要快,因为isset不是函数,PHP能够像if else语句一样直接调用,而array_key_exists()的调用还需要查询PHP的函数库,搜索array_key_exists()函数比较耗时间。虽然如此,isset跟array_key_exists()函数比起来还是有缺陷的,例如:

$search = array('first' => null, 'second' => 4);

isset($search['first']); //返回false

array_key_exists('first', $search); //返回true

通过上面的例子可以看出$search[‘first’]如果等于null的时候,isset就无法发挥作用了。
因此,这两个函数的使用还得分场合,需要大家好好考虑。

JavaScript的split函数在IE浏览器下无法使用的解决方法

        今天我在工作的时候遇到了一个问题,在JavaScript中使用split函数对特定的字符进行分割,在谷歌和火狐浏览器下是正确的,但是在IE浏览器下却无法正常工作。后来,在http://blog.stevenlevithan.com/archives/cross-browser-spli 中找到了答案!解决方法如下:

        你不需要改动原来的代码,只需要在你的代码中添加如下函数,即可解决split函数在IE浏览器下无法使用的问题:

var split;

// Avoid running twice; that would break the `nativeSplit` reference
split = split || function (undef) {

    var nativeSplit = String.prototype.split,
        compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
        self;

    self = function (str, separator, limit) {
        // If `separator` is not a regex, use `nativeSplit`
        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
            return nativeSplit.call(str, separator, limit);
        }
        var output = [],
            flags = (separator.ignoreCase ? "i" : "") +
                    (separator.multiline  ? "m" : "") +
                    (separator.extended   ? "x" : "") + // Proposed for ES6
                    (separator.sticky     ? "y" : ""), // Firefox 3+
            lastLastIndex = 0,
            // Make `global` and avoid `lastIndex` issues by working with a copy
            separator = new RegExp(separator.source, flags + "g"),
            separator2, match, lastIndex, lastLength;
        str += ""; // Type-convert
        if (!compliantExecNpcg) {
            // Doesn't need flags gy, but they don't hurt
            separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
        }
        /* Values for `limit`, per the spec:
         * If undefined: 4294967295 // Math.pow(2, 32) - 1
         * If 0, Infinity, or NaN: 0
         * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
         * If negative number: 4294967296 - Math.floor(Math.abs(limit))
         * If other: Type-convert, then use the above rules
         */
        limit = limit === undef ?
            -1 >>> 0 : // Math.pow(2, 32) - 1
            limit >>> 0; // ToUint32(limit)
        while (match = separator.exec(str)) {
            // `separator.lastIndex` is not reliable cross-browser
            lastIndex = match.index + match[0].length;
            if (lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));
                // Fix browsers whose `exec` methods don't consistently return `undefined` for
                // nonparticipating capturing groups
                if (!compliantExecNpcg && match.length > 1) {
                    match[0].replace(separator2, function () {
                        for (var i = 1; i < arguments.length - 2; i++) {
                            if (arguments[i] === undef) {
                                match[i] = undef;
                            }
                        }
                    });
                }
                if (match.length > 1 && match.index < str.length) {
                    Array.prototype.push.apply(output, match.slice(1));
                }
                lastLength = match[0].length;
                lastLastIndex = lastIndex;
                if (output.length >= limit) {
                    break;
                }
            }
            if (separator.lastIndex === match.index) {
                separator.lastIndex++; // Avoid an infinite loop
            }
        }
        if (lastLastIndex === str.length) {
            if (lastLength || !separator.test("")) {
                output.push("");
            }
        } else {
            output.push(str.slice(lastLastIndex));
        }
        return output.length > limit ? output.slice(0, limit) : output;
    };

    // For convenience
    String.prototype.split = function (separator, limit) {
        return self(this, separator, limit);
    };

    return self;

}();

PHP编码规范(建议)

命名规则

函数命名

函数采用驼峰命名规则。一般采用

actionDescribeTarget

的形式。

例如:

getInternalName

getName

getValue

 

动作的名称使用匹配的方法规则。以下是常用的配对

get/set

from/to

init/uninit

add/remove

避免采用value(),name()这类语义不清的函数名。

 

对于缩写,推荐仅首字母大写。例如

parseXmlText

而不采用

parseXMLText.

 

对于类中的protected以及private函数,加前导线’_’例如

protected function _intertnalInit(){}

 

类命名

一般命名规则为class MyClassName,即所有首字母大写。

 

类库命名

采用以下命名规则:

类库名_Abstract_名称_类型_Interface

例如:

Zend_Session_Adapter_Interface

Zend_Session_Namespace

 

文件的目录则为

Zend/Session/Adapter/Interface.php

一般的功能类,不使用下划线分割。

 

文件命名

文件命名和类命名相似。

例如:

MyFileName.php

 

变量命名

局部变量

建议采用驼峰命名法。

例如:

$errCode

也可以采用简单的

$error

 

类的内部变量

采用前导下划线声明,采用驼峰命名法。例如

class A

{

static private $_instance;

}

 

书写规则

脚本声明

Php代码使用<?php的头声明,不得使用<?头声明。

对于非嵌入网页的脚本,不得使用?>尾部声明。防止另外追加的空格或者回车影响输出。

文件编码

除非有特殊原因,所有文件都应该使用utf-8编码,并且尽量避免中英文混排。

缩进

代码缩进采用4个字符空格的tab键

大括号规则

对于类、函数声明采用以下格式,首大括号另起一行。

class A

{
}

 

function B()

{
}

 

对于if/else/switch/while等判断条件语句,首大括号不另起一行。

if (){

}

else{

}

while(){

}

switch(){

case 0:

break;

default:

break;

}

的方式。

 

判断

是/非判断:

不能使用

if (true == judge()){

}

这样的判断,而应该使用

if (judge()){
}

同样

if (false == judge()){

}

也是不能使用的方法。应该写作:

if (!judge()){

}

除非必须判断强等于时,例如

if (false === judge()){
}

则可以使用。

注释

文件、函数、类应该有完整注释。

 

文件注释:

文件注释用于描述文件的信息。一般包括以下内容:

文件名       可以包含完整路径

作者         作者名字,email地址

创建时间      发布文件的时间

文件说明

修改历史      文件修改的历史记录

 

/**

* index.php

* author:  张三<zhangsan@qq.com>

* create:  2009-2-27

* note:

*    采用XXX的方法,可以完成YYY的效果。

* history:

*     2002-02-28 修订了认证失败信息错误的Bug

*/

 

函数注释

/**

* 函数描述,功能性描述

*

* @param  类型 参数名称 描述

* @return 类型

*/

 

例如:

/**

* 计算传入参数的和

*

* @param  number $a

* @param number  $b

* @return number

*/

function add($a, $b)

{
}

注:Zend Studio可以自动生成这个形式的注释。

 

类注释

当前类的一些功能。所属的包。等其他说明信息。

一般一个文件一个类。文件的注释和类的注释有相重的地方。

 

Tonitech版权所有 | 转载请注明出处: http://www.tonitech.com/?p=1167

浅谈C++与PHP中的构造函数与析构函数

        第一次接触构造函数和析构函数,是学C++的时候,然而一年多没接触C++,似乎对于这两个“类中函数”,早已忘得差不多了。这几天在学PHP,又遇到了这两函数,由于对于构造函数和析构函数的了解不深,今天就好好研究了一下下。

      先说说在C++中的构造函数和析构函数。C++中提供了构造函数来处理对象的初始化,但是不能说构造函数的主要作用是用来对对象进行初始化。构造函数是一种特殊的成员函数,不需要用户调用,在建立对象时,构造函数就会自动执行。而且构造函数的名字必须与类名相同。注意,不能由用户任意命名。有时候也会在想,我们都是在什么时候调用构造函数的?其实,在类对象进入其作用域是就调用了构造函数。构造函数没有返回值,所以也不需要在定义构造函数时声明函数类型,这是构造函数和一般函数的一个不同之处。在定义构造函数的时候,可以带参数,也可以不带参数。但是呢,带参数的构造函数有一个很大的优点:采用带参数的构造函数,在调用不同对象的构造函数时,可以将不同的数据从外面传递给构造函数,以实现不同的初始化。不过这时候要注意几点。首先,我们已经知道用户是不能调用构造函数的,所以不能像常规的调用函数的方法来对构造函数给出实参。在C++中,构造函数的实参是在定义对象时给出的。

        不过这时候我们也会在想,如果用户没有定义构造函数,那会有构造函数么?其实,如果用户没有自己定义构造函数,则C++系统会自动生成一个构造函数。在了解构造函数的时候,我们还得知道一个名词:重载。构造函数的重载,通俗来说就是定义很多个不同的构造函数,但是,函数名必须相同,其中不相同的是,构造函数的参数的个数和参数的类型不同。还需明白的一点是:构造函数的参数的值既可以通过实参传递,也可指定为某些默认值。不过,一般不应同时使用构造函数的重载还有默认参数的构造函数。

        析构函数是什么?我们可以这样理解,析构函数是与构造函数作用相反的函数。从析构函数的名字也可以看出。数学中,数A的相反数是-A。所以可以映射到C++中,构造函数A的作用相反的函数就是析构函数~A。注意,不是-A!就像我们不能说构造函数的主要作用是用来对对象进行初始化一样,析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。同构造函数一样,析构函数没有返回值,没有函数类型。不过析构函数也没有函数参数。可以说析构函数是“三无函数”。因为没有函数参数,所以析构函数不能被重载。因此只有一个析构函数!要切记。在使用构造函数和析构函数时,其顺序可以简单记为:先构造的后析构,后构造的先析构。就好比栈操作,先进后出。

        简单了解完C++中的构造函数和析构函数后,现在来说说PHP中的构造函数与析构函数。在PHP4中,构造函数是类中的一个特殊函数,构造函数与类同名。当使用 new 操作符创建一个类的实例时,构造函数将会自动调用。如果一个类没有构造函数,则调用基类的构造函数,前提是基类有构造函数。然而,在PHP5引入了一个声明构建函数的标准方法: __construct()。这里需要提醒的是:construct()函数前的下划线“_”是两个!!!如果少写一个“_”,结果就错了。见Example1

 Example1:

 Code:

<?php 

	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function _constuct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果: 

 

 

Example2:

Code:

<?php 
	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function __constuct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果:

 

但是,如果没有定义构造函数__construct()怎么办?此时,系统会自动查找是否有与类同名的函数,如果有,此时,构造函数将会变成与类同名的函数。如Example2。

如果同时存在__construct()函数和与类同名的函数,如example3,此时,两个函数是一样的,只执行一个函数。

Example3:

Code: 

<?php 

	/*类的实例4:实现Iterator接口的迭代  */
		class MyIterator implements Iterator
		{
			private $var = array();
			public function __construct($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			}

			public function MyIterator($array)
			{
				if(is_array($array))
				{
					$this-&gt;var = $array;
				}
			} 

			public function rewind()
			{
				echo "rewinding\n";
				reset($this-&gt;var);
			}

			public function current()
			{
				$var = current($this-&gt;var);
				echo "current:$var\n";
				return $var;
			}

			public function key()
			{
				$var = key($this-&gt;var);
				echo "key:$var\n";
				return $var;
			}

			public function next()
			{
				$var = next($this-&gt;var);
				echo "next:$var\n";
				return $var;
			}

			public function valid()
			{
				$var = $this-&gt;current() !== false;
				echo "valid:{$var}\n";
				return $var;
			}
		}

		$values = array(1,2,3);
		$it = new MyIterator($values);

		foreach ($it as $a =&gt; $b)
		{
			print "$a:$b\n";
		}

输出结果:

        对于析构函数,在PHP4中,析构函数是不存在的。但是,PHP5中有析构函数。其他的与C++中的一样。记得析构函数是没有参数的。