JS中的函数认识和作用域及域解析

web.jpeg

函数


函数声明
  • 函数:一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
  • 格式如下:

function 函数名字( 参数1,参数2){ 执行语句 }
调用:函数名称()

  • 命名规范:只能是字母、数字、下划线、美元符号,不能以数字开头

    <script type="text/javascript">
        
        //调用函数
        sayHello();
        //声明函数
        function sayHello() {

            console.log("您好。欢迎您")
        }


    </script>

函数表达式
  • 除了 function 声明函数意外,还可以使用变量赋值的写法命名函数,我们称为函数表达式(其本质就是将一个匿名函数 赋值给一个变量)
  • 在语句结束的时候必须 要有 分号 ;
<script type="text/javascript">

    //匿名函数
    function () {
    console.log("这是一个匿名函数");
    }
       
//赋值给变量--> 函数表达式
        var fuc = function (a) {

            console.log(a)
        };

        fuc("哈哈")
    </script>

函数的参数 和 返回值


参数
  • arguments是存储了函数传送过来实参 ,是一个伪数组;
  • Javascript在创建函数的同时,会在函数内部创建一个arguments对象实例.
  • arguments对象只有函数开始时才可用。函数的 arguments 对象并不是一个数组,访问单个参数的方式与访问数组元素的方式相同
  • arguments对象的长度是由实参个数而不是形参个数决定的
 <script type="text/javascript">

        sayHello("你是?","哈哈");

        function sayHello(a,b) {
       console.log(arguments.length);
            console.log(a + b)
        }

    </script>

//打印结果:
2
你是?哈哈

  • 函数作为参数,这个参数(函数)可以叫做回调函数
<script>
    //
    function f1(fn){
        fn();
    }

    function f2(){
        console.log("开始使用");
    }

    // f2是函数的代码
    f1(f2);

//打印结果: 开始使用

  var arr = [10,200,30,110,40,20,50,200];
      //函数作为参数
        arr.sort(function(obj1,obj2){
            if(obj1 > obj2) {
                return 1;
            } else if (obj1 == obj2){
                return 0;
            } else {
                return -1;
            }

        });

        console.log(arr); // [10, 20, 30, 40, 50, 110, 200, 200]


</script>
返回值
      //返回值
      var c  = sum(10,20);
        console.log(c)
      //打印结果: 30
      //定义函数
        function sum(num1,num2) {

            return num1 + num2
        }
  • 函数可以作为返回值 返回
 //函数作为返回值 

    function f3(){

        return function(){
            console.log("回一个函数");
        }
    }

    let fs = f3(); //此时fs是函数代码
    fs();
//执行结果数输入: 回一个函数
  • 函数作为返回值和参数的例子
   //文件对象构造函数
    function File(name, size, time) {
        this.name = name;
        this.size = size;
        this.time = time;
    }
    //文件对象
    var f1 = new File("jack.avi", "400M", "1997-12-12");
    var f2 = new File("tom.avi", "200M", "2000-12-12");
    var f3 = new File("haungfeihong.avi", "800M", "2017-12-12");

    //数组
    var arr = [f1, f2, f3];
    //文件排序 对象是不能让你更排序的 只有里面的属性才可以
    function fileSort(attr) {
        //函数作为返回值
        return function (obj1, obj2) {
            if (obj1[attr] > obj2[attr]) {
                return 1;
            } else if (obj1[attr] == obj2[attr]) {
                return 0;
            } else {
                return -1;
            }
        }
    }


    //排序 函数作为参数  fileSort 返回的是一个函数
    arr.sort(fileSort("size"));
    console.log(arr);

作用域(变量的使用范围)

  • 全局变量:声明的变量是使用var声明的,那么这个变量就是全局变量,全局变量可以在页面的任何位置使用

    • 除了函数以外,其他的任何位置定义的变量都是全局变量
  • 全局作用域:全局变量的使用范围

  • 局部变量:在函数内部定义的变量,是局部变量,外面不能使用

  • 局部作用域:局部变量的使用范围

  • 隐式全局变量:声明的变量没有var,就叫隐式全局变量

function fn () {
    //隐式全局变量
    num = 100;
};
    fn(); //调用
    console.log(num);

作用域链(搜索机制:内部开始搜索,找不到,在去外部搜索,就近原则)

作用域链.jpg
  • 如上图一样,在调用f1函数时, 输入函数 log在寻找num的变量时,是从函数内部,也是上3级作用开始 向外部寻找,如果在内部或者3级作用域找到num就输入,如果3及作用域没有,就向上一个作用域寻找,一直把所有的作用域找完,没有就报错。

预解析(浏览器解析代码前,把变量的声明和函数的声明提升到作用域的最上面)


js的执行过程是 1.先对代码编译 2.预解析 3.执行代码

变量名的提升

<script>
 console.log(num);
 var num = 10;

//打印结果: undefined

</script>
  • 案例说明,变量在声明的时候,变量明提升到头部了
var num;
console.log(num);
num = 10;
//打印结果: undefined
函数名的提升
  • JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部
<script type="text/javascript">
    f1();
    function f1 () {
        console.log("看看");
    }
</script>

模拟预解析

//模拟提升
//与解析 提升函数代码块
function f1 () {
        console.log("看看");
    }
//执行
f1();
  • 预解析会分段(多对的script标签之间函数重名没有影响)
// script标签1
<script type="text/javascript">
    f1();
    function f1 () {
        console.log("看看");
    }

//模拟提升
//与解析 提升函数代码块
function f1 () {
        console.log("看看");
    }
//执行
f1();

</script>

// script标签2
<script type="text/javascript">
    
    f1();
    function f1 () {
        console.log("这还是");
    }
    
    
</script>
  • 注意:如果采用赋值语句定义函数,变量提升后,在运行的时候JavaScript 就会报错(函数表达式)
//变量提升  没有问题
f();
function f() {}



// 变量提升 有问题
f1();
var f1 = function (){};
//  TypeError: undefined is not a function

//解释
//预解析
var f1;
f1(); //报错
f1= function (){};


  • 在函数体内部,声明变量,会把该声明提升到函数体的最顶端。 只提升变量声明,不赋值。
<script type="text/javascript">


        
        var num = 10;
        func();

        function  func() {

            console.log(num);
            var num = 20;
        }


    </script>
//结果是: undefined
相当于这样的代码

 <script type="text/javascript">

        var num = 10;

        func();

        function  func() {
          //变量提升到头部
            var num;
        //log函数会在 这个作用域里面寻找num, 作用域链
            console.log(num);
            num = 20;
        }
    </script>

  • 注意:全局隐式函数
    f1();
    
    console.log(c);//9
    console.log(b);//9
    console.log(a); //报错
    
    function f1 () {
        var a = b = c = 9; //b,c是隐式函数  全局
        console.log(a); // 9
        console.log(b); //9
        console.log(c);//9
        
    }



//预解析 函数代码块 提升

function f1 () {
     //a是 函数体内的局部变量
// 预解析 提升a 在函数体的作用域内
        var a;
               a = 9;
//解释 函数f1内部的变量  只有 a是var声明的 局部变量 b和c是隐式全局变量
                b = 9;
                c = 9;
        console.log(a); // 9
        console.log(b); //9
        console.log(c);//9
        
    }

//调用函数
f1()

     console.log(c);//9
    console.log(b);//9
    console.log(a); //报错

注意

  1. 与解析阶段会对var 声明的变量 和 function 声明的代码块进行声明 提升,提升到当前作用域的顶端
    2.变量和变量同名 后面会覆盖前面的
    3.函数和函数同名 后面的会覆盖前面的
    4.变量和函数同名 只提升函数的声明不提升和函数同名的变量
 function test(a) {

        console.log(a);

        var a = 10;

        console.log(a);

        function a() {

        }

        console.log(b);
        var b = function () {

        };

        console.log(b);
    }

    test(1);

打印结果


分析

 function test(a) {

        //预解析 函数 被提升到顶端
// 注意a 有函数 有变量的时候  只提升函数的声明
        function a() {

        }
  //预解析 变量 被提升到 作用域的顶端
        var b;

//当执行 下面的代码的时候 
        console.log(a);  // 打印 函数体

        var a = 10;

        console.log(a);  //打印是 10



        console.log(b); //打印是 undefined
        var b = function () {

        };

        console.log(b);  // 打印是 函数体
    }


函数递归

  • 函数中调用函数自己,此时就是递归,递归一定要有结束的条件
  • 递归求和
//递归求和
    
    function getSum (x) {
      //如果 x是1的话  返回1
        if (x == 1) {
            return 1;
        }
        
        return x + getSum(x -1);
        
    }
    
    console.log(getSum(5));  ===》 15
    

递归.jpeg
  • 每个数字之和 比如:123 1+2+3 = 6

//求出个位数 然后相加
function getEverySum (x) {
        if (x < 10) {
            
            return x;
        }
        
        //获取这个数字的个位数   一直获取个位 相加
        return x%10 + getEverySum(parseInt(x/10));
    }
    
    console.log(getEverySum(136));

案例 求输入年月日,计算出是多少天

//    判断是否为闰年
   function isLeapYear(year){
       return (year % 4 == 0 && year % 100 == 0) || year % 400 == 0
   }

//计算
function getDays(year,month,day){
    // 存储对应的天数
    let days = day;
    //是否是一月份
    if(month == 1){
        return days;
    }
    //定义 12宇哥 每一个月对应的天数
    let months = [31,28,31,30,31,30,31,31,30,31,30,31];

    for(let i = 0; i < month - 1; i ++){

        days += months[I];
    }
    //判断是否为闰年
    if(isLeapYear(year) && month > 2){
        days ++;
    }

    return days;

}

console.log(getDays(2018,3,2));
// 61

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容