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

来源:互联网 发布:美工常浏览的网站 编辑:程序博客网 时间:2024/05/29 09:30

点击查看全文


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


1、使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱?

尽管 typeof bar === "object" 是检查 bar 是否对象的可靠方法,令人惊讶的是在JavaScript中 null 也被认为是对象!

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

  1. var bar = null; console.log(typeof bar === "object"); // logs true

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

  1. console.log((bar !== null) && (typeof bar === "object")); // logs false 

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

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

  1. console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function"))); 

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

  1. console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]")); 

或者,如果你使用jQuery的话:

  1. console.log((bar !== null) && (typeof bar === "object") && (! $.isArray(bar))); 

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

  1. (function(){ var a = b = 3; })();
  2. console.log("a defined? " + (typeof a !== 'undefined')); 
  3. console.log("b defined? " + (typeof b !== 'undefined')); 

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

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

  1. var b = 3; 
  2. var a = b; 

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

  1. b = 3;  
  2. var a = b; 

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

  1. a defined? false
  2. b defined? 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.下面的代码将输出什么到控制台,为什么?

  1. var myObject = {   
  2.     foo: "bar",       
  3.     func: function() {        
  4.       var self = this;          
  5.       console.log("outer func:  this.foo = " + this.foo);   
  6.       console.log("outer func:  self.foo = " + self.foo);                
  7.       (function() {     
  8.            console.log("inner func:  this.foo = " + this.foo);  
  9.            console.log("inner func:  self.foo = " + self.foo);           
  10.       }());       
  11.     }   
  12. };  
  13. myObject.func(); 

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

  1. outer func: this.foo = bar outer func: self.foo = bar inner func: this.foo = undefined inner 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命名空间。在完成这项工作之后,你的代码仍然可以使用$ 利用这种闭包技术,如下所示:

  1. (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.考虑以下两个函数。它们会返回相同的东西吗? 为什么相同或为什么不相同?

  1. function foo1() { 
  2.  return { bar: "hello" };  
  3. }  
  4. function foo2() { 
  5.  return { bar: "hello" };  

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

  1. console.log("foo1 returns:");  
  2. console.log(foo1());  
  3. console.log("foo2 returns:");  
  4. console.log(foo2()); 

将产生:

  1. foo1 returns:Object { 
  2.   bar: "hello" 
  3. foo2 returns:undefined 

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

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

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

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

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

NaN 属性代表一个“不是数字”的值。这个特殊的值是因为运算不能执行而导致的,



点击查看全文