函数
1、函数的概念
为什么需要函数?
那么首先我们来看一下输出100以内所有素数问题的解决方案
案例1:循环的嵌套
var n = Number(prompt("请输入一个自然数:"));
var fount = false;//找到因子的标记
for(var i=2; i<=n/2; i++){
if(n%i == 0){
fount = true;
break;//找到提前结束
}
}
alert(fount?"不是素数":"是素数");
案例1的这种解决方案比较复杂,阅读也比较困难,需要比较高超的技术才行。
案例2:应用函数
<script>
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(m%i==0){
return false;
}
}
return true;
}
</script>
案例2这种解决方案是将一个比较复杂的问题分解为两个较为简单的问题去解决,是用“量”去克服“难”和“大”的问题。
这种解决方案给我们提供了一个解决规模大、难度高的解题思路:就是将它分解为多个规模相对较小、难度相对较低的问题去解决,如果分解后的问题还是规模大和难度高,就可以按照这个思路一直分解下去,直到分解后的问题足够小和简单。归纳起来就是“大事化小”。
2、定义与调用
函数的定义:function isPrime(n){
······
}
function 定义了函数的关键字;
isPrime 是函数的名字,和变量名一样的命名规则和原则;
n 形式参数(形参),还有一个实际参数:函数调用:isPrime(12),这个 12 就是实际参数(实参)。
函数头部:function这一行(是比较重要的。体现的是函数的设计)
函数体:function后面大括号里面是代码(体现的是函数的实现过程)
现在用案例来表示。
案例1:验证100以内的数字都符合角谷定理
助手:
功能:判断一个给定的数是否符合角谷定理
名称:isJiaogu()
输入参数:待判断的数
输出结果:true/false
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;//函数体
}
案例2:验证10000以内哥德巴赫猜想成立
/*
* 假设系统有一个函数能帮我们判断大于6的偶数能否分解的素数
* 设计一下该函数
* 功能:判断一个数能够分解为两个素数之和
函数名称:canSpilt
输入参数:待分解的数
返回结果:true/false
* */
var flag = true;
for(var n=6; n<=10000; n+=2){
if(!canSpilt(n)){
flag = false;
}
}
alert("哥德巴赫猜想验证" + (flag?"成功":"失败"));
/*
* 那么如何实现这个函数呢,好像还是不简单,那就继续分解
* 如果系统有一个能判断素数的函数,那这个问题也简单
* 设计:
* 功能:判断一个数是否为素数
* 名称:isPrime()
* 输入参数:待判断的数
* 输出结果:true/false
* */
function canSpilt(n){
for(var a=2; a<=n/2; a++){
if(siPrime(a) && isPrime(n-a)){
return true;
}
}
alert("哥德巴赫猜想" + (flag?"成功":"失败"));
}
这个案例体现了“大事化小”的特性。在这个复杂的程序中,先是把一个程序分解为两步,然后再做,要是还是有点复杂,就再一次的分解,直到简单可以做出来。
(自己的理解:先假设一个函数可以让这个程序的判断执行,然后根据这个题目的性质进行设计,然后进行判断;实际上这个函数是不存在的,那么我们就要用function实现这个函数)
函数的本质:(直观理解)就是实现某个独立功能的代码段,或者说它就是一个数据加工的黑箱子。
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、变量的作用域
局部变量:在函数内部定义的变量,这个变量只能够在函数的内部使用,在全局中不能够使用。
function localVar(){
var a= 1;
alert(a);在这里面可以输出1
}
localVar();
alert(a);这里就没有输出
在函数中内部定义一个变量,如果没有加上var,那么这个变量被认作为全局变量
function localAllVar(){
a = 1;
}
function test(){
alert(a);
}
localAllVar();
test();
全局变量:在函数外部定义的变量,这个变量可以在全局进行使用。
var a = 1;
function allVar(){
alert(a);
}
allVar();
冲突处理原则:就近原则。
var a = 1;
function doubleVar(){
var a= 2;
var a= 3;
alert(a);
}
doubleVar();
当函数中定义了一个和全局变量名相同的变量,此时在函数中在定义以前使用,那么这个变量还是函数中的变量,为undefined,不使用全局变量。
要理解就近原则,而不是从上到下。
var a= 1;
function test(){
alert(a);
var a =2;
alert(a);
}
test();
alert(a);
在局部变量中,如果没有声明(var)就使用,它会默认为是全局变量。
局部和全局同时定义了一个相同名字的变量是如何在局部里面访问全局变量?在局部中给变量叫上window的前缀,就可以访问到全局的变量。
var a = 1;
function doubleVar(){
var a= 2;
var a= 3;
// alert(a);
alert(window.a);//相当于给a加了个前缀。更容易分辨
}
doubleVar();