JavaScript笔记(函数)


函数

一、函数基础

1、函数的定义

将特定的代码片段,抽取成为独立运行的实例,就是函数;

函数好处:代码复用、方便维护、便于理解、使用简单;

2、函数的创建

  • 在当前函数所在script标签创建时,优先将该函数存储在堆中,并且函数名存储在栈中

  • 当前这个代码所在的script标签的上面的script的标签中任意函数和全局变量都是可以被调用的

  • 但是当前代码所在的script标签下面的script的标签中函数和全局变量是不可以调用的

  • 函数名:驼峰式命名法,首字母一般都是小写,如果该函数是构造函数,函数名首字母需要大写

  • 函数后面的()是执行当前函数需要传入参数内容

  • {}里面是函数的语句块,当执行函数时,该语句的内容就会被执行

命名函数

function fn(a,b){     //fn即为函数名
    console.log(a+b);   //调用函数时执行此语句块
}
fn(10,20);        //调用函数并传入参数

匿名函数

//代码运行到定义匿名函数后才可以调用该匿名函数
var fn=function(){
    console.log(arguments.callee);//arguments.callee 就是函数本身
}

自执行函数

(function(){
    //自己执行自己,也是匿名函数
})();

构造函数定义函数

var fn=new Function("a","b","console.log(a+b)");
fn(3,5);

二、作用域与作用域链

1、作用域

作用域就是变量作用的范围,分为全局作用域和局部作用域

作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。

某个执行环境中所有的代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出时,如关闭浏览器或网页,才会被销毁)

var a=10;
//函数外为全局作用域,函数外var定义的变量是全局变量
function fn(a){   //参数是局部变量
    //函数内为局部作用域   
    var a=20;  //函数里var定义为局部变量
    console.log(a);//20 优先局部变量,没有再去外面找全部变量
};
console.log(a);//10 无法调用函数内局部变量,打印全局变量10

2、作用域链

作用域链就是执行代码时,会首先在自身函数内找变量,找不到再去外部找,再找不到就去window环境找,这个过程就是作用域链

var a=10;
function fn(){
    function fn1(){
        console.log(a);//10 执行此代码输出a,首先在函数内fn1找变量,找不                到,然后去外部fn函数找,找不到去全部window找,这时找到a=10;                这个过程就是作用域链
    }
}

当代码在一个环境中执行时,会创建变量对象的一个作用域链(作用域形成的链条)

  • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象

  • 作用域链中的下一个对象来自于外部环境,而在下一个变量对象则来自下一个外部环境,一直到全局执行环境

  • 全局执行环境的变量对象始终都是作用域链上的最后一个对象

内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境的任何变量和函数。

三、参数、return

function fn(a,b){
            // a,b是参数,参数可以是任意内容,如果没有对应填入,该参数就是undefined
            // 执行函数时,填入的参数就相当于给参数赋值
            // js是一个弱类型语言,因此,参数不能强制约定类型
            // ES5中不能设置参数的默认值
            console.log(a+b);
        }
fn(3);执行函数时填入值与函数参数顺序是一一对应关系
function fn(obj){
              // 相当于给obj赋值一个o,obj和o的引用地址相同
              // 当修改obj的属性时,全局的o属性也会被修改
              obj.a=10; //此时o对象中的属性也变成10
          }
  
          var o={a:1};
          fn(o);

arguments参数集

  • 它只能出现在函数内

  • 它用来接受动态的实参

  • 它是一个伪数组,原型是对象Object

  • 可以通过下标[index]方式取值

function getValue(){
    console.log(arguments);//arguments就是传进来的4个参数组成的集合
    //当参数不确定时,就可以不设置参数,使用arguments接收
    //arguments.callee就是函数自己也就是getValue函数
    //匿名函数调用自己常用到arguments.callee
    //arguments.callee.caller是调用此函数的函数,也就是fn1函数
}
getValue(1,2,3,4);
function fn1(){
    getValue();
}
  • function getValue(){
    console.log(arguments);//arguments就是传进来的4个参数组成的集合
       //当参数不确定时,就可以不设置参数,使用arguments接收
       //arguments.callee就是函数自己也就是getValue函数
       //匿名函数调用自己常用到arguments.callee
       //arguments.callee.caller是调用此函数的函数,也就是fn1函数
    }
    getValue(1,2,3,4);
    function fn1(){
       getValue();
    }

    return返回值

    • 可以允许函数返回一个值,仅一个,也可以返回对象,数组,函数,函数体等

    • 如果在函数最后一句没有返回值的情况下,尽量不要写return

    • 函数没有return则返回undefined

return break continue区别

return 只能使用在函数中,函数外不能使用,无视任何内容直接跳出函数

break 用于switch或者循环语句中,跳出当前循环或者锚点循环,或者switch语句,循环外的语句继续执行

continue 仅跳出当前次循环,继续下一次循环,只能用于循环语句中

//生成rgba随机颜色函数,带透明度
function randomColor(alpha){
            // 如果没有参数,随机
            alpha=alpha==undefined ? Math.random().toFixed(2) : alpha;
            // 传入的参数转换为数值
            alpha=Number(alpha);
            // 如果传入的参数是非数值,就让透明度为1
            if(isNaN(alpha))alpha=1;
            var color="rgba(";
            for(var i=0;i<3;i++){
                color+=parseInt(Math.random()*256)+",";
            }
            color+=alpha+")";
            return color;
        }

四、回调函数,递归

递归或者回调的次数过多,没有阻止递归或者回调的条件,会造成堆栈溢出

1、回调函数

function fn1(f){
    f()//这里f函数称为回调的函数
}
function fn2(){
    console.log("aaa");
}
fn1(fn2);

利用回调函数模拟一个简单红绿灯(控制台输出 红灯,绿灯这样)

function getLight(first,second,third){
            first(second,third);
        }

        function getRedLight(fn,fn1){
           var f=arguments.callee;
            var ids=setTimeout(function(){
                console.log("红灯");
                clearTimeout(ids);
                fn(fn1,f);
            },1000);
        }
        function getYellowLight(fn,fn1){
            var f=arguments.callee;
            var ids=setTimeout(function(){
                console.log("黄灯");
                clearTimeout(ids);
                fn(fn1,f);
            },1000);
        }
        function getGreenLight(fn,fn1){
            var f=arguments.callee;
            var ids=setTimeout(function(){
                console.log("绿灯");
                clearTimeout(ids);
                fn(fn1,f);
            },1000);
        }
        getLight(getGreenLight,getYellowLight,getRedLight);
//可以更改函数的回调顺序改变输出结果的顺序

2、递归

函数不断自己调用自己,这样就叫做函数的递归;

递归的本质是函数每次自执行都会复制出一个一样的函数执行,每个复制的函数都有自己的作用域,如没有递归结束,则函数下面语句不执行,知道递归结束后才执行后面语句

 var i=0;
 fn();
function fn(){
   i++;
    // console.log(i);
   if(i<4) fn(); //这里就是再递归,满足条件继续执行自己
   console.log(i);//注意此时会输出四次i=4;因为只有在上面递归完后,才能执行此语句
 } 

function fn(n){
   if(!n) n=1;
   n++;//2
   if(n<5)  fn1(n);//挂起不会往下执行
   return n;//2因为第一次进来n=1,n++之后为2,而递归是复制出一个函数执行,这里是把n作为参数带进去,那么n就是每个复制的函数的局部变量,都只能在自身函数内部调用,此时的fn函数也只能调用到自己的局部变量,也就是n=2;
}
fn();//函数运行完之后,局部变量会被销毁

function fn(n){
   if(!n) n=1;
   n++;//2
   if(n<5) return fn1(n);//挂起不会往下执行,这里使用return把每次复制函数的结果返回给到上一个复制的函数,就会把变量n一步一步向上返回,直到返回给原函数,所以此时return  n 会输出5
   return n; //5

 

原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/272656.html

(0)
上一篇 2022年7月9日
下一篇 2022年7月9日

相关推荐

发表回复

登录后才能评论