函数

函数的意义在于封装:把实现某一个功能的代码封装在一起,后期在想实现这个功能,只需要执行函数即可,不需要重新编写这些代码了。
“低耦合、高内聚”:减少代码的冗余,提高代码使用率。

1.创建函数

function 函数名(形参1,…){
//=>函数体:实现具体功能的代码
}*

2.执行函数:

让函数执行,从而实现具体的功能

函数名(实参1,…);
函数名(实参1,…);

  1. // 1.创建函数
  2. function func() {
  3. console.log('我会玩函数了!');
  4. }
  5. // 2.执行函数
  6. func();
  7. func();

形参和实参

形参:生产一个函数,想要实现一些功能,但是实现功能,需要的原材料不确定,需要用户执行它的时候给我,我才知道,此时我们就提供入口 => 形参(变量)

实参:执行函数的时候,给指定的入口(形参变量)传递的具体值(值)

  1. function sum(x, y) {
  2. // 创建函数的时候,并不知道要求哪两个数字的和,此时可以定义形参变量
  3. // =>x和y就是形参变量
  4. let total = x + y;
  5. console.log(total);
  6. }
  7. sum(10, 20); //=>x=10 y=20是实参(给形参变量传递的具体值)
  8. sum(1, 10); //=>x=1 y=10
  9. sum(10); //=>x=10 y=undefined 定义了形参,但是执行的时候不给传递实参,则形参默认值undefined

return 返回值

return是函数的返回值机制【出口】 return后面放的是”值”
函数里面return 多少,这个函数的返回值就是多少,如果没有返回值,就是undefined;
如果形参数量为两个 实参传递为1个 则不传递的那个值为undefined
return会打断函数执行

  1. function sum(x, y) {
  2. return x + y;
  3. console.log(123);
  4. }
  5. sum(1,2);//返回值为3,但是不会输出123

arguments实参合集

arguments函数内置的实参集合:不管我们设置与否形参,再或者是否传递了实参
ARGUMENTS始终都会存在(ES6箭头函数中没有ARGUMENTS
arguments是一个类数组集合(类似数组,但是不是数组)
根据索引记录了每一个传递进来的实参信息(和是否定义形参变量没有关系,ARGUMENTS中包含了所有传递进来的实参信息)
length属性代表传递实参的个数
image.png

求两个数的之和

函数执行的时候:

  • 形参赋值
  • 变量提升
  • 代码从上往下执行

无返回值:

  1. /* 求两个数的和 */
  2. /* function sum(n,m){
  3. //n/m:形参[变量] 用来接收后期执行时候,传递进来的实参值
  4. //需求:如果n/m 的值是非有有效数字,我们让其为0
  5. n=+n; //默认转Number数字
  6. m=+m;
  7. if(isNaN(n)){//只有一行的时候可以把大括号省略 判断n是否是有效数字
  8. n=0;
  9. };
  10. isNaN(m)?m=0:null;
  11. var total=n+m;
  12. console.log(total);
  13. }
  14. sum(10,"20");//n=10 m=20
  15. sum(10);
  16. // n=10 m=undefined 设置形参 但是不传递实参,默认值是undefined */

有返回值

function sum(n,m){
    n=+n;
    m=+m;
    isNaN(n)?n=0:null;
    isNaN(m)?m=0:null;
    var total=n+m;
    // console.log(total);//里面用total肯定可以 因为是自己家的【大括号/函数体相当于单独的一家人】
    //return是函数的返回值机制【出口】 return后面放的是"值",所以此处“return total;->return 30;”
    //  +如果不写return ,我们默认返回值是undefined
    //  +在函数体中遇到return 直接返回结果即可,后面的代码则不再执行了
    return total; //私有变量
}
// 外面叫做total,和里面的不是一个变量,没啥直接的关系
// +sum();把函数执行 代表的是函数执行后的返回值[RETURN]
// +sum:变量/函数名,代表的创建函数本身[堆内存地址]
var total=sum(10,"20");
console.log(total);

不知道要传递多少个参数,求所有数之和

【arguments】:内置实参集合 【包含了传递进来的所有实参值 “类数组集合”】

function total(){
        console.log(arguments)
    }
total(3,4,5,6)

利用arguments求和

 function total(){
       var res=null;
       for(var i=0;i<arguments.length;i++){
         res+=arguments[i];
       } 
       return res;
    }
   var res= total(3,4,5,6);
   console.log(res);

求所有数之和(考虑非有效字符)

function total(){
     var res=null;
     for(var i=0;i<arguments.length;i++){
        //var item=Number(arguments[i]);
        var item= +arguments[i]; 
        if(isNaN(item)){
            item=0;
        }
        res=res+item;
     }

     return res;

}

var result1=total("1",2,"16px",3);
console.log(result1);

[升级版2]
如 需求:任意数求和:不论传递多少实参值,都可以求和
+传递的是非有效数字,则按照0处理 或者不是处理
+传递的是字符串,需要先变为数字在求和,避免字符串拼接

function sum(){
    //arguments:内置实参集合 【包含了传递进来的所有实参值 “类数组集合”】
    // console.log(arguments);
    var total=0;
    for(var i=0;i<arguments.length;i++){
        // 获取当前的循环中的集合的这一项,并且把其变为数字
        var item= +arguments[i];
        // 如果item不是一个有效数字,则结束当前这轮循环[不求和了] 继续下一轮即可
        if(isNaN(item)) continue;
        total+=item;
    }
    return total;
}
console.log(sum(10,20,'30','AA',40));
console.log(sum(10,20,30));
console.log(sum(10));
console.log(sum());

函数创建的具体过程

1.创建函数
@1 开辟了一个堆内存空间[16进制的内存地址]
@2 向空间中存储内容
作用域
函数体重的代码字符串
键值对
name:函数名
length形参个数
@3 把地址放在栈中,供变量调用

注:只创建函数 但是不执行,函数没有任何意义,因为它只是开了堆内存 存储一堆破字符串而已
image.png

函数执行的具体过程

  1. 创建一个全新的执行上下文,把执行上下文压缩到栈内存中去执行(⇒进栈执行)
  2. 在这个上下文中,也存在一个变量对象,用来存储当前上下文代码中所创建的变量
  3. 代码执行
  4. 当上下文中的代码都执行完后,如果该上下文中的信息没有被外面占用的情况,则执行完出栈(释放内存)

如果,外面想用当前上下文中的一些私有信息,则需要函数提供对应的出口,把信息提供给外面使用,而这个出口在JS函数中被称为“返回值 return”

微信图片_20210414192422.png

匿名函数

没有名字的函数
• 实名函数:就是有名字的函数
• 匿名函数:没有名字的函数,比较常见的有
• 函数表达式:把一个匿名函数赋值给一个变量或者事件
• 自执行函数:创建和执行一起完成。(()、+、~、!)

1.匿名函数——-【事件绑定】

var btn=document.querySelector("#btn");
btn.οnclick=function(){
  // alert("document");
}

2匿名函数——-【定时器】

//定时器
//setTimeout(函数体,时间(单位:毫秒)) 多少毫秒之后执行(只执行一次)
//setInerval(函数体,时间(单位:毫秒)) 每隔多少毫秒一次
//清定时器用clearInterval(timer);
setTimeout(function(){
  console.log("只执行一次呀");
},1000);

var timer=setInterval(function(){
  console.log("每隔两秒执行一次");
},2000);

//10秒停止 清空定时器
setTimeout(function(){
  clearInterval(timer);
},10000);

3. 匿名函数——-【匿名函数具名化】

var fn = function () {};
fn();

4. 匿名函数——-【作为对象中的一个属性】

var obj={
  name:"dddd",
  say:function(){
    alert(this.name);
  }
}
obj.say();

5.自执行函数

一个函数在定义后立即执行
创建和执行都一起完成的[用小括号包起来,或者在前面加入“~/+/!” 等都是为了保证语法不出错]

var a = (function (i) {
    console.log(123);
    //可以拿到返回值
    return 1;
})(10);
var b = ~ function () {
    console.log(123);
      //拿不到返回值
    return 2;
}();
console.log(a, b);//=>1 -3


/* +function(){}();
~function(){}();
!function(){}(); */

微信图片_20210502175520.png

6.回调函数callback

把函数体作为参数,传到另一个函数中去执行
什么情况用:
大多数是内置方法需要自己的某项特殊功能的时候 如Sort forEach

function fn(){
  alert("setTimeout");
}
setTimeout(fn, 1000);

//回调函数例子
function fn(callbak){
    // callbak:传递进来的匿名函数
    callbak();
}
fn(function(){

})

forEach传递进来的参数也叫做回调函数

传递进的参数也叫做匿名函数 回调函数

/* 
    把数组的forEach方法执行,传递一个匿名函数@A[回调函数] 那么在forEach内部,就可以获取到这个@A
    接下来forEach内部干了点事情,循环数组中的每一项,每循环一次都把@A 执行一次【数组有多少项 回调函数@A就要被执行多次】
    并且把每次循环得到的当前项和当前项索引,传递给@A的item/index...
    ->@A:function(item,index)
*/
var arr=[1,11,2,34,24];
arr.forEach(function(item,index){
    //item当前项
    //index 当前项的索引
})

箭头函数

与普通函数的区别:
1.没有arguments
2.没有自己的this,this是执行上下文的this

let fn = () => {};
//如果箭头函数只有一个参数,可省略小括号,只写形参
let fn2 = str => {};
//如果大括号内,除了return没有多余语句,可省略大括号和return
let fn3 = num => num + 1;
// 写全=>let fn3 = (num) => {return num + 1};
//箭头函数和普通函数的区别
// 1、箭头函数没有arguments;arguments只能在普通函数用;箭头函数想要拿到所有的实参需要用...展开运算符
// 2. this 不一样

var fn5=(...arg)=>{
  //console.log(arguments); //箭头函数练习.html:37 Uncaught ReferenceError: arguments is not defined
  console.log(arg);
}
fn5(2,3,5);


/* this不一样 */
var btn=document.getElementById("btn");
btn.onclick=function(){
  console.log(this);
};

//箭头函数
btn.onclick=()=>{
  console.log(this);
}


递归

函数自己调用自己,叫做递归

//求1-100的累加结果
function sum(n) {
  //边界:停止条件
  if(n<0) {
      return 0
  }
    return n+=sum(n-1);
}
sum(100)

递归.png