持续输出js第3篇-(数据渲染机制和闭包作用域)

677 阅读4分钟

思考问题:

一般都把js放在body末尾

1,为什么?

2,放在head可以吗?怎样才可以放到head中和放到body末尾一样效果?

3,script标签有两个属性:defer/async,这两个属性是做什么的?

评论区找答案,帮忙解决?

数据渲染机制

var a =12;

1.先声明-一个变量a,没有赋值(默认值是undefined)
2.在当前作用域中开辟- -个位置存储12这个值
3.让变量a12关联在- -起(定义:赋值)

当浏览器加载页面(加载js代码)的时候,首先会形成一个全局作用域window,提供代码之上而下执行的环境。

当 ary1=null(空对象),ary2=null,那么那个堆就不被谁占用了,也就可以回收了。

栈内存:作用域

1.提供-个供JS代码自上而下执行的环境(代码都是在栈中执行的)

2.由于基本数据类型值比较简单,他们都是直接在栈内存中开辟;一个位置,把值直接存储进去的

=>当栈内存被销毁,存储的那些基本值也都跟着销毁了

堆内存:引用值对应的空间

1.存储引用类型值的(对象:键值对函数:代码字符串)= >当前堆内存释放销毁,那么这个引用值彻底没了

=>堆内存的释放:当堆内存没有被任何的变量或者其它东西所用,浏览器会在空闲的时候,自主的进行内存回收,把所有不被占用的堆内存销毁掉(谷歌浏览器)

执行过程:作用域形成->栈内存/堆内存形成->代码执行

变量提升机制

在当前作用域形成之后,js代码自上而下执行之前,浏览器首先会把所有带var,function关键词的变量进行提前的声明或者(声明和定义)

过程:

1 2

图解浏览器数据渲染过程 注意: 只有function类型才可以在变量提升阶段进行赋值,其他不行,包括数组

私有作用域里的私有变量和外边没关系,这就是闭包

ES6中let不存在变量提升!

老套的变量提升机制(es2,es3)不严谨,你在上面提升的地方能用,下面也能用,不严谨,也不方便维护。

ES6语法:

ES6切断了全局变量和window属性的映射机制

在相同作用域中,基于let不能声明相同名字的变量,会报错,还没执行代码就会报错

第一行报错:

一个小案例: 结果:

20 20
10 20

没有let和const就和ES6没有关系

在代码中同时有老语法和新语法的时候,浏览器会自己识别,然后分别用老机制和新机制

闭包作用域

两道题区分全局作用域和私有作用域

例题1: 函数内部执行过程(首先形成私有作用域)

1,形参赋值
a=12
2,变量提升
var b;

记住哈,是先形参赋值

=>在私有作用域中,只有以下两种情况是私有变量
1:声明过的变量(带VAR/FUNCTION) 
2:形参也是私有变量
剩下的都不是自己私有的变量,都需要基于作用域链的机制向上查找

重点:形参也是私有变量

结果:

b是undefined,是因为首先b是私有变量,然后它用的是老语法,所以按照变量提升,私有作用域第一行打印时还没有赋值。

形参也是私有变量,所以a是私有变量

而不是私有变量的c会去升一级作用域找。

例题2: 图解: 函数里面的ary是形参变量,是私有变量,虽然它和外面那个ary名字一样,所指向的地址也一样,但是它们不是同一个变量。。

无变量提升

ary=[100]是一个新数组,开辟一个新的堆内存。此时私有变量指向这个新的堆内存 而且一个变量只能指向一个空间,所以,

结果:

寻找上级作用域

两道题搞懂寻找上级作用域

例题1:

结果:

12

哈哈,没想到吧?居然是这样的

原因:一个函数函数在执行前,形成一个私有作用域A,A的上级作用域和函数在哪里执行没有关系,只和它在哪里创建有关系

一个知识点-了解即可(现在js开发是严格模式,不让用了)

arguments:实参集合
arguments. callee:函数本身FN
arguments. callee. caller:当前函数在哪执行的, CALLER就是谁(记录的是它执行的宿主环境)

比如:

可以看到打印的就是fn()的宿主环境

全局下执行,caller的结果是null

例题2: 结果:21,22,23,10

var x =fn()其实就是在执行fn(),执行打印了21,然后顺便返回了f()的地址给x

所以,下两步的x()都指向f

画图分析: