js的function--js详解(十一)

1、函数的定义

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	<script type="text/javascript">
	//第一种定义方式
	function fn1() {
		alert("fn1");
	}
	//函数就是一个非常特殊的对象,是一个Function类的实例,其实在内存中存储的操作是通过一个键值对来存储的
	alert(typeof fn1);
	
	//由于函数是一个对象,所以可以通过如下方式定义
	//以下是通过函数的拷贝来完成赋值,两个引用并没有指向同一个对象
	var fn2 = fn1;
	fn2();
	fn1 = function() {
		alert("fnn1");
	}
	/**
	 * 函数虽然是一个对象,但是却和对象有一些区别,对象是通过引用的指向完成对象的赋值的,而函数却是通过对象的拷贝来完成的
	 * 所以fn1虽然变了,并不会影响fn2
	 */
	fn2();
	fn1();
	
	/**
	 * 对于对象而言,是通过引用的指向来完成赋值的,此时修改o1或者o2会将两个值都完成修改
	 */
	var o1 = new Object();
	var o2 = o1;
	o2.name = "Leon";
	alert(o1.name);
	</script>
</head>
<body>
</body>
</html>

2、函数的重载

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	<script type="text/javascript">
	// function sum(num1,num2) {
		// return num1+num2;
	// }
	
	/**
	 * 等同于以上函数
	 */
	var sum = function(num1,num2) {
		return num1+num2;
	}
	
	// function sum(num1) {
		// return num1+100;
	// }
	/**
	 * 此时sum所指向的空间已经从有两个参数的函数变化到只有num1的函数中
	 * 在调用的时候就只会调用只有num1的函数
	 * 特别指出:函数的参数和调用没有关系,如果函数只有一个参数,但是却传入
	 * 了两个参数,仅仅只会匹配一个
	 * 所以在js中函数不存在重载
	 */
	var sum = function(num1) {
		return num1+100;
	}
	
	alert(sum(19));	//119
	alert(sum(19,20));	//119
	
	//函数有如下一种定义方式
	/**
	 * 如下定义方式等于定义了一个
	 * function fn(num1,num2){
	 * 	  alert(num1+num2);
	 * }
	 * 所以通过以下的例子,充分的说明函数就是一个对象
	 */
	var fn = new Function("num1","num2","alert('fun:'+(num1+num2))");
	fn(12,22);
	
	</script>
</head>
<body>
</body>
</html>

 3、函数的传值

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	<script type="text/javascript">
	/**
	 * 由于函数是对象,所以可以直接把函数通过参数传递进来
	 */
	function callFun(fun,arg) {
		//第一个参数就是函数对象
		return fun(arg);
	}
	
	function sum(num) {
		return num+100;
	}
	
	function say(str) {
		alert("hello "+str);
	}
	//var say = xxx
	//调用了say函数
	callFun(say,"Leon");
	//调用了sum函数
	alert(callFun(sum,20));	//120
	
	function fn1(arg) {
		/**
		 * 此时返回的是一个函数对象
		 */
		var rel = function(num) {
			return arg+num;
		}
		return rel;
	}
	//此时f是一个函数对象,可以完成调用
	var f = fn1(20);
	alert(f);	//function(num) {return arg+num;} 此时的arg = 10
	alert(f(20));	//40
	alert(f(11));	//31
	</script>
</head>
<body>
</body>
</html>

 4、函数排序

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div id="person"></div>
	<script type="text/javascript">
	/**
	 * 根据数字来进行排序的函数
	 */
	// function sortByNum(a,b) {
		// return parseInt(a)-parseInt(b);
	// }
	// alert("11"+1);	//111
	// //当进行减法的时候,会自动完成转换
	// alert("11"-1);	//10
	// var as = [1,2,"11px",33,"12px",190];
	// //对于js而言,默认是按照字符串来进行排序的
	// as.sort(sortByNum);	
	// alert(as); ////1,2,"11px","12px",33,190
	
	//测试根据对象排序
	function Person(name,age) {
		this.name = name;
		this.age = age;
	}
	var p1 = new Person("Leno",39);
	var p2 = new Person("John",23);
	var p3 = new Person("Ada",41);
	var ps = [p1,p2,p3];
	// ps.sort(sortByAge);
	//p1.name,p1["name"]
	/**
	 * 使用以下方法来处理排序,带来的问题是需要为每一个属性都设置一个函数,显然不灵活
	 * 但是如果通过函数的返回值调用就不一样了
	 */
	// function sortByName(obj1,obj2) {
		// if(obj1.name>obj2.name) return 1;
		// else if(obj1.name==obj2.name) return 0;
		// else return -1;
	// }
	// function sortByAge(obj1,obj2) {
		// return obj1.age-obj2.age;
	// }
// 	
	ps.sort(sortByProperty("age"))
	function sortByProperty(propertyName) {
		var sortFun = function(obj1,obj2) {
			if(obj1[propertyName]>obj2[propertyName]) return 1;
			else if(obj1[propertyName]==obj2[propertyName])return 0;
			else return -1;
		}
		return sortFun;
	}
	function show() {
		var p = document.getElementById("person");
		for(var i=0;i<ps.length;i++) {
			p.innerHTML+=ps[i].name+","+ps[i].age+"<br/>";
		}
	}
	show();
	</script>
</body>
</html>

 5、函数的arguments内部属性

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div id="person"></div>
	<script type="text/javascript">
	function say(num) {
		/*
		 * 在函数对象中有一个属性(内部属性)叫做arguments,通过这个属性可以获取相应的参数值,这个属性
		 * 是一个数组,其实就是传递进来的参数
		 */
		alert(arguments.length);
		for(var i=0;i<arguments.length;i++) {
			alert(arguments[i]);
		}
		alert(num);
	}
	/**
	 * 在arguments这个对象中有一个callee的方法,arguments.callee(arg)可以反向的调用函数本身
	 */
	
	// say(1,2,3);
	function factorial(num) {
		if(num<=1) return 1; 
		//此时和函数名耦合在一起
		// else return num*factorial(num-1);
		//以下就实现了函数名的解耦合,在js中通常都是使用这种方式做递归
		else return num*arguments.callee(num-1);
		 
	}
	/**
	 * 以上是一个求阶乘的函数,以上递归调用的函数名称和原有函数名耦合在一起了,如果将来这个函数名称更改之后,
	 * 递归调用就会失效
	 */
	var cf = factorial;
	//此时不会报错
	alert(cf(5));
	factorial = null;
	//此时由于cf这个函数依然使用factorial这个名称来调用,但是factorial已经指向null了,所以就会报错
	//如上情况就需要使用arguments.callee方法来调用
	alert(cf(5));
	</script>
</body>
</html>

 6、函数的this内部属性

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div id="person"></div>
	<script type="text/javascript">
	/**
	 * 当需要创建一个类的时候,设置类的属性和方法需要通过this关键字来引用
	 * 但是特别注意:this关键字在调用时会根据不同的调用对象变得不同
	 */
	
	var color = "red";
	function showColor() {
		alert(this.color);
	}
	/**
	 * 创建了一个类,有一个color的属性和一个show的方法
	 */
	function Circle(color) {
		this.color = color;
		this.showColor = showColor;
	}
	
	var c = new Circle("yellow");
	//使用c来调用showColor方法,等于调用了showColor()方法
	//此时的this是c,所以color就是yellow
	c.showColor();//yellow
	//此时调用的对象等于是window,showColor的this就是window,所以就会找window中color
	showColor();//red
	</script>
</body>
</html>

 7、函数的length

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div id="person"></div>
	<script type="text/javascript">
	function fn1() {
		
	}
	
	function fn2(num1,num2) {
		
	}
	
	function fn3(num1){
		
	}
	//函数的length就表示该函数所期望的参数值
	alert(fn1.length);//0
	alert(fn2.length);//2
	alert(fn3.length);//1
	</script>
</body>
</html>

 8、函数的call与apply

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div>
		call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this的指向。因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
		二者的作用完全一样,只是接受参数的方式不太一样。例如,有一个函数 func1 定义如下:
		var func1 = function(arg1, arg2) {};
		就可以通过 func1.call(this, arg1, arg2); 或者 func1.apply(this, [arg1, arg2]); 来调用。其中 this 是你想指定的上下文,他可以任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。
		JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数。
	</div>
	<script type="text/javascript">
	function sum(num1,num2) {
		return num1+num2;
	}
	
	function callSum1(num1,num2) {
		//使用sum这个函数来完成一次调用,调用的参数就是callSum1这个函数的参数
		//apply的第二个参数表示一组参数数组
		return sum.apply(this,arguments);
	}
	
	function callSum2(num1,num2) {
		//关键就是第二个参数是数组
		return sum.apply(this,[num1,num2]);
	}
	alert(callSum1(12,22));	
	alert(callSum2(22,32));
	
	function callSum3(num1,num2) {
		//call是通过参数列表来完成传递,其他和apply没有任何区别
		return sum.call(this,num1,num2);
	}
	alert(callSum3(22,33));
	</script>
</body>
</html>

   

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>js01_hello</title>
	<meta name="author" content="Administrator" />
	
</head>
<body>
	<div id="person"></div>
	<script type="text/javascript">
	/**
	 * 当需要创建一个类的时候,设置类的属性和方法需要通过this关键字来引用
	 * 但是特别注意:this关键字在调用时会根据不同的调用对象变得不同
	 */
	
	var color = "red";
	function showColor() {
		alert(this.color);
	}
	/**
	 * 创建了一个类,有一个color的属性和一个show的方法
	 */
	function Circle(color) {
		this.color = color;
	}
	
	var c = new Circle("yellow");
	
	showColor.call(this);//使用上下文来调用showColor,结果是red
	showColor.call(c);//上下文对象是c,结果就是yellow
	/**
	 * 通过以上发现,使用call和apply之后,对象中可以不需要定义方法了
	 * 这就是call和apply的一种运用
	 */
	</script>
</body>
</html>

猜你喜欢

转载自weifengxuxu.iteye.com/blog/2295152