-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
原来JavaScript内部是这样运行的 #1
Comments
这个地方baz到底是怎样的?
这里baz不应该是undefined吗?相同名字的变量和函数,函数会声明前置,这个地方是覆盖baz吗?博主,能解下疑惑吗? |
是的,你说的没错,函数的优先级高于var变量声明,所以函数声明的标识符baz会覆盖变量声明的标识符baz,值初始化为函数的引用。 |
博主,你的意思是,在这个变量对象中,有两个baz,但是函数声明的baz优先级高,所以console输出的话就会输出函数的声明?这样理解对吗? |
是的,如果把这些js重要的知识理解了,你就会发现以前理解不了的代码,瞬间都懂了,而且写出来的代码会越来越优雅。这个项目我会把js进阶的知识全部写出来,只要跟着读下去,相信你的js水平会发生质的改变。还望推荐给你的小伙伴,让我们一同进步。。。 |
谢谢,会一直关注的 |
写得很深入,受益匪浅 |
function foo() {
} foo(); VO(foo) = { 这里我认为涉及到函数声明与函数表达式的一个优先级关系,解析器在遇到函数声明时会将其提升到一个更高的优先级进行解析,function baz(){}就是一个函数声明,所以即使放在靠后的位置,解析器也会优先解析,但如果是 var baz = function(){},这时执行结果就会是undefined了 |
function foo() {
} foo(); 这里有个疑问,不知道博主有没有试过上面的代码中 console.log(baz);的打印,执行完,打印的是 1。也就是说变量baz覆盖了函数baz |
@AquariusBaby 兄弟,你这个问题提的很好,很细心,给你点赞! 举个不恰当的例子:
大概意思就是这样。。。。 |
谢谢,最开始还不是很理解! function foo() {
}
} |
通透~~~ |
函数的优先级高于变量,这点没错,但是当遇到同名的变量声明时,后面的变量的声明会被忽略,不是覆盖吧,你上面是不是说反了? |
遇到同名变量时,后面的同名变量声明会覆盖之前的函数的。 |
函数也有声明提前,打印的地方不一样哦 |
感谢楼主,很有用,很喜欢。。。 |
你好。贵公司邮件已查收,一到两个工作日内完成初审。初审通过后,我会电联申请表联系人。谢谢。刘工
|
🐬🐬 欢迎评论和star 🐳🐳
天气渐渐转暖了,树渐渐露出了枝芽,小河也欢快的向前流着,感觉大地充满了生命力,好开心 😄😄😄
附上美图一张
小伙伴们,我们也出来活动活动筋骨,迎接我们2018年的春天。
今天我们说说JS执行流程,现在我们先暂且不考虑异步的情况。
如果你把下面的内容都吃透,那你就会发现JS内部是多么精彩的一个世界。
还等什么,go...
编译阶段
词法分析(Lexing)
简单举个例子:c = b - a 转换为
语法分析(Parsing)
AST大概是下面的样子:
生成可执行代码
执行阶段
接下来,我们以一个简单例子进行分析。
1. JS引擎创建一个全局对象(Global Object)
这个对象全局只存在一份,它的属性在任何地方都可以访问,它的存在伴随着应用程序的整个生命周期。全局对象在创建时,将Math,String,Date,document 等常用的JS对象作为其属性。由于这个全局对象不能通过名字直接访问,因此还有另外一个属性window,并将window指向了自身,这样就可以通过window访问这个全局对象了。用伪代码模拟全局对象的大体结构如下:
2. JS引擎会创建一个执行环境栈(Execution Context Stack)
提到栈,小伙伴们都知道,栈是一种类似羽毛球筒存储羽毛球的数据结构,采用先进后出,后进先出的特点。
上图中的羽毛球1一定是先放入栈中,然后是羽毛球2,以此类推,而出栈时,一定是羽毛球5先拿出来,然后是羽毛球4,以此类推,这种方式和栈存取数据的方式如出一辙。
堆数据类型类似与书架。书虽然也整齐的存放在书架上,但是我们只要知道书的名字,我们就可以很方便的取出我们想要的书。
好了好了,扯远了。我们接着往下说,在这只需知道执行环境栈是怎样存取数据的就行。
3. 创建全局执行上下文(Execution Context)
到这你可能会问,上下文是个啥玩意?
是啊,上下文是个什么鬼啊?
上下文不是玩意,也不是什么鬼。
执行上下文可以理解为当前代码的执行环境。JS所有代码都会在自己的上下文环境下运行。
说到上下文,你可能会有这样的疑惑:上下文不就是作用域吗?
老铁,我肯定的告诉你,上下文不是作用域。的确,在JS里,这还真是个很难区分的东东。不过现在我还不能马上道出他们的区别,因为作用域的知识,我们还没有涉及,👉彻底搞懂JavaScript作用域,通过这篇文章,你将彻彻底底了解关于作用域的一切。
那在JS中会有几种执行环境呢?
大概有3种:
因此在一个JavaScript程序中,必定会产生多个执行上下文。
go on...
4. 全局上下文推入执行环境栈底
5. 代码开始从上往下执行,这里我们暂且不谈标识符处理,当代码执行到bar(),生成bar执行上下文,推入栈中
6. 代码执行到foo(),生成foo执行上下文,推入栈中
7. foo()执行完,foo执行上下文出栈
8. bar()执行完,bar执行上下文出栈
9. 全局上下文执行上下文出栈
我们用图走一下js执行流程,是这样的:
小伙伴们,现在是不是对JS执行流程有了一个整体认识,下面我们来说点更有意思的。
上下文执行细节
我们先看整体了解下
创建阶段
1. 创建变量对象(Variable Object)
创建变量对象,依次经历了以下几个步骤
变量提升
看到这,我觉得你对变量提升具体是什么以及如何实现的应该了解的一清二楚了。
是不是呢?
我们来一道题测试下
第一处是undefined,第二处是[Function: baz],是不是很简单?
下面我用代码简单模拟下上面的过程
变量对象大概是这样的
2. 确定作用域链
作用域链是由当前作用域与上层一系列父级作用域组成,作用域的头部永远是当前作用域,尾部永远是全局作用域。作用域链保证了当前上下文对其有权访问的变量的有序访问。
我们先简单了解下,详细的我们会在彻底搞懂JavaScript作用域中谈到。
上面的对于我们来说很简单,是吧?没错这就是作用域链的应用。
我们简单模拟下
3. 确定this指向
谈到this,大家是不是感到很兴奋,平时写代码时,被这家伙整的晕头转向的,这回我们终于可以揭开this的神秘面纱了,搞清楚它在JS到底是怎样的存在,不过客官别着急,我们这里先不介绍this,因为关于this的内容太多了,我们得慢慢去品味它,这里先记住,this是在执行上下文创建阶段确定的。
this传送门👇👇👇
this是个淘气鬼
全局上下文
全局上下文有些特殊,其变量对象永远是window,this永远指向window(在浏览器中,Node中不是)。
即
执行阶段
在执行阶段变量对象(Variable Object)变为活动对象(Active Object)。
VO => AO
执行阶段JS引擎会进行变量赋值、函数引用、执行其他代码,执行顺序取决于代码的位置。
我们就聊到这吧。
喝杯茶,
休息一下。
The text was updated successfully, but these errors were encountered: