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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358