私有变量和全局变量
作用域:一块栈内存,目的是为了给代码执行提供环境
闭包:形成私有作用域可以保护里面的私有变量不受外界干扰,这种保护机制可以理解为闭包。当我们函数执行,有个地儿把变量存起来,以后想要从这里拿出来这种机制叫做闭包,柯里化函数编程思想。
让私有变量和外界隔离开来,保护起来。
如果这个变量不是私有的,往上级作用域链查找。
私有变量的概念
-
形参
-
var或function声明的变量
var a=12,b=13,c=14;
function fn(a){
console.log(a,b,c);
var b=c=a=20;
console.log(a,b,c);
}
fn(a);
console.log(a,b,c);
私有变量练习题
var arr=[12,23]
function fn(arr){
console.log(arr); // [12, 23]
arr[0]=100;
arr=[100];
arr[0]=0;
console.log(arr); // [0]
}
fn(arr);
console.log(arr); // [100, 23]
上级作用域的查找
和它在哪执行的没关系,只跟它在哪创建(定义)的有关系。
var a=12;
function fn(){
console.log(a);
}
function sum(){
var a=120;
fn();
}
sum(); // 12
典型例题
私有作用域的n和全局作用域的没有关系,两个字:闭包。
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);
堆栈内存&闭包
堆栈内存的概念
堆内存:
堆内存能不能被销毁,就看它有没有被占用。2个堆内存,fn;f、x。让堆内存销毁,让引用它的变量为null。
栈内存:
全局栈内存页面关闭才销毁。函数栈内存一般情况下代码执行完毕即销毁了。(全局作用域:刷新页面 销毁原来的作用域形成一个新的全局作用域。)
但是栈内存的某个东西被栈内存以外的空间占用了。
堆栈内存有一个隶属关系。栈内存销毁其中的堆内存也跟着销毁了。
var i=1;
function fn(i){
return function(n){
console.log(n+(++i));
}
}
var f=fn(2);
f(3);
fn(5)(6); // 这里会形成一个全新的独立的fn作用域
fn(7)(8);
f(4); // 8
闭包的作用
函数执行形成的私有作用域的保护机制:闭包。
-
保护自己的私有变量不受外界干扰,保护机制
-
保存。形成一个不销毁的栈内存,把私有变量保存起来供以后调用。因为i那个值就一直被保存下来了。
题外话
闭包
概念
理论模型:函数执行形成一个私有作用域,保护里面私有变量不受外界干扰,这种保护机制称之为闭包。
形成一个不销毁的私有作用域(栈内存)叫做闭包
// 闭包:柯里化函数思想
function fn(){
// 这里return一个function
// 里面返回的堆内存被外边占用了
return function(){
}
}
// 并且将来外面有一个f=fn(),返回的函数被f占用
var f=fn()
/**
* 高阶编程技巧
* 都是利用形成一个不销毁的栈内存
*/
// 闭包:惰性函数
// 也叫高级单例模式
var utils=(function(){
return {
}
})();
所以为了性能优化,应该尽可能减少闭包的使用
一个闭包:一个不销毁的堆和一个不销毁的栈,
一些面试题
闭包 OOP的理解 js异步编程 promise原理 async/await es6新语法
js中dom事件机制
1.保护作用
-
为了防止全局变量过多,让自己的部分放到一个闭包里面,使其成为私有变量。
-
有些东西要提供给别人用
-
在闭包中(大部分保护起来)暴露一些方法供外部调用,通过window. 设置属性的方式暴露出去。
-
基于return返回。这种类似于单例模式
闭包的保护作用:
形成一个私有作用域,保护里面私有变量不受外界干扰,这种机制叫闭包。
把自己写的代码放到一个闭包里面,开发类库、插件时,该保护。
2.保存
传统的es中,判断和循环并不会产生任何作用域。
从异步的角度去讲:
-
为element添加自定义属性
-
闭包方式:
在每次循环时,我们都让其形成一个不销毁的私有作用域,把后面需要用到的 i 的索引值,先保存到不销毁的私有作用域中,之后用到的上级作用域即自执行函数。
原理都是形成3个不销毁的私有作用域,分别存储需要的索引值
var liList=document.getElementsByTagName('li');
console.log(liList);
for(var i=0;i<liList.length;i++){
// (function(i){
// liList[i].onclick=function(){
// console.log(i);
// }
// })(i)
liList[i].onclick=(function(i){
return function(){
console.log(i);
}
})(i)
}
-
基于es6来创建的变量
基于es6语法渲染的,循环3次,形成3个块级作用域,每个块级作用域中都有一个独立的i
var liList=document.getElementsByTagName('li');
for(let i=0;i<liList.length;i++){
liList[i].onclick=function(){
console.log(i)
}
}
总结:
闭包的作用——保存,形成一个不销毁的私有作用域,把我以后需要用到的索引保存起来,以后用的时候直接向上查找找到就行。
插入块级作用域知识点
基于let创建的变量是存在块级作用域的
作用域(栈内存):
-
全局作用域
-
私有作用域 <= 函数执行形成
-
块级作用域
现在可以笼统地理解为,块级作用域就是一种私有作用域,里面的变量是受保护的,没有也会向上查找。
let a=10;
{
let a=100;
{
{
console.log(a); //VM15340:13 Uncaught ReferenceError: Cannot access 'a' before initialization
}
let a=200; // 代码执行前有词法解析
}
}
循环、判断体都有块级作用域
形成了5个块级作用域,每一轮循环都会形成一个单独的块级作用域,每个块级作用域中都有一个私有变量 i ,变量值就是每一次循环 i 的值
for循环也是个块级作用域,循环几次就会形成几个块级作用域,而每个块级作用域里面都有自己独有的变量,而变量值就是当前循环循环的值。5个独立分开的块级作用域