我们知道,一个前端项目的搭建,三个模块必不可少。分别是搭建结构的HTML、控制展示样式的CSS、控制事件触发的JS。那么浏览器如何运行我们的代码,我们的代码在浏览器中又是存放在哪里。为什么我们可以使用
console、setTimout等这些API呢。本文简单介绍一些基础的JS概念。
-
总括:浏览器想要运行我们的代码,就需要在自身的内存中开辟一块内存空间,供代码存放。然后在这些代码事件中,我们可以调用一些浏览器提供的属性方法。当一切环境准备好后,就开始代码运行,而运行时的区域肯定是一个独立的执行上下文,该上下文只能放到栈中执行,所以会存在 进栈 和 出栈的过程。当出栈后,说明代码运行结束,正常来说出栈后,所有的属性、状态、方法将会销毁,但是也存在一些特例,这里后面来说。
-
执行环境栈[ESStack]: 浏览器想要运行JS代码,就需要为其提供一个执行的环境空间,这个空间是一个栈内存。它主要的作用是:
- 提供JS代码执行环境
- 存储基本数据类型值【基本类型和引用类型堆地址】
-
全局对象[GO]: 我们之所以能调用浏览器的一些属性和方法,是因为浏览器将这些内置的属性方法,存放在一个独立的内存中,这个内存是堆内存。我们将这些存放这些内容的叫做 全局对象GO
- 注意:在浏览器端,它是让 window 指向GO的,所以可以理解为 浏览器的window指向就是全局对象
-
执行上下文[EC]: JS代码在运行时,所处的环境叫做执行上下文
- 全局执行上下文
- 函数调用会创建独立的私有上下文
- 块级执行上下文
- ....
-
变量对象[VO]: 在当前上下文中,肯定存在有变量、值这些内容。我们将在当前上下文中存放变量和所对应值的位置,叫做变量对象[VO].函数执行存在私有上下文,在这个私有上下文中的存放变量值的地方叫做 活动对象AO
示例解析
var a = 12, b = a; b=14;
console.log(a);
--------
var a={m: 12},b=a; b['m']=33;
log(a);
-------
var a={m: 12},b=a; b={m:33};
log(a);
注意点
- 基本数据类型的值,是直接存放在栈内存中,引用类型的值首先会开辟一个堆内存,然后将引用值存放进入,最后将堆内存地址放置到栈内存中,让其变量名和值(地址)进行关联指向
- 在JS中,赋值的操作分为三步:第一步创建值(地址);第二步创建变量名称;第三步将两者进行关联,实现指针指向
var a = 12, b = a; b=14;
console.log(a);
代码在全局执行上下文中执行EC[G];
开辟全局变量对象 VO[G], 存放全局变量
a -----> 12; b------> 12;
b=14 ----> b------> 14
结果为 14;
var a={m:12},b=a; b['m']=33;
log(a);
创建全局执行上下文 EC[G]
开辟全局变量对象VO[G],存放全局变量信息,引用类型存放 堆内存名称
{m:12} ----> 创建堆内存,存放字符串,该堆名称 (AAAFFF000)
a ----> AAAFFF000 b ----> AAAFFF000;
b['m'] ---> 更改堆内存中的内容,但是堆内存没变。 此时m: 33
结果为 AAAAFFF000 ----> {m: 33}
var a={m: 12},b=a; b={m:33};
log(a);
创建全局执行上下文 EC[G]
开辟全局变量对象VO[G],存放全局变量信息,引用类型存放 堆内存名称
{m:12} ----> 创建堆内存,存放字符串,该堆名称 (AAAFFF000)
a ----> AAAFFF000 b ----> AAAFFF000;
b={} ---> 创建一个新堆内存,将对象内容放到这个新堆中,堆名 (AAAFFF111).
此时 b和a 指向的地址不是一个地址
结果为 AAAAFFF000 ----> {m: 33}
问个问题?
以下代码,处理执行结果是什么?为毛是这样
var obj = {
name: 'wj';
fn: (function(x) {
return x + ' 山西';
})(obj.name)
}
console.log(obj.fn);