JavaScript引擎怎么执行JS代码

发布时间:2022-03-29 12:14:17 作者:小新
来源:亿速云 阅读:234

这篇文章主要为大家展示了“JavaScript引擎怎么执行JS代码”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JavaScript引擎怎么执行JS代码”这篇文章吧。

JS代码的运行

我们知道了js是弱类型语言,在运行时才确定变量类型。js引擎在执行js代码时,也会从上到下进行 词法分析语法分析语义分析 等处理,并在代码解析完成后生成AST(抽象语法树),最终根据AST生成CPU可以执行的机器码并执行。

除此之外,JS引擎在执行代码时还会进行其它处理,如 V8 中还有两个阶段:

这就引出了两个概念:“执行上下文” 和 “作用域链”。


JavaScript执行上下文

由上面我们可以知道:当js代码执行一段可执行代码时,会创建对应的执行上下文。
首先,js中可执行代码对应着有一个概念:“执行环境” —— 全局环境、函数环境 和 eval
其次,对于每个执行上下文,都有三个重要属性:

我们来看两段代码:

var scope="global scope";function checkscope(){
	var scope="local scope";
	function f(){
		return scope;
	}
	return f();}checkscope();
var scope="global scope";function checkscope(){
	var scope="local scope";
	function f(){
		return scope;
	}
	return f;}checkscope()();

它们会打印什么?
JavaScript引擎怎么执行JS代码

为什么?答案是它们的执行上下文栈不一样!

什么是“执行上下文栈”?
当执行一个可执行代码时,就会提前做准备工作,这里的“准备工作”,专业的说法就是“执行上下文”。但随着可执行代码如函数的增多,如何管理那么多的执行上下文呢?所以JS引擎创建了执行上下文栈的概念。
我们完全可以用数组去模拟其行为(栈底永远有一个全局执行上下文globalContext)

我们定义一个EStack,首先

EStack=[globalContext];

然后来模拟第一段代码:

EStack.push(<checkscope> functionContext);EStack.push(<f> functionContext);EStack.pop();EStack.pop();

而第二段代码是这样的:

EStack.push(<checkscope> functionContext);EStack.pop();EStack.push(<f> functionContext);EStack.pop();

究其原因,你可能需要先研究一下“闭包”的概念了!

这里顺便说下“在前端模块化”中怎么实现“长时间保存数据”?
缓存?不。闭包!


JavaScript作用域和作用域链

首先,作用域是指程序中定义变量的区域。作用域规定了如何查找变量,也就是确定了当前执行代码对变量的访问权限。
作用域有两种:静态作用域动态作用域
JS采用的静态作用域,也叫“词法作用域”。函数的作用域在函数定义的时候就确定了。

由上,词法作用域中的变量,在编译过程中会产生一个确定的作用范围。这个作用范围即“当前的执行上下文”。在ES5后我们用“词法环境”替代作用域来描述该执行上下文。词法环境由两个成员组成:

我们依然来看一个例子:

var value=1;function foo(){
	console.log(value);}function bar(){
	var value=2;
	foo();}bar();

回看上面的定义,该打印什么?

JavaScript引擎怎么执行JS代码

让我们分析下执行过程:
执行foo()函数,先从foo函数内部查找是否有局部变量value。如果没有,就根据定义时的位置,查找上面一层的代码,也就是value=1.所以结果会打印1。

这里面当然不是如此简单能概括的,你可以从执行上下文的角度分析一下。

建立作用域链

上面我们说了词法环境(作用域)的两个组成。再结合执行上下文,我们不难发现:通过外部词法环境的引用,作用域可以顺着栈层层拓展,建立起从当前环境向外延伸的一条链式结构。

再来看一个例子:

function foo(){
	console.dir(bar);
	var a=1;
	function bar(){
		a=2;
	}}console.dir(foo);foo();

由静态作用域,全局函数foo创建了一个自身对象的 [[scope]] 属性

foo[[scope]]=[globalContext];

而当我们执行foo()时,也会先后进入foo函数的定义期和执行期。在foo函数的定义期时,函数bar的 [[scope]] 将会包含全局内置scope和foo的内置scope

bar[[scope]]=[fooContext,globalContext];

这证明了这一点:“JS会通过外部词法环境引用来创建变量对象的一个作用域链,从而保证对执行环境有权访问的变量和函数的有序访问。”

让我们再回头看看执行上下文中的那道题,在前面我们说了它们有什么不同,这里说下为什么它们相同地打印了“local scope”:还是那句话“JS采用的是词法作用域,函数的作用域取决于函数创建的位置” —— JS函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量scope一定是指局部变量,不管何时何地执行 f() ,这种绑定在执行 f() 时依然有效。

基于作用域链的变量查询

当某个变量无法在自身词法环境记录中找到时,可以根据外部词法环境引用向外层进行寻找,直到最外层的词法环境中外部词法环境引用为null
与此相似的是“对象中基于原型链的查找”:

它们的区别也显而易见:原型链是通过 prototype 属性建立对象继承的链接;而作用域链是指内部函数能访问到外部函数的闭包。不管直接还是间接,所有函数的作用域链最终都链接到全局上下文。

以上是“JavaScript引擎怎么执行JS代码”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. rundll32执行js代码&Win32/Poweeliks
  2. java 脚本引擎Rhino执行js代码和文件

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript

上一篇:jquery内div中能不能添加元素

下一篇:python正则表达式相关知识有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》