6函数
6.1函数的概念
大事化小,将复杂的问题简单化
如何大事化小呢?通过函数
为什么需要有函数?
首先看一下输出100以内所有素数的解决方案
方案一:循环嵌套
var n =Number(prompt("请输入一个自然数"));
var m = Math.ceil(Math.sqrt(n));//根据数学相关定理,判断范围可缩小至[2,sqrt(n)]
var found = false;//找到因子的标志
for (var i=2; i<=m; i++){
if(n%i == 0){
found = true ;
break;//找到则提前结束
}
}
alert(found?"不是素数":"是素数");
这种解决方案程序比较复杂,阅读比较困难,需要比较高超的技术
方案二:函数
for(var n=2; n<=100;n++){
if(isPrime(n)){
document.write(n+"<br>");
}
}
function isPrime( n){
var m = Math.ceil(Math.sqrt(n));//根据数学相关定理,判断范围可缩小至[2,sqrt(n)]
// var found = false;//找到因子的标志
for (var i=2; i<=m; i++){
if(n%i == 0){
return false;
}
}
return true;
}
这个方案将一个比较复杂的问题分解为两个较为简单的问题去解决,是用“量”去克服“难”和“大”的问题。也就是“大事化小”。
这样给我们提供了一个解决规模大、难度高的问题的解决思路:它分解为多个规模相对较小,难度相对较低的问题去解决,如果分解后的问题,依然规模大、难度高,可以按着这个思路一直分解下去,知道问题分解的问题足够小、简单。归纳起来就是“大事化小”
6.2定义与调用
函数是什么,怎么用
定义:function isPrime(n){
...........................
}
function 定义函数的关键字
isPrime是函数的名字,和变量名一样的命名规则和原则
n 形式参数(形参)
isPrime(12),12就是实际参数(实参)
案例:验证100以内的数都符合角股定理
函数头部:体现的是函数的设计
函数体:体现的是函数的实现过程
设计比实现更重要
案例:验证10000以内哥德巴赫猜想成立
对于这个问题我们首先要清楚问题的大概思路,大事化小来看
首先判断一个大于6的数能否分解(分解函数)
其次判断分解的数是否是素数
最后判断什么是素数(判断素数函数)
总的来说问题在一步步化小
对于函数来说三要素必不可少
函数名、参数、结果
/*
假设系统有一个函数能够帮我们判断大于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;
}
function isPrime(n){
var m=Math.sqrt(n);
for(var i=2;i<=m;i++){
if(n%i ==0){
return false;
}
}
return true;
}
函数的本质:直观理解就是实现某个独立功能的代码段,或者说它就是一个数据加工的黑箱子
输入参数→ 函数名 →输出结果
所谓“黑箱子”,就是我们只关心箱子外面的东西,比方说他是干什么的,需要输入什么东西,可以得到什么结果,而不关心里面是怎么工作的
忽略实现的细节
6.3参数传递
所谓参数传递,就是将实参的值传递给形参。通过调试可以确定形参在函数之前是不存在的,当函数被调用的那一刻,实参被创建,并且把实参传递给形参
参数传递有两种:值传递和引用传递
var a =5;
increase(a);
alert(a);
function increase(x){
x++;
}
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
如果希望把参数从函数中带出来,但是函数的返回值只有一个
6.4变量作用域
局部变量:在函数内部定义的变量,这个变量只能在函数内部使用,在全局中不能够使用。比如三国时期,袁术称帝后,只有袁术阵营的人才认为他是皇帝,他发布的命令只有在本阵营里面起作用,但是其他人不认为他是皇帝,他发布的命令没有作用。
function doubleVar(){
var a =1;
alert(a);
}
doubleVar()
全局变量:在函数外部定义的变量,这个变量可以在全局进行使用,比如汉朝皇帝发布了命令,那么不管是袁绍还是曹操都要听这个命令
var a = 1;
function doubleVar(){
var a =2;
alert(a);
alert(window.a)
}
冲突处理原则:就近原则
当在函数中定义了一个全局变量名相同的变量,此时在函数中在定义前使用,那么这个变量还是函数中的变量,为underfind,不使用全局变量。
要理解就近原则而不是从上到下
如果在函数内部的局部变量中没有申明(var)变量,那么他就变成了全局变量
所以使用时一定到要使用申明变量
function localAllVar(){
a = 1;
}
function test(){
alert(a)
}
localAllVar();
test();
局部和全局同时定义了一个相同的名字的变量时如何在局部变量里面访问全局变量?
在局部变量中给代码加上window的前缀,就可以访问到全局变量了
var a = 1;
function doubleVar(){
var a =2;
var a =3;
//alert(a);
alert(window.a)
}
doubleVar()