JavaScript基本的面试题及答案

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

例:

var bar=null;

console.log(typeof bar==="object");

输出结果:true;

解释:在javascript中null被认为是对象

如果要避免该陷阱,则还需要判断bar是否为null。

例:

var bar=null;

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

输出结果:false

2、下面的代码在控制台输出什么结果,为什么?

(function(){
   var a=b=3; 

console.log(typeof a=='undefined');//输出结果:false
})();
console.log(
"a defined?"+(typeof a!=='undefined'));//输出结果:true
console.log(
"b defined?"+(typeof b!=='undefined'));//输出结果:false

 解释:

var a=b=3的声明是b=3,var a=b的简写,b是全局变量(因为它没有前缀var关键字),因此它的作用域为匿名函数之内和匿名函数之外;而a的定义为局部变量,因此它的作用域只在匿名函数之内,而输出结果语句是在闭包之外,因此typeof a!=='undefined'的输出结果为true,在匿名函数之内的输出结构则为false.

注:1、这个题的关键在var a=b=3这句话的理解

       2、在严格模式下(即使用use strict),语句var a=b=3将生成ReferenceError:b is not defined的运行时错误,从而避免任何否则可能导致的headfakes/bug.

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

 

<script>
  var myObject={
      foo:"bar",
      func:function(){
          var self=this;
          console.log("outer func:this foo="+this.foo);//输出结果为:outer func:this foo=bar
          console.log("outer func:self.foo="+self.foo);//输出结果为:outer func:this foo=bar
          (function(){
              console.log("inner func:this.foo="+this.foo);//输出结果为:inner func:this.foo=undefined
              console.log("inner func:self.foo="+self.foo);//输出结果为:inner func:self.foo=bar
          }());
      }
  };
  myObject.func();
</script>

解释:在外部函数中,this和self都指向的是myObject对象,所以输出结果都指向的是bar;在内部函数中,this指向的是其匿名函数,而匿名函数中并没有定义foo,因此输出结果为undefined,而self变量相对于内部函数而言是全局变量,其所指向的是myObject对象,因此其输出结果为:bar.

注:该题的关键点在于对this的理解,但是this在JavaScript中又是一个很难理解的东西,通过学习和别人的总计,大致对this在不同的环境中的意义做了总结,大致如下:

    1、在HTML标签中(例:<button onclick="calc(this)">提交</button>),this指代当前触发事件元素对象本身;

    2、所有匿名函数的回调或者自调,内部的this指向的是window;

    3、在程序运行时,this指代正在调用方法的对象(.之前的对象);

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

    答:use strict是一种在JavaScript代码运行时自动实行更严格解析和错误处理的方法,那些被忽略或默默失败了的代码错误,会产生错误或抛出异常。通常而言,这是一个很好的做法。

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

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

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

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

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

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

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

5、考虑以下两个函数,它们会返回相同的东西吗?为什么相同或为什么不同?

<script>
    function foo1(){
        return {
            bar:"hello"
        };
    }
    function foo2(){
        return 
        {
            bar:"hello"
        };
    }
    console.log(foo1());//输出结果为Object {bar: "hello"}
    console.log(foo2());//输出结果为undefined
  </script>

解释:

分号在JavaScript中是一个可选项(尽管省略它们通常是非常糟糕的形式)。其结果就是,当碰到foo2()中包含return语句的代码行(代码行上没有任何其它代码),分号会立即自动插入到返回语句之后。也不会抛出错误,因为代码的其余部分是完全有效的,即使它没有得到调用或做任何事情(相当于它就是一个未使用的代码块,定义了等同于字符串“hello”的属性bar)。这种行为也支持放置左括号于JavaScript代码行的末尾,而不是新代码行开头的约定。正如这里所示,这不仅仅是JavaScript中的一个风格偏好。

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

答:NaN属性代表一个“不是数字”的值。这个特殊的值是因为运算不能执行而导致的,不能执行的原因要么是因为其中的运算对象之一非数字(例如:“abc”/3),要么是因为运算结果为非数字(例如:除数为0)。虽然这看上去很简单,但NaN有一些令人惊讶的特点,如果你不知道它的话,可能会导致令人头痛的bug。

    首先,NaN和任何东西做全等比较,包括它自身,结果返回的都为false,一种可靠的办法来测试一个数字是否是NaN,是使用函数isNaN(),但即使使用isNaN()依然并非是一个完美的解决方案。一个更好的解决办法是使用value!=value,如果值等于NaN,只会产生true。另外,ES6提供了一个新的Number.isNaN()函数,这是一个不同的函数,并且比老的全局isNaN()函数更可靠。

7、下列代码输出什么?为什么?

console.log(0.1+0.2);//输出结果为:0.30000000000000004
console.log(0.1+0.2==0.3);//输出结果为:false

JavaScript中的数字和浮点精度的处理相同,因此可能不会总产生预期的结果。

8、判断值x是否为整数的方法?

答:1、在ECMAScript6中使用number.isInteger()方法判断,如果是整数,则返回true,如果不是,则返回false.

       注:NaN 和正负 Infinity 不是整数

        例:number.isInteger(25)//true;

               number.isInteger(25.0)//true;

               number.isInteger(25.1)//false;

               number.isInteger("25")//false;

               number.isInteger(true)//false;

        2、function isInteger(x){return (x^0)===x;}

        3、function isInteger(x){return Math.round(x)===x};

         注:Math.ceil()和Math.floor()等同于Math.round()

        4、function isInteger(x){return (typeof x==="number")&&(x%1===0)}

        错误方法:function isInteger(x){return parseInt(x,10)===x;}

        解释:因为当x的取值足够大时,这个方法就会出错,因为当X值足够大时,它的字符串就会表达为指数形式,例如:1e+21,当使用parseInt()去判断时,输出的结果为1.

9、下列代码的输出结果是什么?为什么?

(function(){
        console.log(1);
        setTimeout(function (){console.log(2)},1000);
        setTimeout(function (){console.log(3)},0);
        console.log(4);
    })();//输出结果:1    4    3   2

解释:1和4之所以放到前面,是因为他们通过简单调用console.log()而没有任何延迟输出的

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

          但是,既然3是0毫秒延迟之后输出的,那么是否意味着它是立即输出呢?如果是的话,那么它是不是应该在4之前输出,既然4是在第二行输出的?原因是:浏览器有一个事件循环,会检查事件队列和处理未完成的事件。例如:如果事件发生在后台(例如:脚本的onload事件)时,浏览器正忙(例如,处理一个onclick),那么事件会添加到队列中。当onclick处理程序完成后,检查队列,然后处理该事件(例如,执行onload脚本)。同样的,setTimeout()也会把其引用的函数的执行放到事件队列中,如果浏览器正忙的话。当setTimeout()的第二个参数为0的时候,它的意思是“尽快”执行指定的函数。具体而言,函数的执行会放置在事件队列的下一个计时器开始。但是请注意,这不是立即执行:函数不会被执行除非下一个计时器开始。这就是为什么上述例子中,调用console.log(4)发生在console.log(3)是之前调用了。

 

posted @ 2017-09-11 11:21  mchtig  阅读(626)  评论(0编辑  收藏  举报