网易JS面试题与Javascript词法作用域说明

 更新时间:2010年11月09日 10:01:16   作者:  
Javascript函数在定义它们的作用域里运行,而不是在执行它们的作用域里运行。
调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量)、函数参数及Arguments对象都在函数内的作用域中——这意味着它们隐藏了作用域链更上层的任何同名的属性。

2010年9月14日,我去参加网易网页工程师招聘会,应聘JS工程师职位。有幸参加笔试,然后有幸栽在笔试,呵呵。废话少说,抓出音响极深的一题重新研究研究。

题目大概是:写出如下代码的输出结果并进行分析

复制代码 代码如下:

var tt = 'aa';
function test(){
alert(tt);
var tt = 'dd';
alert(tt);
}
test();

“太简单了!”这是我当时看到这个题目是的第一想法,于是轻率答题竟成我的致命之伤。我的答案是——aa和dd,解析:第一次输出全局变量的结果,然后局部变量tt覆盖全局变量所引用的值,所以第二次输出结果是dd。

任何人见我如此作答,都会认为我是在扫盲——想法及其幼稚(我也这么认为)!

网易啊,怎么可能会满意于这种答案!

正确的答案应该是:undefined和dd

为什么第一次alert的结果是undefined呢?要解释得清楚明白需要用到Javascript的词法作用域。

Javascript中的函数“在定义它们的作用域里运行,而不是在执行它们的作用域里运行”,这是权威指南里抽象而精辟的总结。

Javascript的逻辑默认在一个全局作用域中执行,如以上程序段中的“var tt='aa';”就是定义一个全局作用域的全局变量(如果以上代码段不是摘自某个函数链的话)。而test()函数内部的逻辑必须在原有的作用域(全局 作用域)链再添加test函数本身的作用域(局部性)——这些思想几乎在每一种语言中都是如此定义的,然而Javascript作用域链的特别之处在于函 数内部能够嵌套函数的定义(这是闭包的基础。注:在JS中函数是唯一形式的代码作用域)

嵌套的内部函数可以调用外部函数(被嵌套的函数)的变量和其他嵌套函数(函数是一种数据)。如果是在外部函数内调用嵌套函数,那么调用对象不变,当 外部函数执行完毕后所有数据(包括外部函数和嵌套的内部函数)都将被垃圾回收机制收集——这一点还不能体现出‘闭包'的精华。有一种情况,就是 Javascript允许外部调用嵌套的内部函数,即使被嵌套函数已经被‘垃圾收集'——最常见的就是在‘某个函数'中用其嵌套的内部函数定义某些元素的 响应事件,页面载入的时候被嵌套函数(‘某个函数')已经执行完毕(被垃圾回收),但当事件触发的时候仍然会有响应的动作,而且响应函数中还可能调用到在 被嵌套函数(‘某个函数')中定义的变量最终值(不是被垃圾回收了吗?)。

关于闭包的知识和示例有很多资料可供查询,我不想叙述。

本文的重点是以下非常重要的细节:

调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量)、函数参数及Arguments对象都在函数内的作用域中——这意味着它们隐藏了作用域链更上层的任何同名的属性。

即,在以上程序片段中,test函数内部的“var tt='dd'”将会致使“var tt='aa'”在test函数被调用时完全被隐藏。而且,tt是在第一个alert语句之后定义,所以在调用到第一个alert时,tt是还没有被赋值 的。这样说可能会清楚一点,即,在定义test函数时,当定义第一个alert(tt)时,这里会记录tt是作用域链中的一个变量但不会记录它(tt)的 值,函数定义完毕后tt就添加到作用域里,所以第一个alert语句能够找到该作用域里的tt(即,相当于找到一个已经在函数内部声明,但未被赋值的 tt)。

以上程序片段的执行结果与以下片段的结果相同:

复制代码 代码如下:

var tt = 'aa';
function test(){
var tt;
alert(tt);
tt = 'dd';
alert(tt);
}
test();

Javascript的作用域不可简单的用C++等语言的思维来理解啊!C++在调用函数之前必须先声明或定义,而Javascript没必要。在 Javascript中可以先调用函数,后再定义(不用在调用之前作任何声明)。因为在调用函数时,Javascript是向作用域链要函数的定义(函数在定义它们的作用域里运行,而不是在执行它们的作用域里运行)

如以上代码写成:
复制代码 代码如下:

var tt = 'aa';
test(); //先调用后再定义
function test(){
alert(tt); //undefined
var tt = 'dd';
alert(tt); //dd
}

以上代码片段虽然能够得到相同的结果,但最好不要那样写啦,习惯不好,代码不好维护。

相关文章

  • BootStrap轮播HTML代码(推荐)

    BootStrap轮播HTML代码(推荐)

    本文给大家分享bootstrap轮播h tml代码,代码简单易懂非常不错,具有参考借鉴,需要的朋友参考下吧
    2016-12-12
  • js中取得变量绝对值的方法

    js中取得变量绝对值的方法

    这篇文章主要介绍了js中取得变量绝对值的方法,较为详细的分析了js中abs方法取绝对值的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • JS基于myFocus库实现各种功能的tab选项卡切换效果

    JS基于myFocus库实现各种功能的tab选项卡切换效果

    这篇文章主要介绍了JS基于myFocus库实现各种功能的tab选项卡切换效果,实例演示了JS实现tab嵌套显示及常用过度效果的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • layui form表单提交之后重新加载数据表格的方法

    layui form表单提交之后重新加载数据表格的方法

    今天小编就为大家分享一篇layui form表单提交之后重新加载数据表格的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • JS获取当前时间戳方法解析

    JS获取当前时间戳方法解析

    这篇文章主要介绍了JS获取当前时间戳方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • JWT Json Web Token全面详解

    JWT Json Web Token全面详解

    这篇文章主要为大家介绍了JWT Json Web Token全面详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2022-11-11
  • 使用控制台破解百小度一个月只准改一次名字

    使用控制台破解百小度一个月只准改一次名字

    这篇文章主要介绍了使用控制台破解百小度一个月只准改一次名字的方法和代码,有需要的小伙伴可以参考下。
    2015-08-08
  • 为JS扩展Array.prototype.indexOf引发的问题探讨及解决

    为JS扩展Array.prototype.indexOf引发的问题探讨及解决

    Array没有indexOf方法,这样在一个数组中查找某个元素的索引时比较麻烦,于是通过prototype原型扩展了Array.prototype.indexOf(),在对数组进行遍历的时候却出现了问题
    2013-04-04
  • js截取函数(indexOf,join等)

    js截取函数(indexOf,join等)

    下面是js中截取字符串经常会用到的一些函数,这里每个函数都给出了例子,学习的朋友可以参考下。
    2010-09-09
  • js实时获取并显示当前时间的方法

    js实时获取并显示当前时间的方法

    这篇文章主要介绍了js实时获取并显示当前时间的方法,涉及javascript针对时间及页面元素的相关操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07

最新评论