一、ES6中的let
1、没有变量提升
- 虽然没有变量提升,但是在代码执行之前,会进行语法错误的检测
console.log(1); //报语法错误let a = 5;var a = 6;
2、阻断了与window的关系!!
let a=2;console.log(window.a); // undefined
3、不能重复声明
4、暂时性死区
- 在声明变量之前的那个区域内是不允许访问此变量的,一旦访问就会报错
// 练习题let a=10,b=10;let fn=function(){console.log(a);let a=b=20;console.log(a,b);};fn();console.log(a, b)var ary=[12, 13];function fn(ary){console.log(ary);ary[0]=100;ary=[100];ary[0]=0;console.log(ary);}fn(ary);console.log(ary);
二、上级作用域
上级作用域: 当前函数执行,形成一个私有作用域A,这个A的上级作用域是谁,跟它在哪执行无关,跟它在哪定义(创建)有关系,在哪创建,它的上级作用域就是谁
上级作用域,跟它在哪执行没关系,而跟它在哪里定义有关系
// c的上级作用域是b,b的上级作用域是a,a的上级作用域是windowfunction a() {function b() {function c() {}}}
// 典型例题:上级作用域,跟它在哪执行没关系,而跟它在哪里定义有关系var a=2;function fn(){console.log(a);}fn(); // ?function sum(){var a=3;fn(); //?}sum();
// 例题3var n=10;function fn(){var n=20;function f(){n++;console.log(n);}f();return f;}var x=fn();x();x();console.log(n);
堆栈内存小科普
谷歌浏览器标记法:
- 每隔一段时间,就会检测一下引用空间地址是否被占用,如果没有被占用,在空闲的时候就会释放掉
IE和火狐等计数法:
- 当一个空间地址被占用一次,就累加1,如果不被占用了,减1,直到0的时候,就会释放掉
栈内存的释放
- 全局栈内存:当页面关闭的时候
- 函数执行形成的栈内存:
- 一般都是执行完毕之后就销毁额 ``` function fn() { console.log(1);
} fn();
- 不销毁:函数里面有一个引用数据类型的值,并且被外面的变量占用
// 例子1 function fn() { return function () { console.log(1);
}
}
var f = fn();
// 例子2 var ary = []; function fn() { ary = [1,2,3]; } fn(); //执行完之后不会被销毁,因为函数里ary引用数据类型被外边占用
- 不立即销毁```javascriptfunction fn(x) {return function (y) {return x+y;}}fn(x)(y); // fn(x)执行完的时候fn(){}还没有被销毁;fn(x)(y)执行完之后被销毁
三、闭包(closure)
当一个函数执行,形成一个私有作用域,保护里面的私有变量不受外界干扰,这种机制叫做闭包
市场上大部分人认为**: **当一个函数执行时,里面有一个引用数据类型被外界占用了,形成了不销毁作用域
- 当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的变量,且返回的这个函数在外部被执行,就产生了闭包。
- 闭包是一个环境,具体指的就是外部函数—高阶函数
- 优点:
- 变量长期驻扎在内存中,避免全局变量的污染;
- 私有成员的存在
- 缺点:常驻内存 会增大内存的使用量 使用不当会造成内存泄露
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
// 简单闭包例子function fn(x) {return function (y) {return x+y;}}var f = fn(1);f(2); // f(); 执行的时候可以获取到上级作用域中的x,因为fn(x){}函数没有被销毁, 这是闭包的保存作用
闭包的作用
- 【保护】:保护里面的私有变量不受外界的干扰.
function fn () {var a = 10;console.log(a);}console.log(a);
- 【保存】:形成不销毁的作用域,可以把里面的变量保存下来
function fn(x) {return function (y) {return x+y;}}var f = fn(1);f(2); // f(); 执行的时候可以获取到上级作用域中的x,因为fn(x){}函数没有被销毁, 这是闭包的保存作用
闭包在实战中的作用
- 【Jquery】通过window添加属性暴漏到全局
(function(){function jquery(){}//把jquer 这个方法通过window添加属性暴漏到全局window.jquery=window.$=jquery;})()在使用的时候: jquery() 或者$()
- 【zepto】把自执行函数的通过return把返回结果在外面用一个变量进行接收
var zepto=(function(){return {fn:function(){},.....}})()// 在使用的时候:zepto.fn
选项卡中的for循环点击事件运用闭包
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>选项卡</title><style>* {margin: 0;padding: 0;}.main {width: 500px;margin: 0 auto;}.main li {width: 100px;height: 40px;line-height: 40px;text-align: center;border: 1px solid red;display: inline-block;position: relative;top: 1px;}.main li.current {background-color: saddlebrown;border-bottom-color: saddlebrown;}.main div {height: 200px;line-height: 200px;text-align: center;border: 1px solid red;display: none;}.main div.current {background-color: saddlebrown;display: block;}</style></head><body><div class="main"><ul><li class="current">1</li><li>2</li><li>3</li></ul><div class="current">1</div><div>2</div><div>3</div></div><script>var lis = document.querySelectorAll(".main li");var divs = document.querySelectorAll(".main>div");// for (var i = 0; i < lis.length; i++) {// // 方式一:// /* (function (i) {// lis[i].onclick = function() {// for (var j = 0;j < lis.length;j++) {// lis[j].className = "";// divs[j].className = "";// }// lis[i].className = "current";// divs[i].className = "current";// }// })(i) */// // 方式二:// /* lis[i].onclick = (function (i) {// return function () {// for (var j = 0; j < lis.length; j++) {// lis[j].className = "";// divs[j].className = "";// }// lis[i].className = "current";// divs[i].className = "current";// }// })(i) */// }// 方式三:let会形成独立的块级作用域for (let i = 0;i < lis.length;i++) {lis[i].onclick = function() {for (var j = 0;j < lis.length;j++) {lis[j].className = "";divs[j].className = "";}lis[i].className = "current";divs[i].className = "current";}}</script></body>
