`
wangyijiangshui
  • 浏览: 85251 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类

JavaScript函数

 
阅读更多

1、函数的定义

JavaScript中的函数定义有三种,分别如下:

 

/**
 * 函数定义方式一:命名方式/声明式
 */
function test_1() {
	alert("我是命名式函数,或者是声明式函数定义");
}

/**
 * 函数定义方式二:匿名式/引用式函数/函数表达式
 */
var test_2 = function() {
	alert("我是匿名式、引用式或者函数表达式式 的函数定义");
}

/**
 * 函数定义方式三:构造Function对象(直接通过字符串构造函数)
 */
var test_3 = new Function("arg1","arg2", "alert('我是Function对象构造出来的的方法,参数:'+arg1+','+arg2)");

//test_3的调用方式,如果不传参,则在函数体内获得的参数值将是undefined,多传参数,只前两个有效,不影响功能。
test_3(20,"ttt",200);

 

注意”声明式函数定义"与"匿名式函数定义"的区别:二者的区别主要在执行的先后顺序上:浏览器加载完js代码后,”声明式函数“代码会在函数执行代码执行之前被解析器解析,而”匿名式函数“定义则是在函数运行中进行动态解析的——不理解?看下面的例子:

 

/**
 *  声明式定义函数test
 */
function test() {
	alert("one");
}
//调用一次
test();

/**
 *  声明式再定义一遍函数test
 */
function test() {
	alert("two");
}
//再调用一次
test();

//两次调用的结果都为two,因为“声明式定义函数”的代码先与“执行代码”执行,所以在两次调用test函数时
//test函数的真实函数体是第二次定义后的函数体。

 

2、函数闭包,一个函数的返回值仍然是一个函数(通俗理解:闭包就是一个函数定义在另一个函数中),例如:

 

function test() {
	return test;
}
//无论调用多少次,最终得到的结果还是函数本身,打印结果将是定义的函数体
alert(test()()()()()()()()()()());

 

 

3、一般情况,在JavaScript中,一个函数的形参或者函数体内的局部变量在函数调用完成,执行的返回操作,则全部销毁,不在存在,但是通过闭包,可以让其不销毁,办法如下: 

 

function test(a) {
	var b = 1;
	//采用闭包,并且闭包函数内部使用a、b参数,这样a和b参数在函数调用完成后仍不会销毁
	return function(x){
		return x + a + b;
	}
}
//该方法调用结束后,其内容的a、b参数变量不会销毁。
test(100);

 

 

4、使用try……catch……finally让函数多次执行return语句

 

function test() {
	var obj = new String("ttttttttttttt");
	
	try {
		return obj;
	} catch (ex) {
		
	} finally {
		obj = null;
		return null;
	}
}

//当调用函数,执行多次return语句后,最后得到的结果是最后一次执行return语句的结果。
//以下打印的结果是null
alert(test());

 

 

5、函数形参和实参

相信任何一个开发人员对于函数的形参和实参的概念都是了如指掌的,不做详述,这里主要要说的是,javascript中函数的实参个数与行参个数没有关系,当实参少于形参时,多余的形参值为undefined,当实参多余形参时,多余部分可以通过Arguments对象来访问。

 

function test(x, y, z) {
	
} 

//函数的length属性记录的是函数的形参数量,以下结果打印3,说明test函数有三个形参
alert(test.length)

 

 

6、Arguments对象

该对象是任何”函数对象“都拥有的一个属性,记录着调用该函数时传入的实参信息。改变arguments中元素的值,对应的形参值会同步改变,反之亦然。

 

function test(x, y) {
	var xcLength = test.length;
	var scLength = arguments.length;
	alert("形参的个数为:" + xcLength + ",实参的个数为:" + scLength);
	var str = "";
	
	for (var i = 0; i < scLength; i=i+1) {
		str = str + "," + arguments[i];
	}
	alert("你传入的实参值为:" + str);
	
	alert("x1="+x);
	arguments[0] = "呵呵,我变了,x的值也会跟着变,不信你试试!!";
	alert("x2="+x);
} 
//调用
test(1, 2, 3, 4, 5, "55555", "OK!");

 

 

7、使用Arguments对象模拟实现函数重载

以下函数实现,接收多种不同类型不同数目的实参,模拟函数重载

 

function test() {
	var paramsLength = arguments.length;
	if (0 == paramsLength) {
		alert("小东西,一个实参都不给,太吝啬!!");
	} else if (1 == paramsLength && (typeof(arguments[0]) == "number" || arguments[0] instanceof Number)){
		alert("你传入的是Number类型的数据,对不对呀?");
	} else if (1 == paramsLength && (typeof(arguments[0]) == "string" || arguments[0] instanceof String)) {
		alert("呵呵,你传入的是String类型的实参!");
	} else if (paramsLength > 1) {
		throw new TypeError("传入实参过多,该函数不支持!");
	} else {
		throw new TypeError("非法的实参数据类型,该函数不支持!");
	}
}
//执行
try {
	test();
	test(100);
	test("tttt");
	test(100,20,"KKKK");	
} catch (e) {
	alert(e);
}

 

 

8、Arguments对象的callee属性

该属性被用来引用当前正在执行的函数本身,通过它可以实现一种匿名的递归调用能力,这对于闭包来说非常有用

 

/**
 * 递归计算从1加到指定实参值的总和
 * 方法一
 */
function test1(x) {
	if (x <= 1) {
		return x;
	} else {
		return x + test1(x -1);
	}
}

/**
 * 方法二
 * 
 */
function test2(x) {
	if (x <= 1) {
		return x;
	} else {
		return x + arguments.callee(x -1);
	}
}
//函数调用,计算1+2+3+4+5的值
alert(test1(5));//15
alert(test2(5));//15

 

callee执行的是函数本身,而this指向的是当前函数的所有者对象,注意区分

 

 

function test() {
	this.x = 100;
	//打印出来的是函数体本身
	alert(arguments.callee);
	//打印的是一个Object对象引用
	alert(this);
}
//调用
test();

 

9、下面采用Arguments实现函数的重载机制

 首先定义几个不同类型实体类型——交通工具

 

/**
 * 定义汽车类
 */
function Car(name) {
	this.name = name;
}
/**
 * 重写汽车类的toString方法
 */
Car.prototype.toString = function() {
	return "汽车牌号:" + this.name;
}

/**
 * 定义飞机类
 */
function Plane(name) {
	this.name = name;
}
/**
 * 重写飞机类的toString方法
 */
Plane.prototype.toString = function() {
	return "飞机编号:" + this.name;
}

/**
 * 定义轮船类
 */
function Boat(name) {
	this.name = name;
}
/**
 * 重写轮船类的toString方法
 */
Boat.prototype.toString = function() {
	return "轮船标号:" + this.name;
}
        然后定义一个能够,根据不同的参数,动态调用不同的方法的方法

 

 

/**
 * 匹配参数类型和参数值,自动调用符合条件的重载函数
 * 
 * @param	func	将要被调的函数
 * @param	func	参数类型与值的映射
 * @param	func	函数所有者
 */
function callOverloadMethod(func, argMaps, owner) {
	owner = owner || null;
	var args = [];
	
	for (var i = 0; i < argMaps.length; i++) {
		if (argMaps[i].type != typeof(argMaps[i].arg) && !(argMaps[i].arg instanceof argMaps[i].type)) {
			return;
		} else {
			args.push(argMaps[i].arg);
		}
	}
	return func.apply(owner, args);
}
     定义一个存在重载方法的函数

 

 

/**
 * 定义一个司机类,用于开各种交通工具
 * 
 * @param	dirverName	司机姓名
 * @param	meansOfTransportation	交通工具类	
 */
function Driver(dirverName, transportationTool) {
	this.diverName = dirverName;
	this.doing = "";
	
	/**
	 * 开汽车
	 * @returns {driverCar}
	 */
	function driverCar(car) {
		this.doing = "【"+this.diverName + "】正在开汽车," + car;
	}
	
	/**
	 * 开飞机
	 * @returns {driverPlane}
	 */
	function driverPlane(plane) {
		this.doing = "【" + this.diverName + "】正在开飞机," + plane;
	}
	
	/**
	 * 开轮船
	 * @param boat
	 */
	function driverBoat(boat) {
		this.doing = "【" + this.diverName + "】正在开轮船," + boat;
	}
	
	/**
	 * 参数不够时的默认处理方法
	 */
	function doNothing() {
		this.doing = "你传给的参数不够,我不知道做什么,我勒个去…………";
	}
	
	/**
	 * 表示参数类型与值的映射类
	 * 
	 * @param type
	 * @param arg
	 * @returns {___anonymous5119_5138}
	 */
	function toolType(type, arg) {
		return {type:type, arg:arg};
	}
	//方法——数据类型——参数的映射关系
	var funcs = [
			[driverCar, [toolType(Car, transportationTool)]],
			[driverPlane, [toolType(Plane, transportationTool)]],
			[driverBoat, [toolType(Boat, transportationTool)]]
	];
	
	//开始实现司机的实际处理业务逻辑,如果连司机都没有指定,则默认交给队长开飞机
	if (0 >= arguments.length) {
		Driver.call(this, "队长", new Plane("空军一号"));
	//仅指定了司机
	} else if (1 == arguments.length)  {
		this.doNothing();
	//如果既指定了司机,又指定了交通工具,则根据不同的交通工具调用不同的处理方法
	} else if (2 == arguments.length) {
		for (var i = 0; i < funcs.length; i=i+1) {
			try {
				callOverloadMethod(funcs[i][0], funcs[i][1], this);
			} catch (ex) {
				alert(ex);
			}
		}
	} else {
		throw new Error("参数过多,系统不接受!");
	}
}
/**
 * 重写Driver类的toString方法
 */
Driver.prototype.toString = function() {
	return this.doing;
}
      最后测试:
//调用测试
try {
	var d = new Driver();
	alert(d);

	var d1 = new Driver("张三", new Plane("波音一号001"));
	alert(d1);

	var d2 = new Driver("李四", new Car("皖A 000111"));
	alert(d2);

	var d3 = new Driver("王五", new Boat("泰坦尼克号"));
	alert(d3);

	var d4 = new Driver("赵六", 11, 200);
	alert(d4);
} catch (ex) {
	alert(ex);
}

 

 10、函数的调用者和所有者

 

//默认的全局this指向的是Window对象
alert(this);

/**
 * 定义一个全局函数
 */
function test() {
	alert(this);
}
//直接调用test函数,则其内部的this仍然指向window对象,其实本质上下面的调用相当于window.test();
test();

//定义一个对象,并将方法test作为对象的一个成员方法
var testObj = {};
testObj.fun = test;
//则此时test()方法内部的this指向testObj对象
testObj.fun();

/**
 * 方法的调用者和所有者区分
 */
function callMethod() {
	//testObj是fun方法的所有者,而callMethod是fun的调用者。
	testObj.fun();
}
callMethod();

 

11、函数的动态调用(call和apply方法)

 call和apply大致相同,任何方法通过这两个方法动态调用,则其内部的this都指向call或者apply的第一个参数,二者的区别在于

call和apply除第一个参数都为调用函数的对象外,call剩余参数都为传给被调用方法的实参,可以任意多个,apply只有两个参数,第二个

参数为被调用函数的实参数组

 

function doWork(name, age) {
	this.msg = "["+name+"],今年["+age+"]岁了,在干活…………" + this;
}

function callDoWork(msg, sm){
	alert(this.msg+"," + msg+","+sm);
}

var d = new doWork("张三", 100);
//将callDoWork方法作为d对象的方法调用,此时callDoWork方法中的this指向d
callDoWork.call(d, "你好!");
//将callDoWork方法作为d对象的方法调用,此时callDoWork方法中的this指向d
callDoWork.apply(d, ["您好!","我也好!"])

 

12、函数作为参数和返回值

 使用函数作为参数

//求一个数的平方
function sub2(x) {
	return x * x;
}
//计算从1到指定数的平方和
function test(num, op) {
	var totle = 0;
	for (var i = 0; i < num; i++) {
		totle = totle + op(i);
	}
	return totle;
} 
//求1到5的每一个数的平方和
alert(test(5, sub2));

       使用函数作为返回值

 

/**
 * 字符串累加
 */
function concatStr() {
	var temp = "";
	if (arguments.length > 0) {
		for (var i = 0; i < arguments.length; i++) {
			temp = temp + "," + arguments[i];
		}
	}
	return temp;
}

/**
 * 数字累加
 */
function addNum() {
	var temp = 0;
	if (arguments.length > 0) {
		for (var i = 0; i < arguments.length; i++) {
			temp = temp + arguments[i];
		}
	}
	return temp;
}

/**
 * 如果type为数字,则返回一个数字累加函数,否则返回一个字符串累加函数
 * 
 * @param type
 * @returns
 */
function test(type) {
	if (typeof(type) == "number" || type instanceof Number) {
		return addNum;
	} else {
		return concatStr;
	}
}
//打印:21
alert(test(1)(1,2,3,4,5,6));
//打印:,1,2,3,4,5,6
alert(test("str")(1,2,3,4,5,6));

 

13、用var与不用var的区别

全局变量没有区别,但是函数内部的变量,如果不用var声明,则表示你声明了一个全局变量

//函数内部的n用var声明,则n为局部变量,函数外部如果访问n,则报错:Uncaught ReferenceError: n is not defined 
function test() {
	var n = 0;
}
test();
alert(n);

//函数内部的变量不用var声明,则表示是一个全局变量,只要执行test函数,则全局就存在n变量,可以在函数外访问
function test() {
	n = 0;
}
test();
alert(n);

 

 14、使用Function构造函数,将一个字符串构造成函数对象

 

var str = "var temp = 0; for (var i=0; i < arguments.length; i++){temp = temp + arguments[i]} return temp;";
var add = new Function(str);
alert(add(1,2,3,4,5,6));//21

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    javascript函数式编程

    JavaScript函数式编程是利用JavaScript语言编写函数式风格代码的一种编程范式。函数式编程强调使用纯函数、避免副作用、函数的不可变性以及利用高阶函数等概念。通过阅读《JavaScript函数式编程指南》,读者可以了解...

    JavaScript函数式编程.pdf

    不过,由于【标题】中提供了文档的名称——"JavaScript函数式编程.pdf",我可以根据这个名称扩展出关于JavaScript函数式编程的知识点。 JavaScript函数式编程的知识点非常丰富,涉及很多方面的内容,下面将详细介绍...

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    C#与JAVASCRIPT函数的相互调用 C#调用JAVASCRIPT函数的调用 JAVASCRIPT调用C#函数的调用

    javascript函数速查

    JavaScript函数是编程语言的核心组成部分,它是一段可重复使用的代码块,可以接受参数并返回值。在JavaScript中,函数不仅可以作为表达式,还能作为变量赋值、作为参数传递以及作为返回值。本速查指南将深入探讨...

    javascript函数速查手册

    JavaScript函数是编程语言的核心组成部分,尤其在Web开发中起着至关重要的作用。这份"JavaScript函数速查手册"涵盖了JavaScript函数的各个方面,旨在帮助开发者快速查找和理解各种函数的用法和特性。 一、函数基础 ...

    QT和网页中的JavaScript函数进行相互调用的实现

    - 这里的回调函数用于处理JavaScript函数的异步返回结果,如果需要同步获取结果,可以使用`QWebEngineScript`来注册一个全局JavaScript对象,然后通过该对象调用JavaScript函数。 2. **JavaScript调用QT函数**: ...

    javascript 函数教程(由浅入深)

    以下是关于JavaScript函数的详细讲解: 1. **函数定义**: - 无参函数定义:`function 函数名 () { 代码... }` - 有参函数定义:`function 函数名 (参数列表) { 代码... }` - 参数列表中的参数可以是变量、常量...

    JavaScript函数式编程pdf

    JavaScript函数式编程是一种编程范式,它将计算视为数据处理,并强调使用无副作用的纯函数。在JavaScript中,函数式编程允许我们写出更简洁、可读性更强的代码,同时提高了代码的复用性和测试性。《JavaScript函数式...

    javascript函数式编程 underscore.js

    JavaScript函数式编程是一种编程范式,它强调使用函数来组织代码,将计算视为一系列惰性求值的操作。Underscore.js是一个轻量级的JavaScript实用库,它为开发者提供了大量函数式编程工具,使得在JavaScript中实践...

    JavaScript函数(源代码)

    JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)JavaScript函数(源代码)...

    JavaScript 函数式编程 (英文版)

    JavaScript函数式编程是一种编程范式,它强调将计算视为对数据进行操作的纯函数,而不是通过改变状态或显式指令来控制程序流程。在JavaScript中,函数式编程可以帮助我们写出更简洁、可读性强且易于测试的代码。下面...

    JavaScript函数式编程

    JavaScript函数式编程

    javascript指南和函数式编程

    而《JavaScript函数式.zip》可能是一份关于JavaScript函数式编程的资料集合,函数式编程是一种编程范式,强调使用函数和避免改变状态。其中可能涵盖以下知识点: 1. **纯函数**:理解纯函数的定义,即给定相同的...

    第7节 JavaScript函数及应用.rar

    第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数及应用.rar第7节 JavaScript函数...

Global site tag (gtag.js) - Google Analytics