什么是環境與作用域:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <h1>CYY</h1> <script> let name = 'cyy';//全域環境,不會回收 </script> </body> </html>
函式的環境與作用域原理:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <h1>CYY</h1> <script> let name = 'cyy';//全域環境,不會回收 function func() { // 函式環境 let name = 'cyy2'; } // 只在函式被呼叫時創建,函式執行結束后會被銷毀 // 函式外部不能使用函式內部的變數,函式內部可以使用函式外部的變數 </script> </body> </html>
延伸函式環境生命周期:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // 函式執行完之后,內部變數就會被銷毀,除非一直在被參考 // function func() { // let n = 1; // function show() { // console.log(++n); // } // show() // } // func(); func(); // function func() { // let n = 1; // return function show() { // console.log(++n); // } // show() // } // // 每次呼叫會創建新的記憶體地址 // let res = func(); // 等于把show函式回傳給外部 // res(); res(); res(); res(); // // 每次呼叫會創建新的記憶體地址 // let res2 = func(); res2(); // 不會遞增,因為render方法并沒有被外部參考,所以每次呼叫都會創建新的記憶體空間,無法保存上一次的變數 // function func() { // let n = 1; // return function show() { // let m = 1; // function render() { // console.log(++m); // } // render() // } // show() // } // let res = func(); res(); res(); res(); res(); function func() { let n = 1; return function show() { let m = 1; return function render() { console.log('m:' + ++m); console.log('n:' + ++n); } render() } show() } let res = func()(); // 等于把render函式回傳給外部 res(); res(); res(); res(); </script> </body> </html>
建構式中的作用域的使用形態:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // 建構式中的方法一直在被參考,因此變數能夠保存 // function Show() { // let n = 1; // this.render = function () { // console.log(++n); // } // } // let s = new Show(); // s.render(); // s.render(); // 與上述寫法類似 // function Show() { // let n = 1; // function render() { // console.log(++n); // } // return { // render: render // } // } // let s = new Show(); // s.render(); // s.render(); function Show() { let n = 1; this.render = function () { console.log(++n); } } // 每次new都會開辟一塊新的空間,因此變數無法被繼續保存 let s = new Show(); s.render(); s.render(); let s2 = new Show(); s2.render(); s2.render(); </script> </body> </html>
什么是塊級作用域:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // { // let a = 1; // console.log(a); // } // // console.log(a); // { // let a = 1; // console.log(a); // } // var沒有塊級作用域 // { // var a = 1; // } // console.log(a); </script> </body> </html>
let-var在for回圈中的執行原理:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // var沒有塊級作用域,因此i是掛載到全域的,每次回圈都改變了全域的i // for (var i = 0; i <= 3; i++) { // console.log(111); // } // console.log(i); // console.log(window.i); // let有塊級作用域,因此只在for回圈中,在全域無法呼叫 // for (let i = 0; i <= 3; i++) { // console.log(111); // } // console.log(i); for (var i = 0; i <= 3; i++) { setTimeout(function () { console.log(i);//一直輸出全域的i,是4 }); } for (let i = 0; i <= 3; i++) { setTimeout(function () { console.log(i); }); } </script> </body> </html>
模擬出var的偽塊作用域:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // var沒有塊級作用域,但是有函式作用域,因此可以把程式用函式包起來,匿名函式自執行 for (var i = 0; i <= 3; i++) { (function (i) { setTimeout(function () { console.log(i); }); })(i); } </script> </body> </html>
多級作用域嵌套詳解:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // let arr = []; // for (let i = 0; i < 4; i++) { // arr.push(function () { // return i; // }); // } // console.log(arr);//在陣列中壓入4個函式,由于函式處于被參考狀態,因此內部的變數得以保留 // console.log(arr[0]());// 執行陣列中第一個元素的函式 // console.log(arr[1]());// 執行陣列中第一個元素的函式 // console.log(arr[2]());// 執行陣列中第一個元素的函式 // let arr = []; // for (var i = 0; i < 4; i++) { // arr.push(function () { // return i; // }); // } // console.log(arr);//在陣列中壓入4個函式,函式操作的i始終是全域的 // console.log(arr[0]());// 執行陣列中第一個元素的函式 // console.log(arr[1]());// 執行陣列中第一個元素的函式 // console.log(arr[2]());// 執行陣列中第一個元素的函式 // 使用函式作用域使得i不再是全域 let arr = []; for (var i = 0; i < 4; i++) { (function (i) { arr.push(function () { return i; }); })(i); } console.log(arr);//在陣列中壓入4個函式,函式操作的i始終是全域的 console.log(arr[0]());// 執行陣列中第一個元素的函式 console.log(arr[1]());// 執行陣列中第一個元素的函式 console.log(arr[2]());// 執行陣列中第一個元素的函式 </script> </body> </html>
什么是閉包:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // 閉包 function func() { let n = 1; return function sum() { console.log(++n); } } let a = func(); a(); a(); a(); a(); </script> </body> </html>
使用閉包獲取區間商品:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> </style> </head> <body> <script> // let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // let res = arr.filter(item => item <= 7 && item >= 3); // console.log(res); // let res2 = arr.filter(item => item <= 6 && item >= 1); // console.log(res2); // // 閉包可以訪問到父級的變數 // function between(a, b) { // return function (item) { // return item <= a && item >= b; // } // } // let res3 = arr.filter(between(7, 3)); // console.log(res3); // let res4 = arr.filter(between(5, 2)); // console.log(res4); let lessons = [ { title: 'title1', price: 100, click: 1 }, { title: 'title2', price: 67, click: 2 }, { title: 'title3', price: 32, click: 5 }, ]; function between(a, b) { return function (item) { return item.price <= a && item.price >= b; } } let res3 = lessons.filter(between(100, 50)); console.table(res3); </script> </body> </html>
移動影片的閉包使用:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> button { position: absolute; } </style> </head> <body> <button message="cyy1">cyy1</button> <button message="cyy2">cyy2</button> <script> let btns = document.querySelectorAll('button'); btns.forEach(function (btn) { btn.addEventListener('click', function () { let left = 1; console.log(left); // 閉包:能夠訪問到外部的變數,一直向外去找 setInterval(function () { btn.style.left = left++ + 'px'; }, 10); }); }); </script> </body> </html>

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> button { position: absolute; } </style> </head> <body> <button message="cyy1">cyy1</button> <!-- <button message="cyy2">cyy2</button> --> <script> // let btns = document.querySelectorAll('button'); // btns.forEach(function (btn) { // let left = 1; // 點擊之后不會形成新的環境,解決抖動的問題;但是每點擊一次會生成一個新的環境,會重復定義多個定時器,導致影片越來越快 // let interval = false; // 節流閥,防抖 // btn.addEventListener('click', function () { // if (interval == false) { // interval = true; // // let left = 1; // 每次點擊后會形成新的環境,使得left從1開始運動,導致影片抖動 // console.log(left); // // 閉包:能夠訪問到外部的變數,一直向外去找 // setInterval(function () { // btn.style.left = left++ + 'px'; // }, 10); // } // }); // }); // let btns = document.querySelectorAll('button'); // btns.forEach(function (btn) { // let bind = false; // btn.addEventListener('click', function () { // if (bind == false) { // bind = true; // let left = 1; // // 閉包:能夠訪問到外部的變數,一直向外去找 // setInterval(function () { // btn.style.left = left++ + 'px'; // }, 10); // } // }); // }); let btns = document.querySelectorAll('button'); btns.forEach(function (btn) { let bind = false; btn.addEventListener('click', function () { if (bind == false) { let left = 1; // 閉包:能夠訪問到外部的變數,一直向外去找 // setInterval回傳定時器編號 bind = setInterval(function () { btn.style.left = left++ + 'px'; }, 10); console.log(bind); } }); }); </script> </body> </html>
利用閉包根據欄位排序商品:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> button { position: absolute; } </style> </head> <body> <script> let goods = [ { name: 'name1', click: 99, price: 19 }, { name: 'name2', click: 122, price: 327 }, { name: 'name3', click: 44, price: 991 }, ]; function order(field, type = "asc") { return function (a, b) { if (type == 'asc') { return a[field] > b[field] ? 1 : -1; } else { return a[field] > b[field] ? -1 : 1; } } } let res = goods.sort(order('click', 'desc')); console.table(res); </script> </body> </html>

閉包的記憶體泄露解決方法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> button { position: absolute; } </style> </head> <body> <div desc="cyy">CYY</div> <div desc="girl">GIRL</div> <script> // let divs = document.querySelectorAll('div'); // divs.forEach(function (div) { // div.addEventListener('click', function () { // console.log(div.getAttribute('desc')); // console.log(div); // 存在記憶體泄露問題 // }); // }); let divs = document.querySelectorAll('div'); divs.forEach(function (div) { let desc = div.getAttribute('desc'); div.addEventListener('click', function () { // 異步呼叫點擊 console.log(desc); console.log(div); }); div = null; // 同步執行 }); </script> </body> </html>
this在閉包中的歷史遺留問題:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"> <style> button { position: absolute; } </style> </head> <body> <script> // let obj = { // name: 'cyy', // show() { // return function () { // return this.name; // } // } // } // console.log(obj.show()()); // this指向window // let func = obj.show(); func(); // 與上述寫法相同 //使用箭頭函式解決問題 // let obj = { // name: 'cyy', // show() { // return () => { // return this.name; // } // } // } // console.log(obj.show()()); // 使用bind改變this的指向 let obj = { name: 'cyy', show() { return function () { return this.name; } } } let func = obj.show(); console.log(func.bind(obj)()); </script> </body> </html>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/225041.html
標籤:其他
上一篇:這次把JS閉包給你講得明明白白
下一篇:css類名的使用
