合肥Web培训
达内合肥web培训中心

0551-64632511

热门课程

如何绕过面试题中的小坑?

  • 时间:2017-11-10 13:28
  • 发布:合肥web培训
  • 来源:达内新闻

常见的面试题分析

直接来几道面试题看看你能否答对

var foo=1;function bar( ) {

foo=10;return function foo() { };

}

bar( );

alert(foo);

**********分割线***********var foo = 1;function bar() {

foo = 10;return;function foo() {}

}

bar();console.log(foo)

**********分割线***********var a = 1;function fn() {console.log(a);var a = 2;

}

fn()console.log(a);

**********分割线***********var a = 1;function fn(a) {console.log(a);

a = 2;

}

fn(a)console.log(a);

如果你能够都答对可以忽略本文的阅读.免得浪费时间

接下来我要带大家分析下为什么是这样的结果:分析之前你需要明白的是创建应用程序的时候,总免不了要声明变量和函数解析器(interpreter)是如何以及从哪里找到这些数据(变量,函数)的,当我们引用一个变量时,在解析器内部又发生了什么?

我们知道变量和执行上下文相关那么它就应该知道数据储存在哪里以及如何访问这些数据,这种机制被称为变量对象(variable object)。变量对象(简称为VO)是与某个执行上下文相关的一个特殊对象,并储存了一下数据

1.变量(var, VariableDeclaration)

2.函数声明(FunctionDeclaration,缩写为FD)

3.函数形参

也就是所有的执行中的变量都会存储在这个vo中

处理上下文代码的几个阶段,本文最核心的部分了,处理执行上下文代码分为两个阶段:

当进入执行上下文时(在代码执行前),VO就会被下列属性填充

函数的所有形参(如果是在函数执行上下文中)

每个形参都对应变量对象中的一个属性,该属性由形参名和对应的实参值构成,如果没有传递实参,那么该属性值就为undefined

所有函数声明(FunctionDeclaration, FD)

每个函数声明都对应变量对象中的一个属性,这个属性由一个函数对象的名称和值构成,如果变量对象中存在相同的属性名,则完全替换该属性。

所有变量声明(var, VariableDeclaration)

每个变量声明都对应变量对象中的一个属性,该属性的键/值是变量名和undefined,如果变量名与已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性。

举例说明:function test(a, b) {var c = 10;function d() {}var e = function _e() {};

(function x() {});

}

test(10);

分析:当进入test的执行上下文,并传递了实参10,(VO)AO(VO函数上下文中的变量对象)对象如下:

在函数上下文中,变量对象(VO)不能直接被访问到,此时活动对象(Activation Object,简称AO)扮演着VO的角色。

就是VO(functionContext) === AO;

在这个时候AO对象的值是

AO(test) = {a: 10,b: undefined,c: undefined,d:

e: undefined};

注意:AO并不包含函数x,这是因为x不是函数声明,而是一个函数表达式(FunctionExpression,简称为FE),函数表达式不会影响VO。

同理,函数_e也是函数表达式,就像我们即将看到的那样,因为它分配给了变量e,所以可以通过名称e来访问。

函数声明与函数表达式的异同.(有时间我在进行分析)

接下来就到了第二个阶段代码执行阶段

执行代码

继续以上一例子,到了执行代码阶段,AO/VO就会修改为如下形式

AO['c'] = 10;

AO['e'] = ;

这里需要注意的是

函数表达式_e仍在内存中,它被保存在声明的变量e中。

但函数表达式x却不在AO/VO中,如果尝试在其定义前或者定义后调用x函数,这时会发生“x未定义”的错误

如果你看懂了我上面的分析接下来我带大家分析几个例子

console.log(a);var a = 1;console.log(a);function a(){alert(2)}console.log(a);var a = 3;console.log(a);function a() {alert(4);}console.log(a);

分析流程如下:1.进入执行上下文(预解析)给vo对象定义变量1.第二行有var定义的变量a,将其保存为a=undefined;2.第4行有function声明和第二行的a同名此时由于函数的等级高于变量,于是就覆盖变量a,此时a= function a (){ alert(2); }3.第六行又发现一个var定义的变量,名称与第四行的函数相同,但等级低,故a= function a (){ alert(2); }不变。4.同理,由于第八行后定义,又为同一等级的函数,所以a= function a (){ alert(4); }5.浏览器解析完成

此时的

vo= {a:

}2.开始执行1.第一行a应该是打印function a() {alert(4);}2.第二行表达式修改了a的值,使其为1,所以第三行输出a=13.第四行定义了一个函数,但没有执行,所以第五行输出还为14.第六行表达式又一次更改了a的值,现在a=3,此时的a为一个数字,第七行输出35.同理,第八行没有做更改,第九行还是输出3**是不是觉得特别简单**

转过头来我来和大家一起分析前面的几道面试题

var a = 1;function fn() {console.log(a);var a = 2;

}

fn()console.log(a);

*解析1.第一行var定义的变量a=undefined2. fn就是函数本身

vo定义如下:

vo={a: undefinedfn:

}

*开始执行代码1.第一行表达式将修改a=12.第二到五行声明函数3.到了fn()开始执行函数此时函数为一作用域,只要存在作用域就先解析

所有在函数fn内部1.解析a=undefined在fn内部ao定义如下:

ao(fn)= { a: undefined}2.执行fn内部第一行弹出undefined第二行把a赋值为2 (这里的a是在fn中的局部变量和外包的a全局变量不同)4.最后一行打印全局变量a=1;

说明如果把function fn() {console.log(a);

a = 2; (把var去掉此事的a变成了全局变量)

}

分析这道题var foo = 1;function bar() {

foo = 10;return;function foo() {}

}

bar();

console.log(foo)

*解析阶段(进入执行上下文)

vo = {

foo: undefined

bar:

}

*执行代码阶段

1.第一行foo =1;2.第6行执行函数bar() (第二行到第5行的定义的函数)

在函数bar的内部又有解析和执行阶段

表示如下:

vo(bar) = {

foo:

}

执行阶段

在函数bar内部的第一行foo=10 (这里需要注意的是foo是bar的局部变量不会影响外面全局的变量foo)3:最后一行console.log() foo=1;

var foo=1;function bar( ) {

foo=10;return function foo() { };

}

bar( );

alert(foo);

最后对于这道题为什么结果是10不是1你只要明白return function foo() { };其实是一个函数表达式不是函数定义.原因就在这里var a = 1;function fn(a) {console.log(a);

a = 2;

}

fn(a)console.log(a);这道题关键在于fn(a)其实就是fn(1)在函数内部解析阶段a=1 (这里a在函数内部是形参a=2也是改变fn内的局部变量不影响全局的a )

有一点需要说明的是,我们知道,JS中没有块级作用域,只有函数包含的块才会被当做是作用域。诸如for、if等用花括号包含起来的内容是不算作作用域的。

也就是说,其中内容隶属于全局作用域,在全局范围内都可以访问到,如下

alert(fn);if(true){var a = 1;function fn() {

alert(123);

}

}

总结

你只要明白了函数执行分2个阶段(确定上下文执行代码)在确定上下文阶段定义vo(ao)对象值时候的规则,

规则如下:argument(函数的形参) > function声明> var声明(也就之前提高的变量提升Hoisting)

函数的所有形参(如果是在函数执行上下文中)

每个形参都对应变量对象中的一个属性,该属性由形参名和对应的实参值构成,如果没有传递实参,那么该属性值就为undefined

所有函数声明(FunctionDeclaration, FD)

每个函数声明都对应变量对象中的一个属性,这个属性由一个函数对象的名称和值构成,如果变量对象中存在相同的属性名,则完全替换该属性。

所有变量声明(var, VariableDeclaration)

每个变量声明都对应变量对象中的一个属性,该属性的键/值是变量名和undefined,如果变量名与已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性。

今天合肥web培训分享的文章全都掌握了吗?下次再面试时遇见还能答不上来吗?答不上来不光拿不了高薪,甚至有可能无法入职,加油学习哦,争取早日拿到满意的高薪工作。

免费预约企业总监级讲师试听课

怕钱不够?就业挣钱后再付学费!     怕学不会?0基础入学,达内定制课程!     担心就业?近12万家雇主企业,推荐名企就业!

上一篇:看太多简单易懂的教程,对你没有好处
下一篇:程序员回三四线城市能干什么?

感觉程序员文化水平超级高

在合肥大学生选择Web前端开发的就业方向有哪些?

解析如何正确学习JavaScript指南

10种小和快的前端Web开发框架

选择城市和中心
贵州省

广西省

海南省