- 全局执行上下文:只在首次运行js时候产生一个全局执行上下文。浏览器中,this直接指向window对象的属性和方法。var声明的变量都挂载在window上,可以用window直接调用。
- 函数执行上下文:可以有多个,每次函数被调用都会产生一个函数执行上下文,每次同一个函数被调用都会创建一个新的函数执行上下文
- 执行栈:存储代码执行期间的所有执行上下文,有LIFO后进先出的特性
- 执行上下文的执行过程
- 执行上下文的创建阶段
- this的绑定
- 全局执行上下文:浏览器环境,this直接指向window
- 函数执行上下文:
- 被对象调用:指向此对象a.fun() this=> a
- 严格模式:this=>unfined
- 非严格模式:this=>window
- 创建词法环境组件:包含标识符变量映射的结构,这里的标识符是表示变量,函数的名称,变量是对实际对象【函数类型对象】或者原始值得引用
【fun和它对应得的存储位置】- 环境记录:用于存储当前环境中的变量和函数声明的实际位置
- 外部环境引入记录:保存自身环境和可以访问的其他外部环境
- 函数词法环境组件包含函数中定义的所有属性,方法和arguments对象,
执行栈的运行方式,后进先出
消息队列:事件循环的运行方式,先进先出
js数据存储,基本数据类型放在栈中,引用类型数据结构放在堆中,常量存放在常量池也是在栈中,闭包函数的变量在堆中存储
- 创建变量环境组件
和词法环境一样,es6中唯一区别是:
let和const是属于词法环境声名的变量
var是属于变量环境声明的变量
- this的绑定
- 执行上下文的执行阶段
变量如果有值直接赋值,没有值let和从身体就被设置成undefined
- 执行上下文的创建阶段
- 举例
-
bar在执行上下文创建阶段创建一个全局变量,设置值为unfined,执行到重新赋值之前都是undefined(function(){ console.log(bar); console.log(baz); var bar = 20; function baz(){ console.log("baz"); } })()
-
(function(){ console.log(bar); console.log(baz); bar = 20; console.log(window.bar); console.log(bar); function baz(){ console.log("baz"); } })()
-
function(){ console.log(foo); console.log(bar); console.log(baz); var foo = function(){}; function bar(){ console.log("bar"); } var bar = 20; console.log(bar); function baz(){ console.log("baz"); } })()
-
变量提升
/*变量提升*/ foo; // undefined var foo = function () { console.log('foo1'); } foo(); // foo1,foo赋值 var foo = function () { console.log('foo2'); } foo(); // foo2,foo重新赋值
-
函数提升
foo(); // foo2 function foo() { console.log('foo1'); } foo(); // foo2 function foo() { console.log('foo2'); } foo(); // foo2
-
声明的优先级 函数>变量
foo(); // foo2 var foo = function() { console.log('foo1'); } foo(); // foo1,foo重新赋值 function foo() { console.log('foo2'); } foo(); // foo1
-
var a = {n: 1}; var b = a; a.x = a = {n: 2}; /* a.x = {n:2} a = {n:2} */ console.log(a.x) console.log(b.x)
-
在执行上下文创建阶段,var被设置成undined变量提升,function被设置成自身,函数声明提升,var和const设置成未初始化,不会产生变量提升