0 / 题
(1)第一题
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b);
△ 引用数据类型:object
(2)第二题
var x = [12, 23];
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x);
console.log(x);
△ 引用数据类型:function
这些题是不是很简单?我们主要看逻辑:
1 / 引用数据类型:object
在Web浏览器中执行JS代码,会开辟一块栈内存来作为执行环境:ECStack
(Execution Context Stack)
会开辟一块栈内存供全局代码执行:全局执行上下文 EC(G)
(Execution Context Global),还有其他的上下文:函数私有执行上下文、块级私有上下文…… 自己管好自己那一摊的代码执行内容
形成的执行上下文都会 进栈 到执行环境栈中运行.私有上下文会在不被占用时出栈释放,浏览器的回收机制GC
.当浏览器关闭时,全局执行上下文就会出栈释放了
△ 图2.1_第一题,简图
GO:全局对象 Global Object ,并不是VO(G)全局变量对象 Variable Object Global
全局对象,它是个对象,它就是个堆内存,浏览器打开一加载页面就默认开辟的堆内存。
浏览器提供的一些供JS调用的API,在Web浏览器中,全局对象可以通过window
来访问的
注意:运算符优先级,要多看看多比划比划
注意:基本数据类型值直接存储在栈内存中,引用数据类型值存在堆内存中
2 / 引用数据类型:function
var x = [12, 23];
function fn(y) {
y[0] = 100;
y = [100];
y[1] = 200;
console.log(y);
}
fn(x);
console.log(x);
△ 函数执行
(1)第二题,简图
△ 图2.2_函数执行
△ 图2.3_数组的格式:键值对
(2)创建函数
创建函数的步骤:【和创建变量区别不是很大,函数名就是变量名】
① 单独开辟一个堆内存:16进制地址,函数堆内存中存储的是函数体中的<u>代码字符串</u>
② 创建函数的时候,就声明了它的作用域[[scope]],也就是所在的上下文环境
③ 把16进制地址(16进制以0x
开头)存放到栈中,供函数名变量名关联引用即可
只创建函数,不执行函数,没啥意义,那就是一堆字符串。
函数执行的目的:把创建函数的时候在堆内存中存储的 <u>代码字符串</u> 变为代码执行
代码执行一定会有一个执行的环境,它的上级执行上下文,是函数创建的地方
函数执行会形成一个全新的、私有的执行上下文,在私有上下文中,也有存放自己变量的对象:AO(Active Object 活动对象),它是VO的一种。
变量对象: ① 在全局上下文中:VO ② 在私有上下文中:AO
实参都是值。形参是变量。
fn(x)
:执行函数fn,把全局上下文中存储的x
变量关联的值(0x000001),作为实参传递给函数的形参变量
(3)执行函数
执行函数做了哪些事情:
1、形成了一个全新的、私有的执行上下文EC(xxx)
2、当前私有的上下文中,有一个存放此上下文内声明的变量的地方 AO(xxx)
私有变量对象
① 形参变量
② 当前上下文中声明的变量
3、进栈执行
4、代码执行之前还要处理很多事情:
① 初始化作用域链
[[scope-chain]]:<当前自己的上下文, 上级上下文(创建函数时形成的作用域)>
(作用域链有两头,一头是自己执行的上下文,另一头是自己创建时所在的上下文)
即:当前函数的上级上下文是创建函数所在的上下文,就是作用域
以后再遇到函数内的代码执行,遇到一个变量,首先看是否为自己上下文中的私有变量(看AO中有没有,有,是自己私有的;没有,不是自己私有的)。如果是私有的变量,则当前变量的操作和外界环境中的变量互不干扰(没有直接关系);如果不是自己的私有变量,则按照作用域链,查找是否为其上级上下文中的私有变量.....一直找到EC(G)全局上下文为止:作用域链查找机制
② 初始化this....
③ 初始化arguments....
④ 形参赋值:形参都是私有变量,放在AO中的。如果不传递实参,默认值是undefined
⑤ 变量提升....
5、代码自上而下执行
6、.....
7、一般情况下,函数执行所形成的私有上下文,进栈执行完后,会默认出栈释放掉
【私有上下文中存储的私有变量和一些值都会被释放掉,目的:为了优化内存空间,减少栈内存的消耗,提高页面或者计算机的处理速度......】
不能出栈释放:当前上下文中某些内容(一般是堆内存地址)被当前上下文的外部的事物占用了,则无法出栈释放。一旦被释放,后期外部事物就无法找到对应的内容了
注意: 多次函数执行,会形成多个全新的、私有执行上下文,这些上下文之间没有直接的关系
(4)闭包
一般,很多人认为:大函数返回小函数是闭包。
这只是闭包机制中的一种情况。
闭包:函数执行形成一个私有的执行上下文,此上下文中的私有变量,与此上下文以外的变量互不干扰;也就是当前上下文把这些变量保护起来了,我们把函数的这种保护机制称为闭包。
闭包不是具体的代码,而是一种机制。
一般情况下,形成的私有上下文很容易被释放掉,这种保护机制存在时间太短了,不是严谨意义上的闭包。有人认为,形成的上下文不被释放,才是闭包。此时,不仅保护了私有变量,而且这些变量和存储的值也不会被释放掉,保存起来了。
闭包的作用:① 保护 ② 保存
利用闭包的两个作用,可以实现高阶编程技巧,以后再说~
3 / 练习题
(1)第一题
var x = 100;
function fn() {
var x = 200;
return function(y) {
console.log(y + x++);
}
}
var f = fn();
f(10);
f(20);
△ 第一题
i++
后加
△ 图2.4_后加
(2)第二题
let a=0,
b=0;
function A(a){
A=function(b){
alert(a+b++);
};
alert(a++);
}
A(1);
A(2);
△ 第二题
(3)第三题
let x = 5;
function fn(x) {
return function(y) {
console.log(y + (++x));
}
}
let f = fn(6);
f(7);
fn(8)(9);
f(10);
console.log(x);
△ 第三题
- end -
好啦,好啦,碎碎念了很多:
全局执行上下文、创建函数、作用域、执行函数、私有执行上下文、AO和VO、实参、形参、作用域链
△ 图2.5_练习题,第一题
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。