一、ES6中的let

1、没有变量提升

  • 虽然没有变量提升,但是在代码执行之前,会进行语法错误的检测
  1. console.log(1); //报语法错误
  2. let a = 5;
  3. var a = 6;

2、阻断了与window的关系!!

  1. let a=2;
  2. console.log(window.a); // undefined

3、不能重复声明

4、暂时性死区

  • 在声明变量之前的那个区域内是不允许访问此变量的,一旦访问就会报错
  1. // 练习题
  2. let a=10,
  3. b=10;
  4. let fn=function(){
  5. console.log(a);
  6. let a=b=20;
  7. console.log(a,b);
  8. };
  9. fn();
  10. console.log(a, b)
  11. var ary=[12, 13];
  12. function fn(ary){
  13. console.log(ary);
  14. ary[0]=100;
  15. ary=[100];
  16. ary[0]=0;
  17. console.log(ary);
  18. }
  19. fn(ary);
  20. console.log(ary);

二、上级作用域

上级作用域: 当前函数执行,形成一个私有作用域A,这个A的上级作用域是谁,跟它在哪执行无关,跟它在哪定义(创建)有关系,在哪创建,它的上级作用域就是谁

上级作用域,跟它在哪执行没关系,而跟它在哪里定义有关系

  1. // c的上级作用域是b,b的上级作用域是a,a的上级作用域是window
  2. function a() {
  3. function b() {
  4. function c() {
  5. }
  6. }
  7. }
  1. // 典型例题:上级作用域,跟它在哪执行没关系,而跟它在哪里定义有关系
  2. var a=2;
  3. function fn(){
  4. console.log(a);
  5. }
  6. fn(); // ?
  7. function sum(){
  8. var a=3;
  9. fn(); //?
  10. }
  11. sum();
  1. // 例题3
  2. var n=10;
  3. function fn(){
  4. var n=20;
  5. function f(){
  6. n++;
  7. console.log(n);
  8. }
  9. f();
  10. return f;
  11. }
  12. var x=fn();
  13. x();
  14. x();
  15. console.log(n);

堆栈内存小科普

谷歌浏览器标记法:

  • 每隔一段时间,就会检测一下引用空间地址是否被占用,如果没有被占用,在空闲的时候就会释放掉

IE和火狐等计数法:

  • 当一个空间地址被占用一次,就累加1,如果不被占用了,减1,直到0的时候,就会释放掉

栈内存的释放

  • 全局栈内存:当页面关闭的时候
  • 函数执行形成的栈内存:
    • 一般都是执行完毕之后就销毁额 ``` function fn() { console.log(1);

} fn();

  1. - 不销毁:函数里面有一个引用数据类型的值,并且被外面的变量占用

// 例子1 function fn() { return function () { console.log(1);

  1. }

}

var f = fn();

// 例子2 var ary = []; function fn() { ary = [1,2,3]; } fn(); //执行完之后不会被销毁,因为函数里ary引用数据类型被外边占用

  1. - 不立即销毁
  2. ```javascript
  3. function fn(x) {
  4. return function (y) {
  5. return x+y;
  6. }
  7. }
  8. fn(x)(y); // fn(x)执行完的时候fn(){}还没有被销毁;fn(x)(y)执行完之后被销毁

三、闭包(closure)

当一个函数执行,形成一个私有作用域,保护里面的私有变量不受外界干扰,这种机制叫做闭包
市场上大部分人认为**: **当一个函数执行时,里面有一个引用数据类型被外界占用了,形成了不销毁作用域

  • 当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的变量,且返回的这个函数在外部被执行,就产生了闭包。
  • 闭包是一个环境,具体指的就是外部函数—高阶函数
  • 优点:
    • 变量长期驻扎在内存中,避免全局变量的污染;
    • 私有成员的存在
  • 缺点:常驻内存 会增大内存的使用量 使用不当会造成内存泄露
    • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
    • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
  1. // 简单闭包例子
  2. function fn(x) {
  3. return function (y) {
  4. return x+y;
  5. }
  6. }
  7. var f = fn(1);
  8. f(2); // f(); 执行的时候可以获取到上级作用域中的x,因为fn(x){}函数没有被销毁, 这是闭包的保存作用

闭包的作用

  • 【保护】:保护里面的私有变量不受外界的干扰.
  1. function fn () {
  2. var a = 10;
  3. console.log(a);
  4. }
  5. console.log(a);
  • 【保存】:形成不销毁的作用域,可以把里面的变量保存下来
  1. function fn(x) {
  2. return function (y) {
  3. return x+y;
  4. }
  5. }
  6. var f = fn(1);
  7. f(2); // f(); 执行的时候可以获取到上级作用域中的x,因为fn(x){}函数没有被销毁, 这是闭包的保存作用

闭包在实战中的作用

  • 【Jquery】通过window添加属性暴漏到全局
  1. (function(){
  2. function jquery(){
  3. }
  4. //把jquer 这个方法通过window添加属性暴漏到全局
  5. window.jquery=window.$=jquery;
  6. })()
  7. 在使用的时候: jquery() 或者$()
  • 【zepto】把自执行函数的通过return把返回结果在外面用一个变量进行接收
  1. var zepto=(function(){
  2. return {
  3. fn:function(){},
  4. .....
  5. }
  6. })()
  7. // 在使用的时候:zepto.fn

选项卡中的for循环点击事件运用闭包

  1. <head>
  2. <meta charset="UTF-8">
  3. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  4. <title>选项卡</title>
  5. <style>
  6. * {
  7. margin: 0;
  8. padding: 0;
  9. }
  10. .main {
  11. width: 500px;
  12. margin: 0 auto;
  13. }
  14. .main li {
  15. width: 100px;
  16. height: 40px;
  17. line-height: 40px;
  18. text-align: center;
  19. border: 1px solid red;
  20. display: inline-block;
  21. position: relative;
  22. top: 1px;
  23. }
  24. .main li.current {
  25. background-color: saddlebrown;
  26. border-bottom-color: saddlebrown;
  27. }
  28. .main div {
  29. height: 200px;
  30. line-height: 200px;
  31. text-align: center;
  32. border: 1px solid red;
  33. display: none;
  34. }
  35. .main div.current {
  36. background-color: saddlebrown;
  37. display: block;
  38. }
  39. </style>
  40. </head>
  41. <body>
  42. <div class="main">
  43. <ul>
  44. <li class="current">1</li>
  45. <li>2</li>
  46. <li>3</li>
  47. </ul>
  48. <div class="current">1</div>
  49. <div>2</div>
  50. <div>3</div>
  51. </div>
  52. <script>
  53. var lis = document.querySelectorAll(".main li");
  54. var divs = document.querySelectorAll(".main>div");
  55. // for (var i = 0; i < lis.length; i++) {
  56. // // 方式一:
  57. // /* (function (i) {
  58. // lis[i].onclick = function() {
  59. // for (var j = 0;j < lis.length;j++) {
  60. // lis[j].className = "";
  61. // divs[j].className = "";
  62. // }
  63. // lis[i].className = "current";
  64. // divs[i].className = "current";
  65. // }
  66. // })(i) */
  67. // // 方式二:
  68. // /* lis[i].onclick = (function (i) {
  69. // return function () {
  70. // for (var j = 0; j < lis.length; j++) {
  71. // lis[j].className = "";
  72. // divs[j].className = "";
  73. // }
  74. // lis[i].className = "current";
  75. // divs[i].className = "current";
  76. // }
  77. // })(i) */
  78. // }
  79. // 方式三:let会形成独立的块级作用域
  80. for (let i = 0;i < lis.length;i++) {
  81. lis[i].onclick = function() {
  82. for (var j = 0;j < lis.length;j++) {
  83. lis[j].className = "";
  84. divs[j].className = "";
  85. }
  86. lis[i].className = "current";
  87. divs[i].className = "current";
  88. }
  89. }
  90. </script>
  91. </body>