js作用域链&堆栈内存&闭包

私有变量和全局变量

作用域:一块栈内存,目的是为了给代码执行提供环境

闭包:形成私有作用域可以保护里面的私有变量不受外界干扰,这种保护机制可以理解为闭包。当我们函数执行,有个地儿把变量存起来,以后想要从这里拿出来这种机制叫做闭包,柯里化函数编程思想。

让私有变量和外界隔离开来,保护起来。

如果这个变量不是私有的,往上级作用域链查找。

私有变量的概念

  1. 形参

  2. 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

闭包的作用

函数执行形成的私有作用域的保护机制:闭包。

  1. 保护自己的私有变量不受外界干扰,保护机制

  2. 保存。形成一个不销毁的栈内存,把私有变量保存起来供以后调用。因为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.保护作用

  1. 为了防止全局变量过多,让自己的部分放到一个闭包里面,使其成为私有变量。

  1. 有些东西要提供给别人用

  1. 在闭包中(大部分保护起来)暴露一些方法供外部调用,通过window. 设置属性的方式暴露出去。

  1. 基于return返回。这种类似于单例模式

闭包的保护作用:

形成一个私有作用域,保护里面私有变量不受外界干扰,这种机制叫闭包。

把自己写的代码放到一个闭包里面,开发类库、插件时,该保护。

2.保存

传统的es中,判断和循环并不会产生任何作用域。

从异步的角度去讲:

  1. 为element添加自定义属性

  2. 闭包方式:

在每次循环时,我们都让其形成一个不销毁的私有作用域,把后面需要用到的 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)
}

  1. 基于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创建的变量是存在块级作用域的

作用域(栈内存):

  1. 全局作用域

  2. 私有作用域 <= 函数执行形成

  3. 块级作用域

现在可以笼统地理解为,块级作用域就是一种私有作用域,里面的变量是受保护的,没有也会向上查找。

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个独立分开的块级作用域

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值