【JavaScript: The Definitive Guide 读后感 】二、JavaScript中的function

  上一篇文章是讲了JavaScript中的变量,这篇讲是讲一下JavaScript中的function。只是我在看这本书的一个粗略的了解。这篇文章将从一下几个方面来讲解:

  JavaScript中函数的介绍

  首先介绍一下JavaScript中的function。在JavaScript中,function是通过一下方法来声明的。

function func(/*parameter*/) {
	/*the body of the function*/
	/*we can return the result*/
}

从上面这个例子中我们可以看出JavaScript中的函数声明方式,首先,是使用function这个关键字来声明函数的。func是我们声明的函数的名字,在括号里可以添加我们自己的函数参数,有关函数参数方面,将会在后面详细的讲解。然后就是在“{}”内的函数体。这里我们会发现JavaScript中函数和其他编程语言中函数的一个不同的地方,这就数JavaScript中,函数就不表明返回值的类型的。这个也可以理解,因为JavaScript是一个弱类型的语言,我们没有必要表明返回值的类型,因为程序会自动根据类型自动地转变返回值的。

  JavaScript中函数的参数

  这一段将讲讲JavaScript中函数的参数。在JavaScript中,函数的参数也和其他编程语言有点不同。

function add(a , b) {
	return a + b;
}

上面是一个很简单的add的函数,在这个函数中,我们会发现函数的参数没有类型要求的,只有参数的名字。这个也是因为JavaScript是一种弱类型的语言。我们可以通过a , b来获得传进来的变量的值。在JavaScript中,我们还可以使用另外的一种方法来获得传来的参数的值,那就是arguments这个关键字,这个也只能在函数体里使用,我们可以通过这个arguments对象来或者传进来的参数值。如arguments[0]就是a,arguments[1]就是b。另外,在JavaScript中,我们可以想函数中传递任意个实参,即
add(1 , 2 , 3 , 4 , 5);

上面这个代码,我们可以调用上面的那个add函数,因为只有两个参数有在函数中用到的,所以其他参数也就无用的了。但是我们可以通过arguments来获得传进来的函数。如下:
function max(a , b) {
	var ret = a;
	
	for (var i=0 ; i<arguments.length ; i++) {
		if (ret < arguments[i])
			ret = arguments[i];
	}
	
	return ret;
}

alert(max(1 , 2 , 3 , 4 , 100 , 5));
上面那段代码,虽然我们只有在函数中定义了两个形参,但是我们可以在调用函数的时候使用多个实参,使用arguments来获得这些形参的。如果当传入的参数个数少于在声明时候的个数,则后面的都是undifined的。我们还可以使用argumens.length来获得传进来实参的个数。相应的,如果我们想知道这个函数在声明的时候定义了几个形参,我们可以通过函数的一个length属性来获得。
function test(a , b) {
	if (arguments.callee.length > arguments.length) return "less";
	else if (arguments.callee.length < arguments.length) return "more";
	else return "equal";
}

alert(test(1));
alert(test(1 , 2));
alert(test(1 , 2 , 3));

上面的代码中,arguments.callee就是或者这个arguments所在的函数,自此的test函数。这里我还不明白既然length是function的属性了,为什么我们不能直接在函数中使用length,即
function test(a , b) {
	alert(length);
}

但是上面那段代码显示的是0,希望有大牛能帮我解答这个问题。

 

  JavaScript中的匿名函数

  接着我们讲讲在JavaScript中的匿名函数。
button.onclick = function() {
	/*body of function*/
}
例如上面的函数,我们没有必要知道函数的名字,所以就直接使用了匿名函数,这样使用起来比较的方便。接着让我们看一个比较有意思的事情,我们使用匿名函数来写递归。这里我们使用到的是上面我们讲到过的callee这个对象。在看代码之前,我首先介绍一下JavaScript中函数声明的特殊的方式,在JavaScript中,我们匿名声明函数的方式是成为Function Literals,这个和我们和我们通常声明的函数是有区别的,
function f(x) { return x*x; } // function statement
var f = function(x) { return x*x; }; // function literal

所以使用上面的方法,我们会看到一种比较有趣的方式,匿名函数实现递归。
var f = function (a) {
	if (a <= 1) return 1;
	else return (a * arguments.callee(a - 1));
}

alert(f(10));


  JavaScript中函数的一些特性,函数可以当作data使用
  在JavaScript中,一个比较有趣的事情就是,这里的函数我们可以当做data来使用。我们可以通过()来实行这个函数。请看下面这段代码:

function test() {
	var a = new Array();
	a[0] = function(x) {return x * x};
	a[1] = 10;
	a[2] = a[0](a[1]);
	alert(a[2]);
	
}
在上面的代码中,虽然上面的代码看起来比较的奇怪,但是正是说明了在JavaScript中,函数可以当做一种data进行保存起来。其实这种使用的方式给我们在编程的时候带来了很多方便,看看下面的代码:
function addEvent(f) {
	if (typeof window.onload != 'function') {
		window.onload = f;
	}
	else {
		var oldOnload = window.onload;
		window.onload = function() {
			oldOnload();
			f();
		}
	}
}

上面的代码主要是为了在我们在添加多个window.onload事件,在上面的代码中,我们首先是检查window.onload有没有事件了,如果没有的话,我们就把f当做window.onload事件,如果已经有添加了,那么就先保存前面的事件,然后在创建一个匿名function,先执行老的事件,然后执行新添加的事件,我们发现这里我们都是使用()来执行函数的。


  函数的属性以及函数的触发

  在上面,我们看到了我们可以使用()来invoke一个函数,在JavaScript中,还有其他方式来invoke一个函数。

  1.   call
  我们可以使用call来invoke一个函数
var a = 1;

function test(num) {
	alert(this.a + num);
}

var b = new Object();
b.a = 2;

test.call(b , 1);
test(1);
在上面的代码中,我们可以看到call中函数分为两部分,一部分是调用这个函数的对象,另外一部分是参数列表。还有在上面的代码中我们可以看到,类似this.a这种的,是根据调用这个函数不同的对象而不同的。

      2.    apply

  apply也可以用来invoke一个函数,只是在invoke一个函数的时候,第二部分的参数有一点不同,call是一个一个分开的,但是在apply中,使用的是array。见下面代码:

function flexisum(a) {
	var total = 0;
	for(var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (!element) continue; 
		
		var n;
		switch(typeof element) {
			case "number":
				n = element; 
				break;
			case "object":
				if (element instanceof Array) 
					n = flexisum.apply(this, element);
				else n = element.valueOf(); 
				break;
			case "function":
				n = element(); 
				break;
			case "string":
				n = parseFloat(element); 
				break;
			case "boolean":
				n = NaN; 
				break;
		}
		
		if (typeof n == "number" && !isNaN(n)) total += n;

		else throw new Error("sum(): can't convert " + element + " tonumber");
	}
	return total;
}

alert(flexisum(1 , [1 , 2]));
从上面代码,能看到一个apply的使用方式。


  函数的scope以及闭包

  最后,我们讲讲JavaScript中函数的scope以及闭包的使用。

  在JavaScript中,函数的scope在我们定义函数的时候就已经确定了的。我们这里主要看看函数中闭包,在讲函数中的闭包之前,我们先回忆一下scope chain。如果一个函数中使用一个变量,首先查看的是传进来的参数和函数中有没有定义这个变量,如果没有的话,我们就从上一层scope寻找。在上面,我们也已经知道,一个函数中有一个arguments这样一个变量,在我们调用一个函数中,我们首先会初始化这个变量,在这个变量中存放着我们传进来的参数和我们在函数中声明的变量。这样当我们在函数中使用到一个变量是,我们就是从arguments这里寻找的,如果没有的话,就从上一层的arguments进行寻找。在介绍上面的背景只是之后,我们看看下面的代码:

(function test () {
	var a = [];
	for (var i=0 ; i<10 ; i++) {
		a[i] = function() {
			alert(i);
		};
	}
	
	for (var i=0 ; i<10 ; i++) {
		a[i]();
	}
})();
看看上面代码的结果是什么?
(function test () {
	var a = [];
	for (var i=0 ; i<10 ; i++) {
		a[i] = function() {
			alert(i);
		};
	}
	
	for (var j=0 ; j<10 ; j++) {
		a[j]();
	}
})();
在比对上面的结果后,是不是觉得有点奇怪。首先我们说明一下上面函数的调用方式,上面函数test是会自动执行的,这样做的好处就是不会混论命名空间。现在我们来具体分析上面代码的原理。首先我们在test函数中声明了10个函数,并保存起来,然后在最后才执行这些函数。但是我们会发现上面两段代码执行的结果并不相同。只是一个循环变量不一样,为什么会出现上面的情况。这样就要讲到变量的scope chain了。我们看看执行a[]()函数时,i这个变量时从哪里来的。i这个变量没有在我们声明的function() {alert(i)}中,所以这个变量是在函数test中的。我们模拟一下a[]()函数的执行的过程。当执行到alert(i)时,首先在本函数的arguments中找有没有i这个变量,发现没有,就到上一级找,发现上一级arguments有i这个变量,就把上一级的变量拿过来了。所以women分析一下第二段代码,在这段代码中,当我们执行a[j]()这个函数是,test中变量i的值已经是10了,所以才会都是10的。但是在第一段代码中,由于JavaScript中没有块级的变量,第二个var i其实和第一个for中是同一个i,所以在arguments中只有一个i,这样我们每次在invokea[i]()时,i的值又从0到9,所以才会出现那种情况的。我们再来看一段代码:
var a = [];
(function test () {
	for (var i=0 ; i<10 ; i++) {
		a[i] = function() {
			alert(i);
		};
	}
	
	
})();

for (var i=0 ; i<a.length ; i++) {
	a[i]();
}
从上面的代码中,我们更加能体会到JavaScript中的闭包。在我们执行a[i]()的时候,函数test已经执行完毕了,local变量i应该是已经清除了的,那为什么我们在执行a[i]()时,函数还是可以访问i这个变量呢?这个因为在JavaScript中,由于发现有a是在外层的scope定义的,所以虽然test执行完了,但是在a[i](),使用到了i这个局部变量,所以test的arguments一直是保存着的,知道定义a[i]的scope也执行完了,才会一起删除arguments。在后面将JavaScript的class时,我们还能看到我们可以使用闭包来实现JavaScript的私有变量等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《汽车以太网:权威指南第版》是一本关于汽车领域以太网技术的详细指南。 随着汽车电子化快速发展,以太网逐渐成为汽车通信领域的主要技术,该书介绍了汽车以太网的各种标准、应用和实现方法。本书内容涵盖了以太网在车内和车外通信的应用,包括车联网、自动驾驶、诊断和测试等方面的应用及实践经验,详细阐述了汽车以太网的物理层、数据链路层、网络层和应用层等各个方面的知识。 本书不仅适合从事汽车电子和通信领域的工程师和研究人员阅读,也适合学习和了解汽车以太网技术的学生和教育工作者使用。 总之,《汽车以太网:权威指南第版》是一本理论与实践相结合的最全面、最详尽的汽车以太网技术指南,对于掌握汽车以太网技术具有重要的参考价值。 ### 回答2: "汽车以太网:第版定义指南"是一本解释汽车以太网技术的权威指南。本书详细介绍了汽车以太网在车辆的应用,包括在车辆通信和互联网连接方面的主要优势和挑战。 本书包括对汽车以太网的技术和体系结构的详细讲解。它描述了汽车以太网速度和协议的演进,重点介绍了10Base-T1L和1000Base-T1等重要设计标准,并对时域网络和数据包传输机制以及网络安全方面的问题进行了深入探讨。 此外,本书还探讨了汽车以太网和汽车系统开发的实际用例,并提供了一些方法论和最佳实践,以指导技术人员在产品开发的决策。最后,本书还对未来汽车以太网技术的发展和应用进行了预测和展望。 总之,“汽车以太网:第版定义指南”是一本深入探讨汽车以太网技术的优秀指南,对理解这一领域的技术、应用和发展趋势都有极大帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值