25个最基本的JavaScript面试问题及答案

作者 : 开心源码 本文共13956个字,预计阅读时间需要35分钟 发布时间: 2022-05-12 共60人阅读

1.用typeof bar === “object”来确定bar能否是对象的潜在圈套是什么?如何避免这个圈套?

虽然typeof bar === “object”是检查bar能否对象的可靠方法,令人惊讶的是在JavaScript中null也被认为是对象!

因而,令大多数开发人员惊讶的是,下面的代码将输出true(而不是false) 到控制台:

varbar =null;console.log(typeofbar ===”object”);// logs true!

只需清楚这一点,同时检查bar能否为null,即可以很容易地避免问题:

console.log((bar !==null) && (typeofbar ===”object”));//logsfalse

要答全问题,还有其余两件事情值得注意:

首先,上述处理方案将返回false,当bar是一个函数的时候。在大多数情况下,这是期望行为,但当你也想对函数返回true的话,你可以修改上面的处理方案为:

console.log((bar !==null) && ((typeofbar ===”object”) || (typeofbar ===”function”)));

第二,上述处理方案将返回true,当bar是一个数组(例如,当var bar = [];)的时候。在大多数情况下,这是期望行为,由于数组是真正的对象,但当你也想对数组返回false时,你可以修改上面的处理方案为:

console.log((bar !==null) && (typeofbar ===”object”) && (toString.call(bar) !==”[object Array]”));

或者者,假如你用jQuery的话:

console.log((bar !==null) && (typeofbar ===”object”) && (! $.isArray(bar)));

2.下面的代码将输出什么到控制台,为什么?

(function(){vara = b =3;})();console.log(“a defined? “+ (typeofa !==’undefined’));console.log(“b defined? “+ (typeofb !==’undefined’));

因为a和b都定义在函数的封闭范围内,并且都始于var关键字,大多数JavaScript开发人员期望typeof a和typeof b在上面的例子中都是undefined。

然而,事实并非如此。这里的问题是,大多数开发人员将语句var a = b = 3;错误地了解为是以下公告的简写:

varb =3;vara = b;

但事实上,var a = b = 3;实际是以下公告的简写:

b=3;vara = b;

因而(假如你不用严格模式的话),该代码段的输出是:

adefined?falsebdefined?true

但是,b如何才能被定义在封闭函数的范围之外呢?是的,既然语句var a = b = 3;是语句b = 3;和var a = b;的简写,b最终成为了一个全局变量(由于它没有前缀var关键字),因而依然在范围内甚至封闭函数之外。

需要注意的是,在严格模式下(即便使用use strict),语句var a = b = 3;将生成ReferenceError: b is not defined的运行时错误,从而避免任何否则可能会导致的headfakes /bug。 (还是你为什么应该天经地义地在代码中用use strict的最好例子!)

3.下面的代码将输出什么到控制台,为什么?

varmyObject = {? ? foo:”bar”,? ? func:function(){varself =this;console.log(“outer func:? this.foo = “+this.foo);console.log(“outer func:? self.foo = “+ self.foo);? ? ? ? (function(){console.log(“inner func:? this.foo = “+this.foo);console.log(“inner func:? self.foo = “+ self.foo);? ? ? ? }());? ? }};myObject.func();

上面的代码将输出以下内容到控制台:

outer func:this.foo = barouter func:self.foo = barinner func:this.foo = undefinedinner func:self.foo = bar

在外部函数中,this和self两者都指向了myObject,因而两者都可以正确地引使用和访问foo。

在内部函数中,this不再指向myObject。其结果是,this.foo没有在内部函数中被定义,相反,指向到本地的变量self保持在范围内,并且可以访问。 (在ECMA 5之前,在内部函数中的this将指向全局的window对象;反之,由于作为ECMA 5,内部函数中的功能this是未定义的。)

4.封装JavaScript源文件的一律内容到一个函数块有什么意义及理由?

这是一个越来越普遍的做法,被许多流行的JavaScript库(jQuery,Node.js等)采使用。这种技术创立了一个围绕文件一律内容的闭包,也许是最重要的是,创立了一个私有的命名空间,从而有助于避免不同JavaScript板块和库之间潜在的名称冲突。

这种技术的另一个特点是,允许一个易于引使用的(假设更短的)别名使用于全局变量。这通常使用于,例如,jQuery插件中。jQuery允许你用jQuery.noConflict(),来禁使用$引使用到jQuery命名空间。在完成这项工作之后,你的代码依然可以用$利使用这种闭包技术,如下所示:

(function($){/* jQuery plugin code referencing $ */} )(jQuery);

5.在JavaScript源文件的开头包含use strict有什么意义和好处?

对于这个问题,既简要又最重要的答案是,use strict是一种在JavaScript代码运行时自动实行更严格解析和错误解决的方法。那些被忽略或者默默失败了的代码错误,会产生错误或者抛出异常。通常而言,这是一个很好的做法。

严格模式的少量主要优点包括:

使调试更加容易。那些被忽略或者默默失败了的代码错误,会产生错误或者抛出异常,因而尽早提示你代码中的问题,你才能更快地指引到它们的源代码。

防止意外的全局变量。假如没有严格模式,将值分配给一个未公告的变量会自动创立该名称的全局变量。这是JavaScript中最常见的错误之一。在严格模式下,这样做的话会抛出错误。

消除this强制。假如没有严格模式,引使用null或者未定义的值到this值会自动强制到全局变量。这可能会导致许多令人头痛的问题和让人恨不得拔自己头发的bug。在严格模式下,引使用 null或者未定义的this值会抛出错误。

不允许重复的属性名称或者参数值。当检测到对象(例如,var object = {foo: “bar”, foo: “baz”};)中重复命名的属性,或者检测到函数中(例如,function foo(val1, val2, val1){})重复命名的参数时,严格模式会抛出错误,因而捕捉几乎可以一定是代码中的bug可以避免白费大量的跟踪时间。

使eval()更安全。在严格模式和非严格模式下,eval()的行为方式有所不同。最显而易见的是,在严格模式下,变量和公告在eval()语句内部的函数不会在包含范围内创立(它们会在非严格模式下的包含范围中被创立,这也是一个常见的问题源)。

在delete用无效时抛出错误。delete操作符(使用于从对象中删除属性)不能使用在对象不可配置的属性上。当试图删除一个不可配置的属性时,非严格代码将默默地失败,而严格模式将在这样的情况下抛出异常。

6.考虑以下两个函数。它们会返回相同的东西吗? 为什么相同或者为什么不相同?

出人预料的是,这两个函数返回的内容并不相同。更确切地说是:

console.log(“foo1 returns:”);console.log(foo1());console.log(“foo2 returns:”);console.log(foo2());

将产生:

foo1returns:Object{bar:”hello”}foo2returns:undefined

这不仅是令人惊讶,而且特别让人困惑的是,foo2()返回undefined却没有任何错误抛出。

起因与这样一个事实有关,即分号在JavaScript中是一个可选项(虽然省略它们通常是非常糟糕的形式)。其结果就是,当碰到foo2()中包含return语句的代码行(代码行上没有其余任何代码),分号会立即自动插入到返回语句之后。

也不会抛出错误,由于代码的其他部分是完全有效的,即便它没有得到调使用或者做任何事情(相当于它就是是一个未用的代码块,定义了等同于字符串”hello”的属性bar)。

这种行为也支持放置左括号于JavaScript代码行的末尾,而不是新代码行开头的商定。正如这里所示,这不仅仅只是JavaScript中的一个风格偏好。

7.NaN是什么?它的类型是什么?你如何可靠地测试一个值能否等于NaN?

NaN属性代表一个“不是数字”的值。这个特殊的值是由于运算不能执行而导致的,不能执行的起因要么是由于其中的运算对象之一非数字(例如,”abc” / 4),要么是由于运算的结果非数字(例如,除数为零)。

尽管这看上去很简单,但NaN有少量令人惊讶的特点,假如你不知道它们的话,可能会导致令人头痛的bug。

首先,尽管NaN意味着“不是数字”,但是它的类型,不论你信不信,是Number:

console.log(typeofNaN===”number”);// logs “true”

此外,NaN和任何东西比较——甚至是它自己本身!——结果是false:

console.log(NaN===NaN);// logs “false”

一种半可靠的方法来测试一个数字能否等于 NaN,是用内置函数isNaN(),但即便用isNaN()仍然并非是一个完美的处理方案。

一个更好的处理办法是用value !== value,假如值等于NaN,只会产生true。另外,ES6提供了一个新的Number.isNaN()函数,这是一个不同的函数,并且比老的全局isNaN()函数更可靠。

8.下列代码将输出什么?并解释起因。

console.log(0.1+0.2);console.log(0.1+0.2==0.3);

一个略微有点编程基础的答复是:“你不能确定。可能会输出“0.3”和“true”,也可能不会。JavaScript中的数字和浮点精度的解决相同,因而,可能不会总是产生预期的结果。“

以上所提供的例子就是一个演示了这个问题的典型例子。但出人预料的是,它会输出:

0.30000000000000004false

9.探讨写函数isInteger(x)的可能方法,使用于确定x能否是整数。

这可能听起来是小菜一碟,但事实上,这很琐碎,由于ECMAScript 6引入了一个新的正以此为目的Number.isInteger()函数。然而,之前的ECMAScript 6,会更复杂一点,由于没有提供相似的Number.isInteger()方法。

问题是,在ECMAScript规格说明中,整数只概念上存在:即,数字值总是存储为浮点值。

考虑到这一点,最简单又最干净的ECMAScript6之前的处理方法(同时也非常稳健地返回false,即便一个非数字的值,如字符串或者null,被传递给函数)如下:

functionisInteger(x){return(x^0) === x; }

下面的处理方法也是可行的,尽管不如上面那个方法优雅:

functionisInteger(x){returnMath.round(x) === x; }

请注意Math.ceil()和Math.floor()在上面的实现中等同于Math.round()。

或者:

functionisInteger(x){return(typeofx ===’number’) && (x %1===0);

相当普遍的一个不正确的处理方案是:

functionisInteger(x){returnparseInt(x,10) === x; }

尽管这个以parseInt函数为基础的方法在x取许多值时都能工作良好,但一旦x取值相当大的时候,就会无法正常工作。问题在于parseInt()在解析数字之前强制其第一个参数到字符串。因而,一旦数目变得足够大,它的字符串就会表达为指数形式(例如,1e+21)。因而,parseInt()函数就会去解析1e+21,但当到达e字符串的时候,就会中止解析,因而只会返回值1。注意:

10.下列代码行1-4如何排序,使之能够在执行代码时输出到控制台? 为什么?

序号如下:

1

4

3

2

让我们先来解释比较显著而易见的那部分:

1和4之所以放在前面,是由于它们是通过简单调使用console.log()而没有任何推迟输出的

2之所以放在3的后面,是由于2是推迟了1000毫秒(即,1秒)之后输出的,而3是推迟了0毫秒之后输出的。

好的。但是,既然3是0毫秒推迟之后输出的,那么能否意味着它是立即输出的呢?假如是的话,那么它是不是应该在4之前输出,既然4是在第二行输出的?

要答复这个问题,你需要正确了解JavaScript的事件和时间设置。

浏览器有一个事件循环,会检查事件队列和解决未完成的事件。例如,假如时间发生在后端(例如,脚本的onload事件)时,浏览器正忙(例如,解决一个onclick),那么事件会增加到队列中。当onclick解决程序完成后,检查队列,而后解决该事件(例如,执行onload脚本)。

同样的,setTimeout()也会把其引使用的函数的执行放到事件队列中,假如浏览器正忙的话。

当setTimeout()的第二个参数为0的时候,它的意思是“尽快”执行指定的函数。具体而言,函数的执行会放置在事件队列的下一个计时器开始。但是请注意,这不是立即执行:函数不会被执行除非下一个计时器开始。这就是为什么在上述的例子中,调使用console.log(4)发生在调使用console.log(3)之前(由于调使用console.log(3)是通过setTimeout被调使用的,因而会略微推迟)。

11.写一个简单的函数(少于80个字符),要求返回一个布尔值指明字符串能否为回文结构。

下面这个函数在str是回文结构的时候返回true,否则,返回false。

functionisPalindrome(str){? ? str = str.replace(/\W/g,”).toLowerCase();return(str == str.split(”).reverse().join(”));}

例如:

console.log(isPalindrome(“level”));//logs’true’console.log(isPalindrome(“levels”));//logs’false’console.log(isPalindrome(“A car, a man, a maraca”));//logs’true’

12.写一个sum方法,在用下面任一语法调使用时,都可以正常工作。

console.log(sum(2,3));// Outputs 5console.log(sum(2)(3));// Outputs 5

(至少)有两种方法可以做到:

方法1

functionsum(x){if(arguments.length ==2) {returnarguments[0] +arguments[1];? }else{returnfunction(y){returnx + y; };? }}

在JavaScript中,函数可以提供到arguments对象的访问,arguments对象提供传递到函数的实际参数的访问。这使我们能够用length属性来确定在运行时传递给函数的参数数量。

假如传递两个参数,那么只要加在一起,并返回。

否则,我们假设它被以sum(2)(3)这样的形式调使用,所以我们返回一个匿名函数,这个匿名函数合并了传递到sum()的参数和传递给匿名函数的参数。

方法2

functionsum(x, y){if(y !==undefined) {returnx + y;? }else{returnfunction(y){returnx + y; };? }}

当调使用一个函数的时候,JavaScript不要求参数的数目匹配函数定义中的参数数量。假如传递的参数数量大于函数定义中参数数量,那么多余参数将简单地被忽略。另一方面,假如传递的参数数量小于函数定义中的参数数量,那么缺少的参数在函数中被引使用时将会给一个undefined值。所以,在上面的例子中,简单地检查第2个参数能否未定义,即可以相应地确定函数被调使用以及进行的方式。

13.请看下面的代码片段:

for(vari =0; i <5; i++) {varbtn =document.createElement(‘button’);? btn.appendChild(document.createTextNode(‘Button ‘+ i));? btn.addEventListener(‘click’,function(){console.log(i); });document.body.appendChild(btn);}

(a)当使用户点击“Button 4”的时候会输出什么到控制台,为什么?(b)提供一个或者多个备使用的可按预期工作的实现方案。

(a)无论使用户点击什么按钮,数字5将总会输出到控制台。这是由于,当onclick方法被调使用(对于任何按钮)的时候,for循环已经结束,变量i已经取得了5的值。(面试者假如能够谈一谈有关如何执行上下文,可变对象,激活对象和内部“范围”属性贡有助于闭包行为,则可以加分)。

(b)要让代码工作的关键是,通过传递到一个新创立的函数对象,在每次传递通过for循环时,捕捉到i值。下面是三种可能实现的方法:

for(vari =0; i <5; i++) {varbtn =document.createElement(‘button’);? btn.appendChild(document.createTextNode(‘Button ‘+ i));? btn.addEventListener(‘click’, (function(i){returnfunction(){console.log(i); };? })(i));document.body.appendChild(btn);}

或者者,你可以封装一律调使用到在新匿名函数中的btn.addEventListener:

for(vari =0; i <5; i++) {varbtn =document.createElement(‘button’);? btn.appendChild(document.createTextNode(‘Button ‘+ i));? (function(i){? ? btn.addEventListener(‘click’,function(){console.log(i); });? })(i);document.body.appendChild(btn);}

也可以调使用数组对象的本地forEach方法来替代for循环:

[‘a’,’b’,’c’,’d’,’e’].forEach(function(value, i){varbtn =document.createElement(‘button’);? btn.appendChild(document.createTextNode(‘Button ‘+ i));? btn.addEventListener(‘click’,function(){console.log(i); });document.body.appendChild(btn);});

14.下面的代码将输出什么到控制台,为什么?

vararr1 =”john”.split(”);vararr2 = arr1.reverse();vararr3 =”jones”.split(”);arr2.push(arr3);console.log(“array 1: length=”+ arr1.length +” last=”+ arr1.slice(-1));console.log(“array 2: length=”+ arr2.length +” last=”+ arr2.slice(-1));

输出结果是:

“array 1: length=5 last=j,o,n,e,s””array 2: length=5 last=j,o,n,e,s”

arr1和arr2在上述代码执行之后,两者相同了,起因是:

调使用数组对象的reverse()方法并不只返回反顺序的阵列,它也反转了数组本身的顺序(即,在这种情况下,指的是arr1)。

reverse()方法返回一个到数组本身的引使用(在这种情况下即,arr1)。其结果为,arr2仅仅是一个到arr1的引使用(而不是副本)。因而,当对arr2做了任何事情(即当我们调使用arr2.push(arr3);)时,arr1也会受到影响,由于arr1和arr2引使用的是同一个对象。

这里有几个侧面点有时候会让你在答复这个问题时,阴沟里翻船:

传递数组到另一个数组的push()方法会让整个数组作为单个元素映射到数组的末端。其结果是,语句arr2.push(arr3);在其整体中增加arr3作为一个单一的元素到arr2的末端(也就是说,它并没有连接两个数组,连接数组是concat()方法的目的)。

和Python一样,JavaScript标榜数组方法调使用中的负数下标,例如slice()可作为引使用数组末尾元素的方法:例如,-1下标表示数组中的最后一个元素,等等。

15.下面的代码将输出什么到控制台,为什么?

console.log(1+”2″+”2″);console.log(1+? +”2″+”2″);console.log(1+? -“1″+”2″);console.log(+”1″+”1″+”2”);console.log(“A”-“B”+”2”);console.log(“A”-“B”+2);

上面的代码将输出以下内容到控制台:

“122””32″”02″”112″”NaN2″NaN

起因是…

这里的根本问题是,JavaScript(ECMAScript)是一种弱类型语言,它可对值进行自动类型转换,以适应正在执行的操作。让我们通过上面的例子来说明这是如何做到的。

例1:1 + “2” + “2”输出:”122″说明:1 + “2”是执行的第一个操作。因为其中一个运算对象(”2″)是字符串,JavaScript会假设它需要执行字符串连接,因而,会将1的类型转换为”1″,1 + “2”结果就是”12″。而后,”12″ + “2”就是”122″。

例2:1 + +”2″ + “2”输出:”32″说明:根据运算的顺序,要执行的第一个运算是+”2″(第一个”2″前面的额外+被视为一元运算符)。因而,JavaScript将”2″的类型转换为数字,而后应使用一元+号(即,将其视为一个正数)。其结果是,接下来的运算就是1 + 2,这当然是3。而后我们需要在一个数字和一个字符串之间进行运算(即,3和”2″),同样的,JavaScript会将数值类型转换为字符串,并执行字符串的连接,产生”32″。

例3:1 + -“1” + “2”输出:”02″说明:这里的解释和前一个例子相同,除了此处的一元运算符是-而不是+。先是”1″变为1,而后当应使用-时又变为了-1,而后将其与1相加,结果为0,再将其转换为字符串,连接最后的”2″运算对象,得到”02″。

例4:+”1″ + “1” + “2”输出:”112″说明:尽管第一个运算对象”1″由于前缀的一元+运算符类型转换为数值,但又立即转换回字符串,当连接到第二个运算对象”1″的时候,而后又和最后的运算对象”2″连接,产生了字符串”112″。

例5:”A” – “B” + “2”输出:”NaN2″说明:因为运算符-不能被应使用于字符串,并且”A”和”B”都不能转换成数值,因而,”A” – “B”的结果是NaN,而后再和字符串”2″连接,得到”NaN2″。

例6:”A” – “B” + 2输出:NaN说明:参见前一个例子,”A” – “B”结果为NaN。但是,应使用任何运算符到NaN与其余任何的数字运算对象,结果依然是NaN。

16.下面的递归代码在数组列表偏大的情况下会导致堆栈溢出。在保留递归模式的基础上,你怎样处理这个问题?

varlist= readHugeList();varnextListItem =function(){varitem =list.pop();if(item) {// process the list item…nextListItem();? ? }};

潜在的堆栈溢出可以通过修改nextListItem函数避免:

varlist= readHugeList();varnextListItem =function(){varitem =list.pop();if(item) {// process the list item…setTimeout( nextListItem,0);? ? }};

堆栈溢出之所以会被消除,是由于事件循环操纵了递归,而不是调使用堆栈。当nextListItem运行时,假如item不为空,timeout函数(nextListItem)就会被推到事件队列,该函数退出,因而就清空调使用堆栈。当事件队列运行其timeout事件,且进行到下一个item时,定时器被设置为再次调使用nextListItem。因而,该方法从头到尾都没有直接的递归调使用,所以无论迭代次数的多少,调使用堆栈保持清空的状态。

17.JavaScript中的“闭包”是什么?请举一个例子。

闭包是一个可以访问外部(封闭)函数作使用域链中的变量的内部函数。闭包可以访问三种范围中的变量:这三个范围具体为:(1)自己范围内的变量,(2)封闭函数范围内的变量,以及(3)全局变量。

下面是一个简单的例子:

在上面的例子中,来自于innerFunc,outerFunc和全局命名空间的变量都在innerFunc的范围内。因而,上面的代码将输出如下:

outerArg=123innerArg=456outerVar= ainnerVar= bglobalVar= xyz

18.下面的代码将输出什么:

for(vari =0; i <5; i++) {? setTimeout(function(){console.log(i); }, i *1000);}

解释你的答案。闭包在这里能起什么作使用?

上面的代码不会按预期显示值0,1,2,3,和4,而是会显示5,5,5,5,和5。

起因是,在循环中执行的每个函数将整个循环完成之后被执行,因而,将会引使用存储在i中的最后一个值,那就是5。

闭包可以通过为每次迭代创立一个唯一的范围,存储范围内变量的每个唯一的值,来防止这个问题,如下:

for(vari =0; i <5; i++) {(function(x){? ? setTimeout(function(){console.log(x); }, x *1000);? ? })(i);}

这就会按预期输出0,1,2,3,和4到控制台。

19.以下代码行将输出什么到控制台?

console.log(“0 || 1 = “+(0||1));console.log(“1 || 2 = “+(1||2));console.log(“0 && 1 = “+(0&&1));console.log(“1 && 2 = “+(1&&2));

并解释。

该代码将输出:

0||1=11||2=10&&1=01&&2=2

在JavaScript中,||和&&都是逻辑运算符,使用于在从左至右计算时,返回第一个可完全确定的“逻辑值”。

或者(||)运算符。在形如X||Y的表达式中,首先计算X并将其解释执行为一个布尔值。假如这个布尔值true,那么返回true(1),不再计算Y,由于“或者”的条件已经满足。假如这个布尔值为false,那么我们依然不能知道X||Y是真是假,直到我们计算Y,并且也把它解释执行为一个布尔值。

因而,0 || 1的计算结果为true(1),同理计算1 || 2。

与(&&)运算符。在形如X&&Y的表达式中,首先计算X并将其解释执行为一个布尔值。假如这个布尔值为false,那么返回false(0),不再计算Y,由于“与”的条件已经失败。假如这个布尔值为true,但是,我们依然不知道X&&Y是真是假,直到我们去计算Y,并且也把它解释执行为一个布尔值。

不过,关于&&运算符有趣的地方在于,当一个表达式计算为“true”的时候,那么就返回表达式本身。这很好,尽管它在逻辑表达式方面计算为“真”,但假如你希望的话也可使用于返回该值。这就解释了为什么,有些令人奇怪的是,1 && 2返回2(而不是你以为的可能返回true或者1)。

20.执行下面的代码时将输出什么?请解释。

console.log(false==’0′)console.log(false===’0′)

代码将输出:

truefalse

在JavaScript中,有两种等式运算符。三个等于运算符===的作使用相似传统的等于运算符:假如两侧的表达式有着相同的类型和相同的值,那么计算结果为true。而双等于运算符,会只强制比较它们的值。因而,总体上而言,用===而不是==的做法更好。!==vs!=亦是同理。

21.以下代码将输出什么?并解释你的答案。

vara={},? ? b={key:’b’},c={key:’c’};a[b]=123;a[c]=456;console.log(a[b]);

这段代码将输出456(而不是123)。

起因为:当设置对象属性时,JavaScript会暗中字符串化参数值。在这种情况下,因为b和c都是对象,因而它们都将被转换为”[object Object]”。结果就是,a[b]和a[c]均相当于a[“[object Object]”],并可以互换用。因而,设置或者引使用a[c]和设置或者引使用a[b]完全相同。

22.以下代码行将输出什么到控制台?

console.log((functionf(n){return((n >1) ? n * f(n-1) : n)})(10));

并解释你的答案。

代码将输出10!的值(即10!或者3628800)。

起因是:

命名函数f()递归地调使用本身,当调使用f(1)的时候,只简单地返回1。下面就是它的调使用过程:

f(1): returns n, whichis1f(2): returns2* f(1), whichis2f(3): returns3* f(2), whichis6f(4): returns4* f(3), whichis24f(5): returns5* f(4), whichis120f(6): returns6* f(5), whichis720f(7): returns7* f(6), whichis5040f(8): returns8* f(7), whichis40320f(9): returns9* f(8), whichis362880f(10): returns10* f(9), whichis3628800

23.请看下面的代码段。控制台将输出什么,为什么?

(function(x){return(function(y){console.log(x);? ? })(2)})(1);

控制台将输出1,即便素来没有在函数内部设置过x的值。起因是:

正如我们在JavaScript招聘指南中解释过的那样,闭包是一个函数,连同在闭包创立的时候,其范围内的所有变量或者函数一起。在JavaScript中,闭包是作为一个“内部函数”实施的:即,另一个函数主体内定义的函数。闭包的一个重要特征是,内部函数依然有权访问外部函数的变量。

因而,在本例中,因为x未在函数内部中定义,因而在外部函数范围中搜索定义的变量x,且被发现具备1的值。

24.下面的代码将输出什么到控制台,为什么:

代码有什么问题,以及应该如何修复。

代码将输出:

undefinedJohn Doe

第一个console.log之所以输出undefined,是由于我们正在从hero对象提取方法,所以调使用了全局上下文中(即窗口对象)的stoleSecretIdentity(),而在此全局上下文中,_name属性不存在。

其中一种修复stoleSecretIdentity()函数的方法如下:

varstoleSecretIdentity = hero.getSecretIdentity.bind(hero);

25.创立一个给定页面上的一个DOM元素,就会去访问元素本身及其所有子元素(不只是它的直接子元素)的函数。对于每个被访问的元素,函数应该传递元素到提供的回调函数。

此函数的参数为:

DOM元素

回调函数(将DOM元素作为其参数)

访问树(DOM)的所有元素是经典的深度优先搜索算法应使用。下面是一个示范的处理方案:

functionTraverse(p_element,p_callback){? p_callback(p_element);varlist= p_element.children;for(vari =0; i

【假如大家对程序员,web前台感兴趣,想要学习的,关注一下小编吧。我是一名六年的前台工程师,打算深入理解这个行业的朋友,可以加下小编的前台学习群 :731771211,不论你是小白还是大牛,小编我都欢迎,不定期分享干货,包括小编自己整理的一份2018最新的web前台学习资料和0基础入门教程,欢迎初学和进阶中的小伙伴。

每天晚上20:00我都会开直播免费给大家分享web前台编程学习知识和路线方法,群里会不定期升级最新的教程和学习方法(进群送2018web前台编程学习教程),大家都是学习web前台的,或者是转行,或者是大学生,还有工作中想提升自己能力的web前台党,假如你是正在学习web前台的小伙伴可以加入学习。最后祝所有程序员都能够走上人生巅峰,让代码将梦想照进现实,非常适合新手学习,有不懂的问题可以随时问我,工作不忙的时候希望可以给大家解惑。】

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 25个最基本的JavaScript面试问题及答案

发表回复