一、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的上级作用域是window
function a() {
function b() {
function c() {
}
}
}
// 典型例题:上级作用域,跟它在哪执行没关系,而跟它在哪里定义有关系
var a=2;
function fn(){
console.log(a);
}
fn(); // ?
function sum(){
var a=3;
fn(); //?
}
sum();
// 例题3
var 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引用数据类型被外边占用
- 不立即销毁
```javascript
function 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>