JS从0开始(四)函数

264 阅读5分钟

重点:什么是实参形参、实参求和、在函数内更改实参的值、
隐式添加return、递归

1.函数

数学里的函数:任意一个x的值 都会有一个确定的y与它对应 ; x:自变量; y:因变量
数学里的函数的值是确定的
而计算机里的函数(函数式编程) 的值是不确定的

  • 耦合:代码重复的东西大多了
  • 高内聚:开发的一个功能(模块)代码相关性强:紧密联系度强-->即高独立性-->即独立的完成一个任务
  • 低耦合:把重复的代码提取出来-->组成一个独立的功能体(模块)-->去完成一个特点的功能
    高内聚、低耦合:一个模块它有强的功能性、强的独立性,可以拿过去直接用
    高内聚、低耦合 --> 模块的单一责任制:一个功能的代码只管这一块
    解耦合:最好的方式就是函数,解耦合的方式都是基于函数的

2.最基本的函数写法:函数声明

为什么叫函数声明?因为用function来声明一个叫test的函数
基本格式:

function test(参数){ 
函数执行语句;
}

用:执行同样功能的语句,
var if(1>0){test();}
var if(2>0){test();}
var if(3>0){test();}

我们要完成的就是:当以上条件满足的时候分别去执行一个for循环输出0到9
直接拿过去用就行

function test(){
 for(var i=0;i<10;i++){
 console.log(i);
 }
}

函数的功能都是提前准备好了的,
各个功能的函数就相当于含有各种功能的软件
安装软件的过程相当于编写函数的过程

3.匿名函数表达式

var test = function() { 函数执行语句; }
当用表达式定义函数时,后边的函数是匿名函数(因为后面没有test, 这样的函数没有名字)
这样函数定义的方式叫做匿名函数表达式,也叫函数字面量
var a=[] ,[]就是一个数组字面量
var a={} ,{}就是一个对象字面量,还有数字类型、字符串类型字面量等等

 var test = function test1(){//声明了一个函数test1   将test1赋给test
          a=1;
          console.log(a);
         // test1();     test1可以在函数内部执行,但是会无限循环
      }
      test();
      test1(); /当上式test()函数执行的时候会默认忽略test1,即此句输出ReferenceError
}

test()函数执行的时候会默认忽略test1()

4.函数名的命名规则

和变量差不多:不能数字开头
可以含有数字 _ $
包含数字
小驼峰命名法
不能使用关键字、保留字等

5.函数的组成部分

function 函数名 参数(可不填) 、 返回值(可不填)如return后面括号内可不填

function test(){
var a=1,
    b=2;
console.log(a+b);
}
test();/之前function test()括号内没有参数 即里面固定的值 不能赋值

function test(a,b){ /形参
console.log(a+b);
}
test(12);/之前function test()括号内有参数; 即可以赋值; 此句test()传达的值1,2称之为实参

第二个函数中a,b不用时占位,形式上调用,称之为形参
而下面test括号内的1,2 实际上调用 ,称之为实参
形参是占位符,实参是给占位符赋值
或者说形参就是变量,实参就是给变量赋值
区别在函数内部声明变量,无法在函数调用时赋值

小细节:

function test(a,b,c){
console.log(a,b,c);
}
test(1,2); /不会报错 输出1, 2, undefined
/c的类别是undefined 

function test(a,b,c){
console.log(a+b+c);
}
test(1,2); /输出NaN    1 + 2+ undefined = 非数? 非数!

function test(a,b){
console.log(a,b);
}
test(1,23); /不会报错 输出12

总结:形参和实参数量可以不相等

6.实参与argument

在函数内部能知道有哪些实参吗?函数内部有个argument存储了实参

function test(a,b){
console.log(arguments); //输出argument数组  里面存了实参 1 2 3 
console.log(arguments.length);/输出3
}
test(1,2,3); 

面试知识点:实参求和

function sum(){
var a = 0;
for (var i=0;i<arguments.length;i++){ 
a = a + arguments[i]
}
console.log(a);
}
sum(1,2,3);

在函数内更改实参的值

  • 实参和形参不是同一个变量,他们在函数内部是映射关系 形参和实参中任何一个变,另一个都会变。但如果没有形参就没有映射关系
function test(a,b){
a=3;/形参 a重新赋值为3
console.log(argumens[0]); /输出3 表明形参变实参也会变
arguments[0] = 2 /对第一个变量重新赋值
console.log(a);/表明实参变形参也会变
}
test(1,2);     

/此例中argumens[0]和a = 3 不是一个东西; 形参a=3存在栈内存中 而argumens[0]的值存在堆内存中,然后栈内存中存地址
/形参和实参中任何一个变,另一个都会变

此例实用性:当用户填了个不合法的数时,自动更改它

  • 当实参里面没有这个值时:
function test(a,b){
b=3console.log(argumens[1]); //输出undefined  
/实参都没有b这个值,不能改变
}
test(1);

7.隐式添加return

1.每个函数最后一定是return,如果没写,js引擎会默认添加

2.如果写了return,那么return后面的语句是不会执行的(笔试细节):

function test(){
console.log('1');
return;
console.log('2');/不输出     /return下所有语句是不会被执行的 甚至是 returnreturn("3"); /不输出
                            
}

即出现return就直接结束整个循环

8.作用域

每个function都有自己独立的作用域
作用域:已声明的变量和函数可访问的范围

9.总结

函数式编程到底是什么? 其实就是一个固定的功能或者是程序段 被封装的过程。
实现一个固定的功能或者是程序需要什么? 在这个封装体中需要一个入口和一个出口,入口就是参数,出口就是返回

10.实战、递归

(1)定义一个函数,从wp接受一个饮料的名称,函数返回对应的价格

 function drinks() {
            var a = window.prompt('请输入饮料名称');
            if (a == '可乐') {
                console.log('cola');
            } else if (a == '雪碧') {
                console.log('sprite');
            } else { console.log('暂无该饮料'); }
        }
        drinks();

(2)定义一个函数,从wp接受第一个数,接收一个运算符号(+ - * / %),接受第二个数,利用这个函数做运算,并返回运算结果

        var a = Number(window.prompt('请输入第一个数'));
        var b = window.prompt('请输入运算符');
        var c = Number(window.prompt('请输入第二个数'));
        function operation(a, b, c) {
            if(b == "+"){
            console.log(a+c);
            }else if(b == "-"){
                console.log(a-c);
            }else if(b == "/"){
                console.log(a/c);
            }else if(b == '*'){
                console.log(a*c);
            }else{
                console.log(a%c);
            }
        }
        operation(a, b, c);

(3)定义一个函数,从wp接收一个n,算出n的阶乘,不能用for循环

/利用递归:
  var a = Number(window.prompt('请输入一个数'));
        function Factorial(a) {
          if(a == 1){
              return 1;
          }
          return a * Factorial(a - 1);
        }
        console.log(Factorial(a));

这题我本来想先用for循环解决,却遇到了一个问题:

       var a = Number(window.prompt('请输入一个数'));
            var sum = 1; //全局变量 
 
           function Factorial(a){
               for(var i=1;i<= a;i++){
                   //var  sum = sum * i;//返回NaN //因为我在这里重新声明(var)了sum 导致它不能访问外面的sum,而此时后面的sum没赋值,所以输出非数NaN
                   
                /解决办法 就是去掉var
                   sum = sum * i  //这样才是对的
                   console.log(sum);             
               }
           }
           console.log(sum);
           Factorial(a);

(4)定义一个函数,从wp 接收一个n, 算出斐波那契数列的第n位,不能用for循环

   var n = window.prompt("输入n");
      function fb(n){
          if(n <= 2){
              return 1;
          }
          if(n<=0){
              return 0;
          }
       return  fb(n-1) + fb(n - 2);  /递归里面一般都用return
      }
      console.log(fb(n));

(5)递归

实战总结:递归总是走到出口(返回)的时候,再向上一步一步的返回结果;
递归就是函数自己调用自己,慎用,用for循环更好
递归的解决方法:1.找到计算的规律 2.找到一个递归的出口,让函数结束掉