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