1.函数的概念
先看一下输出100所有素数问题的解决方案
方案一:循环的嵌套
for(var n=2;n<100; n++){ var m = Math.ceil(Math.sqrt(n)); var sum = false; for(var i = 2;i<num; i++){ if(num%i == 0){ sum = true; break; } } document.write(sum?"不是质数":"是质数"); }
这种解决方案程序比较复杂,阅读也比较困难,需要比较高超的技术
方案二:运用函数
<script> /*假设系统已经提供了一个判断素数的函数isPrime(x),那么问题是否就很简单 * */ for(var n=2; n<=100; n++){ if(isPrime(n)){ document.write(n+"<br>"); } } function isPrime(n){ var m = Math.ceil(Math.sqrt(n)); var found = false; for(var i = 2;i<m; i++){ if(num%i == 0){ return false; } } return true; } </script>
这种解决方案是将一个比较复杂的问题分解为两个较为简单的问题去解决,是用“量”去客服“难”和“大”的问题。也就是“大事化小”。
这种解决方案给我们提供了一个解决规模大、难度高的问题的解决思路:将它分解为多个规模相对较小、难度相对较低的问题去解决、如果分解后的问题依然规模大或者难度高,可以按照这个思路一直分解下去,知道分解后的问题足够小、简单。归纳起来就是“大事化小”。
2 函数与调用
函数是什么?怎么用?
定义:
function isPrime(){
………
}
Function 定义函数的关键字
isPrime: 是函数的名字,和变量名一样的命名规则和原则
n 形式参数(形参)
isPrime(12);12就是实际参数(实参)
函数头部:体现的是函数的设计
函数体:体现的是函数的实现过程
设计比实现更重要
如果一个问题,可以设定一个函数,如果还是无法解决那就继续拆分
案例:验证100以内的数都复合角谷定理
var flag = true; for(var n=2; n<100; n++){ if(!isJiaogu(n)){ flag = false; alert("角谷定理验证失败"); } } alert("角谷定理验证"+(flag?"成功":"失败")); function isJiaogu(n){ while(n != 1){ if(n%2 == 0){ n/=2; }else{ n = n*3+1; } } return true; }
案例:验证10000以内哥德巴赫猜想成立
<script> /* * 假设系统有一个函数能帮我们判断大于6的偶数能否分解 * 设计该函数 * 功能:判断一个数是否能分解为两个素数之和 * 名称:canSplit * 输入参数:待分解的数 * 返回结果:true或false * */ var flag = true; for(var n = 6; n<10000; n+=2 ){ if(!canSplit(n)){ flag = false; break; } } alert("哥德巴赫猜想验证"+(flag?"成功":"失败"));
/* * 没法解决就继续分解 * 如果系统有一个能判断素数的函数,那么这个问题也简单 * 设计 * 功能:判断一个数是否为素数 * 名称:isPrime * 输入参数:待判断的数 * 输出结果:true或false * */ function canSplit(n){ for(var a=2; a<=n/2; a++){ if(isPrime(a) &&isPrime(n-a)){ return true; } } return false; } </script>
函数的本质:直观理解就是实现某个独立功能的代码段,或者说它就是一个数据加工的黑箱子
所谓“黑箱子”,就是我们只关心外面的东西,比方说它是干什么的,需要加入什么,可以得到什么结果,而不关心里面是怎么工作的。
忽略实现细节
3 参数传递
所谓参数传递,就是将实参的值传递给形参。通过调试可以确定形参在函数被调用之前是不存在的,当函数被调用的那一刻,实参被创建,并且把实参的值传递给形参。
参数传递有两种方式:值传递和引用传递。
值传递:
<script> var a = 5; increase(a); alert(a); function increase(x){ x++; } </script>
a的值并没有显示预期中的6,而显示的还是5.因为形参x和实参a是两个不同的变量,x的变化和a没有任何关系。
引用传递:
/*引用传递*/ var a = new Object(); a.value = 5; increase(a); alert(a.value); function increase(x){ x.value++; }
a.value没有被现实修改,但是a.value确实+1了,因为x就是a,或者说x是a的别名,专业一点就叫做引用。
常规类型的参数采用的是值传递,比如:Number、String、boolean
对象采用的是引用传递,Object
如果希望把参数从函数中带出来,但是函数的返回值只有一个。
4 变量作用域
局部变量:在函数内部定义的变量,这个变量只能够在函数的内部使用,在全局中不能够使用。比如在三国时期,袁术称帝后,只有袁术阵营的人才认为他是皇帝,他发布的命令只有在本阵营里面起作用。但是其他人不认为他是皇帝,他发布的命令没有作用
<script> function localVar(){ var a = 1; alert(a); } localVar(); </script>
全局变量:在函数外部定义的变量,这个变量可以在全局进行使用。比如汉朝的皇帝发布了命令,那么不管是袁绍还是曹操都要听这个命令。
<script> var a = 1; function allVar(){ alert(a); } allVar(); </script>
冲突处理原则:就近原则。---当在函数中定义了一个和全局变量名相同的变量,此时在函数中在定义前使用,那么这个变量还是函数中的变量,为undefined,不使用全局变量。
理解就近原则,而不是从上到下。
局部和全局同时定义了一个相同名字的变量时,如何在局部里面访问全局变量?------在局部中给变量加上window的前缀,就可以访问到全局的变量。
<script> var a = 1; function allVar(){ var a = 2; var a = 3; // alert(a); alert(window.a); } allVar(); </script>
在函数内部定义一个变量,如果没有加上var那么这个变量就会被认作全局变量。
<script> function localAllvar(){ a = 1; } function add(){ alert(a); } localAllvar(); add(); </script>