面试(-)

0.作用域

考虑以下代码:

 

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

 

控制台会打印出什么?

答案

上述代码打印出5

这个问题的陷阱,在立即执行函数表达式中,有两个赋值,但其中变量a使用关键词var来声明。这就意味着a是这个函数的局部变量。与此相反,b被分配了全局作用域。

另一个陷阱,函数没有使用“严格模式”。如果严格模式开启,那么代码会报错“b is not defined”.请记住,如果这是预期的行为,严格模式要求你显式地引用全局作用域。需要这么写:

 

1 (function(){
2     "use strict";
3      var a = window.b = 5; 
4 })()
5 
6 console.log(b)

 

1.创建"原生"方法

String对象上定义一个repeatify函数。这个函数接受一个整数参数,来明确字符串需要重复几次。这个函数要求字符串重复指定的次数。举例:

console.log("hello".repeatify(3));

应该打印出hellohellohello

答案

可行做法如下:

1 String.prototype.repeatify = String.prototype.repeatify || function(times){
2   var str = '';
3   for(var i=0;i<times;i++){
4      str += this;  
5   }      
6   return str;
7 }

这个问题测试了开发人员对JavaScript中继承及原型属性的知识。这也验证了开发人员是否有能力扩展原生数据类型的功能。

在这里,另一个关键点是,看你怎样避免重写可能已经定义了的方法。这可以通过在定义自己的方法之前,检测方法是否已经存在。

1 String.prototype.repeatify = String.prototype.repeatify || function(times){
2 /*code here*/
3 }

2.变量提升

执行以下代码结果是什么?为什么?

 1 function test(){
 2    console.log(a);
 3    console.log(foo());
 4 
 5    var a= 1;
 6    function foo(){
 7       return 2;    
 8   }  
 9 }
10 test();

答案

这段代码的执行结果是undefined和2.

这个结果的原因是,变量和函数都被提升到了函数整体的顶部。因此,当打印变量a时。它虽存在于函数体,但仍然是undefined。换言之,上述代码等同于下面代码:

function test(){
  var a;
  function foo(){
    return 2;
  }  
  console.log(a);
  console.log(foo());

  a=1;
}
test()

3.在JavaScript中,"this"是如何工作的

以下代码的结果是什么?解释你的答案。

 

 1 var fullname = 'John Doe';
 2 var obj = {
 3    fullname:'Colin Ihrig',
 4    prop:{
 5          fullname:'Aurelio De Rosa',
 6          getFullname:function(){
 7              return this.fullname;  
 8          }  
 9     }  
10 }
11 console.log(obj.prop.getFullname()); 
12 var test = obj.prop.getFullname;
13 console.log(test());

 

打印结果是:Aurelio De Rosa 和  John Doe 。因为JavaScript中关键字this所引用的是函数上下文,取决于函数是如何调用的,而不是怎么被定义的。

在第一个console.log(),getFullname()是作为obj.prop对象的函数被调用。因此,当前的上下文指代后者,并且函数返回这个对象的fullname属性。但当getFullname()被赋值给test变量时,当前的上下文是全局对象window,这是因为test被隐式地作为全局对象的属性。基于这一点,函数返回window的fullname,第一行代码设置的。

 

 

 4.call()和apply()

修改前一个问题,让最后一个console.log(test())打印输出Aurelio De Rosa

这个问题可以应用call()或者apply()方法强制转换上下文环境。

 

console.log(test.call(obj.prop));

 

5.闭包

以下代码结果是什么,解释一下。

 1 var count = 10;   //全局作用域 标记为flag1
 2 function add(){
 3   var count = 0;   //函数全局作用域  标记为flag2
 4   return function(){
 5      count+=1;     //函数的内部作用域
 6      alert(count)
 7   }  
 8 }
 9 var s = add();
10 s();
11 s();

第一个s()输出1,第二个s()输出2

根据作用域链的规则,底层作用域没有声明的变量,会向上一级找,找到就返回,没找到就一直找,直到window的变量,没有就返回undefined.这里明显count是函数内部的flag2的那个count。

定义:当一个函数的返回值是另一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。

表现形式:使函数外部能够调用函数内部定义的变量。

变量的作用域分类:全局变量和局部变量

特点:

1.函数内部可以读取函数外部的全局变量;在函数外部无法读取函数内部的局部变量。

2.函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量。

使用闭包注意:

1.滥用闭包,会造成内存泄漏,由于闭包会使得函数中的变量被保持在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,IE中可能导致内存泄漏。解决方案,退出函数之前,将不使用的局部变量全部删除。

2.会改变父函数的内部变量的值。所以,如果你把父函数当作对象使用,把闭包当作它的公用方法,把内部变量当作它的私有属性,这时一定要小心,不要随便改变父函数内部变量的值。

 6.数据类型

考虑如下代码:

 

1 console.log(typeof null);
2 console.log(typeof {});
3 console.log(typeof []);
4 console.log(typeof undefined);

 

答案

考察typeof操作符的知识。很多JavaScript开发人员不知道typeof的一些特性。控制台将显示以下内容:

1 object
2 object
3 object
4 undefined

最令人惊讶的输出结果可能是第三个。大多数开发人员认为typeof()会返回Array。如果你想测试一个变量是否为数组,您可以执行以下测试:

1 var myArray = [];
2 if(myArray instanceof Array){
3       //do something
4 }

7.事件循环

下面代码运行结果是什么?请解释。

1 function printing(){
2     console.log(1);
3     setTimeout(function(){console.log(2)},1000);
4     setTimeout(function(){console.log(3)},0);
5     console.log(4);
6 }
7 printing();

答案

输出结果:

1
4
3
2

想知道为什么输出顺序是这样的,你需要了解setTimeout()做了什么,以及浏览器的事件循环原理。浏览器有一个事件循环用于检查事件队列,处理延迟的事件。UI事件(例如,点击,滚动等),Ajax回调,以及提供给setTimeout()和setInterval()的回调都会依次被事件循环处理。因此,当调用setTimeout()函数时,即使延迟的时间被设置为0,提供的回调都会依次被事件循环处理。回调会呆在队列中,直到指定的时间用完后,引擎开始执行动作(如果它在当前不执行其他动作)。因此,即使setTimeout()回调被延迟0毫秒,它仍然会被排队,并且直到函数中其他非延迟的语句被执行完了之后,才会执行。

有了这些认识,理解输出结果为“1”就容易了,因为它是函数的第一句并且没有使用setTimeout()函数来延迟。接着输出“4”,因为它是没有被延迟的数字,也没有进行排队。然后,剩下了“2”,“3”,两者都被排队,但是前者需要等待一秒,后者等待0秒(意味着引擎完成前两个输出之后马上进行)。这就解释了为什么“3”在“2”之前。

8.算法

写一个isPrime()函数,当其为质数时返回true,否则返回false。

答案

首先,因为JavaScript不同于c或者java,因此你不能信任传递来的数据类型。如果面试官没有明确地告诉你,你应该询问他是否需要做输入检查,还是不进行检查直接写函数。严格上说,应该对函数的输入进行检查。

第二点要记住:负数不是质数。同样的,1和0也不是,因此,首先测试这些数字。此外,2是质数中唯一的偶数。没有必要用一个循环来验证4,6,8.再则,如果一个数字不能被2整除,那么它不能被4,6,8等整除。因此,你的循环必须跳过这些数字。如果你测试输入偶数,你的算法将慢2倍。可以采取其他一些更明智的优化手段,这里采用的是适用于大多数情况的。例如,如果一个数字不能被5整除,它也不会被5的倍数整除。所以,没有必要检测10,15,20等。

最后一点,你不需要检查比输入数字的开方还要大的数字。

 1 function isPrime(number){
 2    if(typeof number !== 'number' || !Number.isInteger(number)){
 3          return false;
 4     }
 5     if(number < 2){
 6          return false;
 7    }
 8    if(number === 2){
 9         return true;
10    }else if(number % 2 === 0){
11         return false;
12    }
13 
14    var squareRoot = Math.sqrt(number);
15    for(var i=3;i<=squareRoot;i+=2){
16       if(number % i === 0){
17              return false;
18       }
19   }  
20   return true;
21 }

原文:http://www.css88.com/archives/7052

 

转载于:https://www.cnblogs.com/jzgod/p/8819258.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值