【JavaScript进阶】函数进阶

本文深入讲解JavaScript中的函数定义与调用、this指向调整方法、严格模式特性、高阶函数、闭包原理、递归机制及深浅拷贝的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本次主要学习内容:

  • 函数的多种定义和调用方式
  • 函数内部this的指向
  • 严格模式的特点
  • 高阶函数把函数作为参数和返回值传递
  • 闭包的作用
  • 递归的两个条件
  • 深拷贝和浅拷贝的区别

一、函数的定义和调用

01. 定义

  • (1)函数声明方式function关键字(命名函数)

    function fn(){
        
    }
    
  • (2)函数表达式(匿名函数)

    var fn = function(){
        
    }
    
  • (3)利用 new Function()

    var fn = new Function("参数1", "参数2", "函数体");
    
    • 参数必须是字符串格式
    • 但第三种方式执行效率低,也不方便书写,因此较少使用
    • 另外,所有函数都是 Function 的实例(对象),因此函数也属于对象

02. 调用

  • 普通函数

    this指向window

    fn();
    fn.call();
    
  • 对象的方法

    this指向obj

    obj.fn();
    
  • 构造函数1

    this指向实例对象

    new Person();
    
  • 绑定事件函数

    this指向btn,函数的调用者

    btn.onclick = function(){
        
    };
    
  • 定时器函数

    this指向window

    setInterval(function(){
        
    }1000);
    
  • 立即执行函数(自动调用)

    this指向window

    (function(){
        
    })();
    

二、this指向的改变

  • call()apply()append()
(1)通过call()方法
  • 语法结构:

    call(thisarg, arg1, arg2)
    
    • thisarg即为改变的this的指向对象

    • 可以调用函数

    • 可以实现继承

      function func(arg1, arg2){
      	    
      }
      
      func(arg1, arg2);	//调用函数,传递参数
      
      func.call(thisArg, arg1 ,arg2);		//调用函数,改变this,传递参数
      
(2)通过apply()方法
  • 语法结构:

    apply(thisArg, [])
    
    • 可以调用函数

    • 改变函数内部this的指向,可以为空null

    • 参数必须是数组,且参数的数据类型和数组的数据类型一致

    • 应用:

      • 可以利用Math.maxapply()求数组中的最大值

        var arr=[1,3,5,7,8,9];
        
        // Math.max(arg1, arg2, aeg3, ...)
        Math.max(1,3,5,7,8,9);		// 结果:9
        
        // .apply(Math,arr)
        // 即将参数以数组形式传入,但函数仍以其原有接受参数形式进行接收
        var max = Math.max.apply(Math,arr);		//等价于上面的Math.max(...)
        
        
(3)通过bind()方法
  • 语法结构:

    fn.bind(thisArg, arg1, arg2);
    
    • bind()方法不会调用函数

    • 能改变原来函数内部this的指向

    • 会返回一个新函数

    • 应用:

      btn.onclick = function(){
          this.disabled = true;
          
          setTimeout(function(){	//一般情况下,定时器里面的this指向window
              this.disabled = false;
          }.bind(this),3000)		//通过bind() 让定时器内部的 this指向 改变为事件函数的调用者
      }
      

(4)总结call()、apply()、bind()
  • 相同点

    • 都可以改变函数内部的this指向
  • 区别点:

    • callapply会调用函数,并且改变函数内部this指向

    • callapply传递的参数不一样

      • call传递参数单个形式:arg1,arg2
      • apply传递参数数组形式:[arg1,arg2]
    • bind不会调用函数,但也能改变函数内部this指向

  • 主要应用场景:

    • call:经常在继承中使用

      在子构造函数中调用父构造函数的构造方法

    • apply:经常搭配数组使用

      比如借助于数学对象实现数组最大值最小值

    • bind:不需要调用函数,但是还想改变this指向时适用

      比如改变定时器内部的this指向


三、严格模式(strict mode)

01.基本概念

  • 消除了Javascript语法的一些不合理、不严谨之处,减少了一些怪异行为
  • 消除代码运行的一些不安全之处,保证代码运行的安全
  • 提高编译器效率,增加运行速度
  • 禁用了ECMAScript的末来版本中可能会定义的一些语法,为末来新版本的 Javascript做好铺垫。
    • 比如一些保留字,如:classenumexportextendsimportsuper不能做变量名

02.使用方法

(1)为脚本开启严格模式
  • 在所有语句之前放置特定语句: "use strict";
(2)为函数开启严格模式
  • 在函数内部之前放置语句: "use strict";

03.严格模式下的变化

(1)变量
  • 变量必须先声明,再使用
  • 不能随意删除已经声明的变量
(2)this指向
  • 有改变的:
    • 全局作用域中函数的 this 不指向 window , 而是指向 undefined
    • 构造函数中,不加 new 调用,this会报错
  • 没有变化的:
    • new实例化的构造函数还是指向对象实例
    • 定时器函数this还是指向window
    • 事件对象还是指向调用者
(3)函数
  • 函数必须声明在顶层,不允许在非函数的代码块内声明函数

    如,函数声明不能在if、for、while

  • 函数的参数不能重名


四、高阶函数

  • 高阶函数是对其他函数进行操作的函数
    • 可以接收函数作为参数或将函数作为返回值输出

五、闭包

01.关于变量作用域

  • 全局变量和局部变量

02.闭包的基本概念

  • 闭包( closure指:有权访问另—个函数作用域中变量函数

  • 一个作用域可以访问另外—个函数内部的局部变量,局部变量所在函数就称为:闭包

function father(){
    var num = 24;		//num可以被son函数访问到,num所在函数就产生了闭包
    function son(){		//这个son函数可以访问father函数下的num
        console.log(num);
    }
    son();
}
function father(){
    var num = 24;
    
    function son(){
        console.log(num);
    }
    
    return son;
}

var fun = father();		//这时,fun就等于son,可以调用
fun();			//调用fun,仍然可以产生闭包,可以访问num
  • 闭包的作用:延伸了变量的作用范围
for(var i=0;i<lis.length;i++){
    //闭包可以延伸i的作用范围,这样可以实现点击li打印对应索引号
    (function(i){
        lis[i].onclick = function(){
            console.log(i);
        }
    })(i);
}

六、递归

  • 递归函数:函数内部自己调用自己,这个函数就是递归函数(类似于循环)

  • 递归里面必须加退出条件return(否则死递归)


  • 应用:数学递归、数据递归

    function factorial(n){
        if(n == 1){
            return 1;
        }else{0
            return n * factorial(n-1);
        }
    }
    console.log(factorial(5));
    

七、浅拷贝、深拷贝

  • 浅拷贝:只拷贝一层,更深层次对象级别的只拷贝【引用(地址)】

  • 深拷贝:可拷贝多层,每一级别的数据都会拷贝

    可用栈+堆的思维方式理解:

    浅拷贝只拷贝栈上的值,因此对于存放在堆里面的对象数据只能拷贝栈上的引用,而无法拷贝具体数据

    深拷贝可拷贝所有的值,包括栈和堆里的数据


  • ES6的浅拷贝方法:assign

    Object.assign(目标对象, 原对象);
    
    //把原对象拷贝给目标对象,这个拷贝是浅拷贝
    
  • ES6的深拷贝方法:(递归)

    var oldObj = {};
    var newObj = {};
    
    function deepCopy(newObj, oldObj){
        for(var k in oldObj){
            var item = oldObj[k];
            if(item instanceof Array){
                //如果这个属性是数组,注意数组要在对象前,因为数组也是对象
                newObj[k] = [];	//让目标对象的这个属性也是数组
                deepCopy(newObj[k],item);//然后进入递归
            }else if(item instanceof Object){
                //如果这个属性是对象
                newObj[k] = {};	//让目标对象的这个属性也是对象
                deepCopy(newObj[k],item);//然后进入递归
            }else{
                //只有在既不是数组、也不是对象时,才可以直接赋值
                newObj[k] = item;
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值