一个没有理解面试题

hello雨荷
  • 243
 var tt = 'aa';   

 function test(){

       alert(tt);
       var tt = 'dd';
       alert(tt);    

       }   

  test();

为什么第一个弹出undifine呢?

又:

 var tt = 'aa';

 function test(){


  alert(tt);

  //var tt = 'dd';
  //alert(tt);

        }

   test();

弹出aa?

求各位大神解答下

回复
阅读 10.3k
19 个回答
✓ 已被采纳

这题总结下来就2点知识:
1. 声明提升
2. 作用域链

先说后者,js在访问一个变量时会优先在该作用域(访问时的那个作用域)内寻找是否声明过该变量,如果该变量已经存在,则直接使用它的值,否则它会寻找该作用域的‘父作用域/上级作用域’,以此类推,直到找到全局作用域为止。

关于声明提升是指:js在解析的时候总是会将var, function这类关键词的声明语句提升至该作用域的最顶部(注意:这里只会提升声明部分)。

于是你那段代码等价于下面

javascriptvar tt = 'aa';   

function test(){
    var tt; //这个tt未被赋值,按js的‘规矩’,它的值是`undefined`
    alert(tt);
    tt = 'dd';
    alert(tt);    
}   

test();

所以执行的时候返回的是 undefineddd.


广告
更多精彩内容你或许不知道的javascript,css细节

这样是全局的:

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

这是你的例子:

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

在函数内部使用var声明变量,是局部的。优先级高于函数外部的全局变量。
这个说明js解释器的解析顺序,尽管你的alert(tt)var tt = 'dd'前面,但是它还是认为你是在内部定义了一个局部变量。

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

这是JS的解释机制,第一个会理解成:
function test(){
var tt;
alert(tt);
tt = 'dd';
alert(tt);
}

这个时候函数内作用域的 tt 优先于外面的 tt

函数内的变量也会有类似函数声明提升的效果,test内的相当于
function test(){
var tt; //先定义,但未赋值。这里把全局(或者父函数)的tt给覆盖了
alert(tt);
tt = 'dd'; //这里才给tt赋值。
alert(tt);
}

我来将整个执行过程给你捋一捋哈

0.明白一个机制: 开始执行Js文件时,它会先扫描下整个js文件再去执行代码,会创建全局对象,搜索函数外面的 “var” 声明语句(此时并未赋值,为undefined),
在这面试题中,在全局对象中创建 tt 属性,tt = undefined,创建全局的执行环境,作用域链只有一个对象:全局对象
1.代码执行过程: var tt = 'aa';变量名解析开始,在全局对象属性中查找tt属性,把"aa"赋给tt。
跳过函数声明
test();遇到test()函数调用:创建调用对象
搜索函数中的var声明语句和参数,在调用对象中创建tt的属性,tt=undefined (这里很重要,tt现在是undefined)
创建函数执行环境,作用域链:调用对象>全局对象
回到函数,依次执行代码:
alert(tt),查询tt,变量名解析,先搜索调用对象,找到tt属性,其值为undefined,执行弹出undefined,(这就是为什么了)
var tt="dd",查询tt,变量名解析,先搜索调用对象,找到tt属性,tt="dd"
alert(tt),查询tt,变量名解析,先搜索调用对象,找到tt属性,其值为"dd",执行弹出dd

这个问题涉及到函数的执行环境和作用域链,建议你去了解下哦。第二个函数你应该懂了不用解释了吧。

求采纳啊

一小子攻城狮
  • 1
新手上路,请多包涵

知道代码是分两个阶段执行就行了
解析和进入上下文[变量 函数等声明]阶段
第二个阶段是代码执行

js的作用域不是块作用域而是函数作用域
这个是js变量的声明提前

liúyàn
  • 1
新手上路,请多包涵

主要考点就是变量申明提前 到作用域内的顶部

Jhon16
  • 3
新手上路,请多包涵
风雪寻梦
  • 3
新手上路,请多包涵

第一块的代码经过编译器的预编译后会变成这个样子:

javascriptvar tt = 'aa';

function test(){
       /*
        * 所有变量定义都会提到最上面,其实赋值语句是分为两步的,
        * 第一步定义变量:var tt,第二部赋值:tt = xxx;预编译
        * 之只会把定义变量的语句移动到最上面,而复制语句还是在原
        * 来的位置执行
        */
       var tt;

       alert(tt); // 此时tt为undefined
       tt = 'dd'; // 赋值为'dd'
       alert(tt); // 因此此时输出'dd'
}

test();
puhanyuan
  • 1
新手上路,请多包涵

根据js中函数作用域的特性,局部变量在整个函数作用域内都是有定义的,也就是说,这个时候局部变量会遮盖全局的同名变量,因此在函数体内alert的是局部变量tt。此时涉及到js的另外一个特性就是变量声明提前,即先var tt;然后再alert(tt),此时tt还没有被赋值,因此是undefined。

作用域内声明提升了

其实我觉得LZ对于局部 全局应当是了解的(这都不懂还去面试?)
只不过没有想到声明提升而已

楼主作用域链没有搞明白,先去看书吧

宣传栏