js闭包函数引发的点击事件变量最新值获取问题以及解决方案

**一. 问题**
		const [contentParams, setContentParams] = useState({
		    title: "资料",
		    mode: 'edit', // edit/read,
		    editParams: {
		      extra: [
		        <Button
		          key="save"
		          type="primary"
		          icon="save"
		          onClick={saveHandler}
		          style={{ marginLeft: '8px' }}
		        >
		          保存
		        </Button>
		      ],
		    },
		    readParams: {
		      extra: [],
		    }
		    // baseInfoCardData:[]
		  })
		  <Card>
		        <Button onClick={contentParams.editParams.extra[0]}>点击事件</Button>
		  </Card>
		
		const saveHandler =()=>{
		    const params = {
		      structureMain,
		      structureHistoryList,
		      contactList,
		      customerBaseInfo: {},
		      customerAuthInfo: {}
		    }
		  }

	structureMain,structureHistoryList,contactList发生改变的方式是赋值形式(即变量引用发生改变)。
	
	其中structureMain,structureHistoryList,contactList,等是外部状态变量,问题出在当这三个变量发生改变时,onClick方法无法获取最新的值。



## 二. 解答

		 这个方法中,contentParams中OnClick={saveHandler}中saveHandler实际上是函数的定义而非执行,这种写法就相当于在useState的匿名函数中写了一个saveHandler函数,因为这个函数也用到了外部变量,所以这个地方的saveHandler是一个闭包函数。
		 由于闭包函数的特性(无法直接访问外部变量环境,而只能通过引用来访问),这个闭包函数在创建的时候,记录了structureMain,structureHistoryList和contactList的引用,而这三个变量发生改变是通过重新赋值进行的,变量的引用已经发生了改变,但是此闭包函数使用的仍然是创建时的引用(即旧的引用),因此获取到的始终是未发生改变的值,才导致了此问题。
		 要解决这个问题,思路上可以考虑想办法重新创建这个闭包函数,使得其获取到最新的引用;也可以调整structureMain,structureHistoryList和contactList的变量的改变方式,从赋值形式改成属性赋予,这样它的引用就没有改变,闭包函数就能通过作用域链获取到最新的值;还可以改变函数的调用方式,使这个函数变成非闭包函数。
		 此次问题采用的解决方案是改为非闭包函数。并通过useEffect间接触发保存方法。
		 部分代码如下:
		 
			const [methodDispatchParams, setMethodDispatchParams] = useState({ saveHandlerDispatch: 0 })
		   ……
          <Button
	          key="save"
	          type="primary"
	          icon="save"
	          // loading={updateLoading}
	          // disabled={!isShowSave}
	          onClick={()=>setMethodDispatchParams({...methodDispatchParams, saveHandlerDispatch: 1})}
	          style={{ marginLeft: '8px' }}
        >
          	保存
        </Button>,
	……
			useEffect(()=>{
		    // 函数调用(一次useEffect只调用一次函数,防止出现套娃问题,所以执行完后return中断)
			    const { saveHandlerDispatch } = methodDispatchParams
			    if(saveHandlerDispatch === 1){
			      // 点击事件
		 	     saveHandler()
		   	   setMethodDispatchParams({...methodDispatchParams,saveHandlerDispatch: 0})
		    	  return;
		    }
		  },[methodDispatchParams])

## 三. 说明
		1. js中变量赋值的两种形式的区别
		   let a = {}
		   (1)   赋值形式,引用发生改变
		   a = {age: 15}
		   (2)  属性赋予形式,引用不变
		   a.age = 15
   
		2. 数组解构方法
		   const array = [1,5,7]
		   const [age1, age2, age3=17 ]  = array
		   结果age1 = 1, age2=5, age3 = 7
		   其中age3=17是的意思是赋予age3一个默认值17
		   
		3. 闭包函数的充分必要条件
		   (1) 定义在另一个函数内部
		   (2) 使用了闭包函数外的变量
		
		4. 闭包函数的特征
		   (1) 创建时记录捕获外部变量的引用,形成了自己的私有环境
		   (2) 无法直接访问外部环境(这意味着只能通过引用来访问外部变量,一旦引用发生变化,就无法感知到外部变量的变化)
		   
		5.  外部变量感知的原理
		这种感知的实现原理主要是JavaScript的作用域链和闭包机制。
		作用域链:JavaScript中有一个概念叫做“作用域链”,当代码运行时,JavaScript引擎会创建一个执行上下文,这个上下文中包含一个变量对象,存储着当前作用域内的变量和函数信息。当函数访问一个变量时,JavaScript引擎会沿着作用域链向上查找这个变量,直到找到为止。所以,当一个函数引用了外部变量,实际上是通过作用域链来访问这些变量的。
		闭包机制:当你在一个函数内部定义另一个函数,内部函数可以访问其包含函数(外部函数)的变量,即使外部函数已经执行完毕。这是因为内部函数形成了一个闭包,闭包中包含了对外部函数变量的引用。所以,即使外部变量的值改变了,闭包函数依然能够感知到,因为它保留了对旧变量的引用。
		综上所述,这种感知的实现原理就是,通过作用域链查找变量,通过闭包机制保留对变量的引用。这两者共同作用,使得函数能够感知到外部变量的变化。
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值