论坛首页 Web前端技术论坛

关于js解析执行有趣的事

浏览 13334 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-06-18   最后修改:2012-06-18

前些天总监在群里发了两段代码:

 

var foo = 1;  
function bar() {  
    if (!foo) {  
        var foo = 10;  
    }  
    alert(foo);  
}  
bar();  

 

var a = 1;  
function b() {  
    a = 10;  
    return;  
    function a() {}  
}  
b();  
alert(a);  
 

不测试,大家看输出的是什么?

   发表时间:2012-06-18  
第一题
10
第二题
1(局部和全局变量不同)
0 请登录后投票
   发表时间:2012-06-18  
xleon 写道
第一题
10
第二题
1(局部和全局变量不同)

这答案没说服力啊
0 请登录后投票
   发表时间:2012-06-18  
liukemin 写道
xleon 写道
第一题
10
第二题
1(局部和全局变量不同)

这答案没说服力啊

楼上说的没有错,想简单理解的话,可以想象在第一个例子的函数bar进入时候第一行加一行
var foo = undefined

在第二个例子的函数b的第一行加一个
var a = undefined

解析作用域时候,该作用域里面不管哪行定义了东西,都可以简单想象成第一行声明了一个未初始化的同名变量。
(纯粹为了容易理解)
0 请登录后投票
   发表时间:2012-06-18  
red008 写道
liukemin 写道
xleon 写道
第一题
10
第二题
1(局部和全局变量不同)

这答案没说服力啊

楼上说的没有错,想简单理解的话,可以想象在第一个例子的函数bar进入时候第一行加一行
var foo = undefined

在第二个例子的函数b的第一行加一个
var a = undefined

解析作用域时候,该作用域里面不管哪行定义了东西,都可以简单想象成第一行声明了一个未初始化的同名变量。
(纯粹为了容易理解)

这关系到JS解析顺序的问题,当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。
做如下处理:
1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。
2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined)

换个角度来说,这个是函数体升迁的问题,如果是用 var fn = function() 这种形式来定义,那么 fn 会升迁,但是函数体不会升迁,因此会报告错误说 fn 不是一个方法(注意不是报告未定义),而如果使用 function fn() 来定义方法,那么 fn 和函数体会同时升迁,这样 fn() 是可以调用到结果的。
0 请登录后投票
   发表时间:2012-06-18  
red008 写道
liukemin 写道
xleon 写道
第一题
10
第二题
1(局部和全局变量不同)

这答案没说服力啊

楼上说的没有错,想简单理解的话,可以想象在第一个例子的函数bar进入时候第一行加一行
var foo = undefined

在第二个例子的函数b的第一行加一个
var a = undefined

解析作用域时候,该作用域里面不管哪行定义了东西,都可以简单想象成第一行声明了一个未初始化的同名变量。
(纯粹为了容易理解)

这关系到JS解析顺序的问题,当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。
做如下处理:
1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。
2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined)

换个角度来说,这个是函数体升迁的问题,如果是用 var fn = function() 这种形式来定义,那么 fn 会升迁,但是函数体不会升迁,因此会报告错误说 fn 不是一个方法(注意不是报告未定义),而如果使用 function fn() 来定义方法,那么 fn 和函数体会同时升迁,这样 fn() 是可以调用到结果的。


不怎么懂
0 请登录后投票
   发表时间:2012-06-19  
不理解,有没有相关知识的书或文章可以参考一下的
0 请登录后投票
   发表时间:2012-06-19  
有意思,以前只以为会自动向上一级域寻找定义,原来只是赋值的时候。学习了。
0 请登录后投票
   发表时间:2012-06-19   最后修改:2012-06-19
liukemin 写道
red008 写道
liukemin 写道
xleon 写道
第一题
10
第二题
1(局部和全局变量不同)

这答案没说服力啊

楼上说的没有错,想简单理解的话,可以想象在第一个例子的函数bar进入时候第一行加一行
var foo = undefined

在第二个例子的函数b的第一行加一个
var a = undefined

解析作用域时候,该作用域里面不管哪行定义了东西,都可以简单想象成第一行声明了一个未初始化的同名变量。
(纯粹为了容易理解)

这关系到JS解析顺序的问题,当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理。
做如下处理:
1. 在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用var申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是undefined,并将那些以function定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。
2. 在解释执行阶段,遇到变量需要解析时,会首先从当前执行环境的活动对象中查找,如果没有找到而且该执行环境的拥有者有prototype属性时则会从prototype链中查找,否则将会按照作用域链查找。遇到var a = ...这样的语句时会给相应的变量进行赋值(注意:变量的赋值是在解释执行阶段完成的,如果在这之前使用变量,它的值会是undefined)

换个角度来说,这个是函数体升迁的问题,如果是用 var fn = function() 这种形式来定义,那么 fn 会升迁,但是函数体不会升迁,因此会报告错误说 fn 不是一个方法(注意不是报告未定义),而如果使用 function fn() 来定义方法,那么 fn 和函数体会同时升迁,这样 fn() 是可以调用到结果的。


一团,看懂一部分又有新的看不懂,感觉是解释的太多又没说详细,比如 “活动对象”,“该执行环境的拥有者”是什么,“升迁”。会给人越看问题越多的感觉。

个人的简单理解是不管是var c,还是 function c(){}都定义了一个变量c.而javascript变量定义是整个scope的,所以在一开始就有一个undefined的c变量隐藏了outer scope的c。
另外则是:
function c(){} 和 var c = function(){}的不同是第一个作为函数在整个scope都有效,而第二个则只有变量c在整个scope有效.而为什么有这种区别对待,也和两者语义有关,第二个变量上面已经提过(个人觉得javascript这么设置并不合理,局部变量顺序定义更容易观察和理解)。第一个则接近于方法,方法自然不应为其定义顺序影响.

javascript是没有if block这种scope的,所以if里面的和函数内部其实是同一个scope.记得javascript只有函数才有scope.
----------------
变量一开始就声明了但没赋值和一开始就没声明变量的区别是,一个是undefined,一个会报reference错误.
0 请登录后投票
   发表时间:2012-06-19   最后修改:2012-06-19
不明白为什么第二个例子去掉function a() {}就能赋值了,后面那个函数是干吗用的,不是之前已经return了吗?
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics