作用域
什么是作用域呢?通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。在javascript中作用域有以下几种:
1.函数作用域
2.全局作用域
我们用一张图来看一下
图片中我们清楚地可以看到全局作用域代码产生时就会出现,而函数作用域是在函数体内部的。
3.块级作用域
说到块级作用域就需要我们知道其实js在2015年进行了一次更新,出现了let,const 定义变量的语法,而块级作用域的出现就需要let和const定义一个变量再加上一个{},举个简单的例子:
for(let i=0; i<10; i++){}
在这里其实就形成了快级作用域。
注意
内层作用域可以访问外层作用域的,反之则不可以;举个例子:
我们可以清楚地看到全局作用域被函数作用域给访问了,而反过来就不可以。
作用域链
相信看到这里大家应该都了解了作用域,那什么是作用域链呢?
在这之前我们应该先要理解一个概念:运行期上下文:指的是当函数执行时,会创建一个称为执行期上下文的内部对象,简称AO:{};多次调用就会多次创建,当函数执行完毕就会销毁。
当然全局也有内部对象,简称GO:{}
还有点抽象?我们来看代码:
function a() {
function b() {
var b = 2
}
var a = 1
b()
}
var glob = 100
a()
//a 定义 产生全局内部对象 ---> 0 : GO{}
//a 执行 产生函数内部对象 ---> 0 : AO{} 1: GO{}
内部对象里面有什么呢?看图:
函数a定义时会产生一个全局作用域[[scope]],全局作用域里面有全局对象,包括定义的数值。
当a执行时,看图:
a执行会产生一个执行期上下文的内部对象AO:{},它会挤在GO:{}的前面。
而作用域链就是[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,故叫做作用域链。
预编译
声明提升
1.在编译时,将变量的声明,提升到当前作用域的顶端
console.log();
var a = 1
此段代码在编译时相当于
var a
console.log()
a = 1
打印的结果都为undefined。
2.函数声明整体提升
同样函数的声明函数整体都会提升
foo();
function foo() {
var a = 2;
console.log(a);
}
相当于
function foo() {
var a = 2;
console.log(a);
}
foo();
都能打印出结果为2。
函数执行之间(四部曲)
- 创建一个AO对象
- 找形参和变量声明,将变量声明和形参作为AO的属性名,值为underfined
- 将实参和形参统一
- 在函数体内找函数声明,将函数名作为AO对象的属性名,值赋予函数体
我们来看下面的代码,分析它的函数执行之前:
var a = 1;
function foo(a) {
var a = 2;
function a() { }
var b = a
console.log(a);
}
foo(3);
当foo函数要执行时
第一步:产生一个执行上下文对象AO:{}
第二步:形参为a,变量声明有a和b作为属性名,值为undefined。此时
AO:{a: undefined, b: undefined}
第三步:实参为3,为a的值 AO:{a: undefined 3 , b: undefined}
第四步:有函数声明a,值赋予函数体AO:{a: undefined 3 function(){} , b: undefined}
之后再执行函数,最终:AO: {a: undefined 3 function a() { } 2, b: undefined 2}打印出来a的值为2。
全局执行(分三步)
- 创建一个GO对象
- 找变量声明,将变量声明作为GO的属性名,值为undefined
- 在全局找函数对象,将函数名作为GO的属性名,值赋予函数体
综合上面讲到的知识,我们再来分析一下下面代码:
global = 100
function fn() {
console.log(global);
global = 200
console.log(global);
var global = 300
}
fn()
var global;
首先声明提升,创建一个GO:{}
接下来找变量声明,全局下有global,GO:{global:undefined}
然后找函数对象,全局下有fn函数,GO:{global:undefined, fn: function(){}}
最后执行函数调用又回到了函数执行之前的四部曲
这里简略一下得出AO: {global: undefined 200 300}}
第一个console.log()打印出undefined,第二个打印出200 。
小结
JS代码到浏览器里去执行时,V8引擎会按照自己的规则将JS编译执行,通过学习作用域,作用域链和预编译让我们对V8引擎怎样运行JS清楚了,本文可能存在不足,欢迎大佬批评指正。