久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      簡單了解JavaScript閉包

      本篇文章給大家?guī)砹岁P(guān)于JavaScript的相關(guān)知識,其中主要介紹了關(guān)于JavaScript閉包的相關(guān)問題,閉包的概念有很多版本,不同的地方對閉包的說法不一,下面一起來看一下,希望對大家有幫助。

      簡單了解JavaScript閉包

      什么是閉包?

      閉包的概念是有很多版本,不同的地方對閉包的說法不一

      維基百科:在計算機科學(xué)中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是在支持頭等函數(shù)的編程語言中實現(xiàn)詞法綁定的一種技術(shù)。

      MDN: 閉包(closure)是一個函數(shù)以及其捆綁的周邊環(huán)境狀態(tài)(lexical environment詞法環(huán)境)的引用的組合。

      個人理解:

      • 閉包是一個函數(shù)(返回一個函數(shù))
      • 返回的函數(shù)保存了對外變量引用

      一個簡單的示例

      function fn() {    let num = 1;    return function (n) {        return n + num     } }let rFn = fn()let newN = rFn(3) // 4
      登錄后復(fù)制

      num 變量作用域在 fn 函數(shù)中, rFn 函數(shù)卻能訪問 num 變量,這就是閉包函數(shù)能訪問外部函數(shù)變量。

      從瀏覽器調(diào)試和 VSCode Nodejs 調(diào)試看閉包

      • 瀏覽器

      簡單了解JavaScript閉包

      • VS Code 配合 Node.js

      簡單了解JavaScript閉包

      看到 Closure 中 fn 是閉包函數(shù),其中保存 num 變量。

      一個經(jīng)典的閉包:單線程事件機制+循環(huán)問題,以及解決辦法

      for (var i = 1; i <= 5; i++) {  setTimeout(() => {    console.log(i);   }, i * 1000); }
      登錄后復(fù)制

      登錄后復(fù)制

      輸出的結(jié)果都是 6,為什么?

      • for 循環(huán)是同步任務(wù)
      • setTimeout 異步任務(wù)

      for 循環(huán)一次,就會將 setTimeout 異步任務(wù)加入到瀏覽器的異步任務(wù)隊列中,同步任務(wù)完成之后,再從異步任務(wù)中拿新任務(wù)在線程中執(zhí)行。由于 setTimeout 能夠訪問外部變量 i, 當(dāng)同步任務(wù)完成之后,i 已經(jīng)變成了6, setTimeout 中能夠訪問變量 i 都是 6。

      解決辦法1:使用 let 聲明

      for (var i = 1; i <= 5; i++) {  setTimeout(() => {    console.log(i);   }, i * 1000); }
      登錄后復(fù)制

      登錄后復(fù)制

      解決辦法2:自執(zhí)行函數(shù) + 閉包

      for (var i = 1; i <= 5; i++) {   (function(i){      setTimeout(() => {    console.log(i);   }, i * 1000)   })(i) }
      登錄后復(fù)制

      解決辦法3:setTimeout 傳遞第三參數(shù)

      第三個參數(shù)意思:附加參數(shù),一旦定時器到期,它們會作為參數(shù)傳遞給要執(zhí)行的函數(shù)

      for (var i = 1; i <= 5; i++) {  setTimeout((j) => {    console.log(j);   }, 1000 * i, i); }
      登錄后復(fù)制

      閉包與函數(shù)科里化

      function add(num) {  return function (y) {    return num + y;   }; };let incOneFn = add(1); let n = incOneFn(1);  // 2let decOneFn = add(-1); let m = decOneFn(1); // 0
      登錄后復(fù)制

      add 函數(shù)的參數(shù)保存了閉包函數(shù)變量。

      實際作用

      在函數(shù)式編程閉包有非常重要的作用,lodash 等早期工具函數(shù)彌補 javascript 缺陷的工具函數(shù),有大量的閉包的使用場景。

      使用場景

      • 創(chuàng)建私有變量
      • 延長變量生命周期

      節(jié)流函數(shù)

      防止?jié)L動行為,過度執(zhí)行函數(shù),必須要節(jié)流, 節(jié)流函數(shù)接受 函數(shù) + 時間作為參數(shù),都是閉包中變量,以下是一個簡單 setTimeout 版本:

      function throttle(fn, time=300){    var t = null;    return function(){        if(t) return;         t = setTimeout(() => {             fn.call(this);             t = null;         }, time);     } }
      登錄后復(fù)制

      防抖函數(shù)

      一個簡單的基于 setTimeout 防抖的函數(shù)的實現(xiàn)

      function debounce(fn,wait){    var timer = null;    return function(){        if(timer !== null){            clearTimeout(timer);         }         timer = setTimeout(fn,wait);     } }
      登錄后復(fù)制

      React.useCallback 閉包陷阱問題

      問題說明:父/子 組件關(guān)系, 父子組件都能使用 click 事件同時修改 state 數(shù)據(jù), 并且子組件拿到傳遞下的 props 事件屬性,是經(jīng)過 useCallback 優(yōu)化過的。也就是這個被優(yōu)化過的函數(shù),存在閉包陷阱,(保存一直是初始 state 值)

      import { useState, useCallback, memo } from "react";const ChildWithMemo = memo((props: any) => {  return (    <div>       <button onClick={props.handleClick}>Child click</button>     </div>   ); });const Parent = () => {  const [count, setCount] = useState(1);  const handleClickWithUseCallback = useCallback(() => {    console.log(count);   }, []); // 注意這里是不能監(jiān)聽 count, 因為每次變化都會重新綁定,造成造成子組件重新渲染    return (    <div>       <div>parent count : {count}</div>       <button onClick={() => setCount(count + 1)}>click</button>       <ChildWithMemo handleClick={handleClickWithUseCallback} />     </div>   ); };export default Parent
      登錄后復(fù)制

      • ChildWithMemo 使用 memo 進行優(yōu)化,
      • handleClickWithUseCallback 使用 useCallback 優(yōu)化

      問題是點擊子組件時候,輸出的 count 是初始值(被閉包了)。

      解決辦法就是使用 useRef 保存操作變量函數(shù):

      import { useState, useCallback, memo, useRef } from "react";const ChildWithMemo = memo((props: any) => {  console.log("rendered children")  return (    <div>       <button onClick={() => props.countRef.current()}>Child click</button>     </div>   ); });const Parent = () => {  const [count, setCount] = useState(1);  const countRef = useRef<any>(null)    countRef.current = () => {    console.log(count);   }  return (    <div>       <div>parent count : {count}</div>       <button onClick={() => setCount(count + 1)}>click</button>       <ChildWithMemo countRef={countRef} />     </div>   ); };export default Parent
      登錄后復(fù)制

      針對這個問題,React 曾經(jīng)認可過社區(qū)提出的增加 useEvent 方案,但是后面 useEvent 語義問題被廢棄了,對于渲染優(yōu)化 React 采用了編譯優(yōu)化的方案。其實類似的問題也會發(fā)生在 useEffect 中,使用時要注意閉包陷阱。

      性能問題

      • 閉包不要隨意定義,定義了一定找到合適的位置進行銷毀。因為閉包的變量保存在內(nèi)存中,不會被銷毀,占用較高的內(nèi)存。

      使用 chrome 面板功能 timeline + profiles 面板

      1. 打開開發(fā)者工具,選擇 Timeline 面板
      2. 在頂部的Capture字段里面勾選 Memory
      3. 點擊左上角的錄制按鈕。
      4. 在頁面上進行各種操作,模擬用戶的使用情況。
      5. 一段時間后,點擊對話框的 stop 按鈕,面板上就會顯示這段時間的內(nèi)存占用情況。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號