2020年11月20日星期五

这次把JS闭包给你讲得明明白白 -cyy

什么是环境与作用域:

<!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>

 









原文转载:http://www.shaoqun.com/a/490673.html

拍拍网服装:https://www.ikjzd.com/w/2205

张洁:https://www.ikjzd.com/w/1663

let go:https://www.ikjzd.com/w/825


什么是环境与作用域:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Document</title><metaname="viewport"content="width=de
凹凸曼:凹凸曼
亚马逊全球开店:亚马逊全球开店
阳江闸坡东方银滩门票大概要多少?:阳江闸坡东方银滩门票大概要多少?
Joom平台产品审核速度及审核顺序详解!:Joom平台产品审核速度及审核顺序详解!
泉州北溪文苑桃花谷好玩吗?景色怎样?:泉州北溪文苑桃花谷好玩吗?景色怎样?

没有评论:

发表评论