`
darrenzhu
  • 浏览: 804374 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JavaScript小技巧

阅读更多
关系javascript变量的内存堆栈介绍可参考
http://web.jobbole.com/81010/#comment-86438


参考链接:http://web.jobbole.com/81785/
问题1:闭包

考虑下面的代码:

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', function() {
      console.log('You clicked element #' + i);
   });
}
请问,如果用户点击第一个和第四个按钮,控制台上会输出什么?为什么?

答案

上面代码的目的在于检测JavaScript的一个重要概念:闭包。对于每一个JavaScript开发者来说,如果你想在网页中编写5行以上的代码,那么准确理解和恰当使用闭包是非常重要的。如果你想开始学习或者只是想简单地温习一下闭包,那么我强烈建议你去阅读这个教程:Colin Ihrig 写的JavaScript Closures Demystified 。

好了,回到上面的代码。控制台会输出两次You clicked element #NODES_LENGTH,其中#NODES_LENGTH等于nodes内的元素个数。当for循环结束时,变量i的值等于nodes的长度。另外,由于i是在事件被添加时的函数作用域,因此变量i属于事件的闭包。由于闭包中变量的值不是静态的,因而i的值并不是事件被添加时所赋予的值(比如添加第一个按钮时i为0,第二个按钮时i为1)。当事件被执行时,控制台会输出变量i当前的值,即i等于nodes的长度。

问题2:闭包

修复上题的问题,使得点击第一个按钮时输出1,点击第二个按钮时输出2。

答案

有多种办法解决这个问题,下面我给出其中的两种。

第一个解决方案要用到一个IIFE来创建另外一个闭包,从而得到所希望的i的值。相应的代码如下:

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', (function(i) {
      return function() {
         console.log('You clicked element #' + i);
      }
   })(i));
}
另一个解决方案不使用IIFE,而是将函数移到循环的外面,代码如下:

function handlerWrapper(i) {
   return function() {
      console.log('You clicked element #' + i);
   }
}

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', handlerWrapper(i));
}
问题3:数据类型

考虑如下代码:

console.log(typeof null);
console.log(typeof {});
console.log(typeof []);
console.log(typeof undefined);
答案

这一个问题看起来似乎有点傻,但是它测试了typeof 操作符的知识。很多JavaScript开发者并没有意识到typeof的独特性。在本例中,控制台会输出下面的内容:

object
object
object
undefined
最让人吃惊的输出结果可能是第三个,许多开发者认为typeof [ ] 会返回Array。如果想测试变量值是否为数组,可以写下面的代码:

var myArray = [];
if (myArray instanceof Array) {
   // do something...
}
问题4:事件循环

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

function printing() {
   console.log(1);
   setTimeout(function() { console.log(2); }, 1000);
   setTimeout(function() { console.log(3); }, 0);
   console.log(4);
}
printing();
答案
1,4,3,2
输出结果:
要弄懂数字为何以这种顺序输出,你需要弄明白setTimeout()是干什么的,以及浏览器的事件循环工作原理。浏览器有一个事件循环用于检查事件队列,处理延迟的事件。UI事件(例如,点击,滚动等),Ajax回调,以及提供给setTimeout()和setInterval()的回调都会依次被事件循环处理。因此,当调用setTimeout()函数时,即使延迟的时间被设置为0,提供的回调也会被排队。回调会呆在队列中,直到指定的时间用完后,引擎开始执行动作(如果它在当前不执行其他的动作)。因此,即使setTimeout()回调被延迟0毫秒,它仍然会被排队,并且直到函数中其他非延迟的语句被执行完了之后,才会执行。

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

问题5:算法

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

答案
我认为这是在面试中最常问到的一个问题。尽管这个问题反复出现并且也很简单,但是从候选人提供的答案中能很好地看出候选人的数学和算法能力水平。

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

需要记住的第二点,负数不是质数。同样的,1和0都不是,因此,要对这些数字做检测。另外,2是唯一的既是偶数又是质数的数字。没有必要用一个循环来验证4,6,8。再者,如果一个数字不能被2整除,它同样也不能被4,6,8等整除,因此你的循环需要跳过这些数字。可以采取其他一些更明智的优化手段,我这里采用的是适用于大多数情况的。例如,如果一个数字不能被5整除,它也不会被5的倍数整除。所以,没有必要检测10,15,20等等。如果你深入了解这个问题的解决方案,我建议你去看相关的Wikipedia介绍。

最后一点,你不需要检查比输入数字的开方还要大的数字。我感觉人们会遗漏掉这一点,并且也不会因为此而获得消极的反馈。但是,展示出这一方面的知识会给你额外加分。

现在你具备了这个问题的背景知识,下面是总结以上所有考虑的解决方案:

function isPrime(number) {
   // If your browser doesn't support the method Number.isInteger of ECMAScript 6,
   // you can implement your own pretty easily
   if (typeof number !== 'number' || !Number.isInteger(number)) {
      // Alternatively you can throw an error.
      return false;
   }
   if (number < 2) {
      return false;
   }

   if (number === 2) {
      return true;
   } else if (number % 2 === 0) {
      return false;
   }
   var squareRoot = Math.sqrt(number);
   for(var i = 3; i <= squareRoot; i += 2) {
      if (number % i === 0) {
         return false;
      }
   }
   return true;
}

结论

本文以问题和练习的形式讨论了另外几个重要的Javascript概念,这些都是前端开发者面试的重要内容。我希望你能顺利地回答这些问题,或者从这里学到一些新的东西,以便在下一次面试中有更好的表现




参考链接:http://web.jobbole.com/80564/
问题1:作用域

考虑如下代码:

(function() {

var a = b = 5;

})();

console.log(b);
请问控制台上会输出什么?

答案

输出:5

这一题的陷阱是,在函数表达式中有两个赋值,但a是用关键字var 来声明的,这意味着a是局部变量,而b则被赋予为全局变量。

另一个陷阱是,它并没有使用严格模式(use strict)。在函数里面,如果启用了严格模式,代码就会报错:“Uncaught ReferenceError: b is not defined”。请记住,严格模式需要你显式地引用全局作用域,代码应该写成:

(function() {

'use strict';

var a = window.b = 5;

})();

console.log(b);
问题2:创建“内置”方法

给String对象定义一个repeatify方法。该方法接收一个整数参数,作为字符串重复的次数,最后返回重复指定次数的字符串。例如:

console.log('hello'.repeatify(3));
输出应该是

hellohellohello.
答案

一个可行的做法如下:

String.prototype.repeatify = String.prototype.repeatify || function(times) {

var str = '';

for (var i = 0; i < times; i++) {

str += this;

}

return str;

};
这题测试开发者对Javascript的继承及原型属性的知识,它同时也检验了开发者是否能扩展内置数据类型的方法。

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

String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};
当你被问起去扩展一个Javascript方法时,这个技术非常有用。

问题3 :声明提前

下面这段代码的结果是什么?为什么?

function test() {

console.log(a);

console.log(foo());

var a = 1;

function foo() {

return 2;

}}

test();
答案

代码的运行结果:undefined和 2

理由是,变量和函数的声明都被提前至函数体的顶部,而同时变量并没有被赋值。因此,当打印变量a时,它虽存在于函数体(因为a已经被声明),但仍然是undefined。换句话说,上面的代码等同于下面的代码:

function test() {

var a;

function foo() {

return 2;

}

console.log(a);

console.log(foo());

a = 1;

}

test();
问题4:JavaScript中的this

下面代码的运行结果是什么并做解释。
var fullname = 'John Doe';

var obj = {

fullname: 'Colin Ihrig',

prop: {

fullname: 'Aurelio De Rosa',

getFullname: function() {

return this.fullname;

}}};

console.log(obj.prop.getFullname());

var test = obj.prop.getFullname;

console.log(test());
答案

代码输出:Aurelio De Rosa 和 John Doe

理由是,Javascript中关键字this所指代的函数上下文,取决于函数是怎样被调用的,而不是怎样被定义的。

在第一个console.log(),getFullname()被作为obj.prop对象被调用。因此,当前的上下文指代后者,函数返回这个对象的fullname属性。相反,当getFullname()被赋予test变量,当前的上下文指代全局对象window,这是因为test被隐式地作为全局对象的属性。基于这一点,函数返回window的fullname,在本例中即为代码的第一行。

问题5:call()和apply()

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

答案

这个问题可以通过运用call()或者apply()方法强制转换上下文环境。如果你不了解这两个方法及它们的区别,我建议你看看这篇文章What’s the difference between function.call and function.apply?. 下面的代码中我用了call(),但apply()也能产生同样的结果:

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

本文我们讨论了5个在对Javascript开发者面试中常问起的典型问题。实际中的问题会因面试的不同而不同,但是所涉及的概念和主题通常很类似。我希望你在检测自己的知识中获得乐趣。如果你不知道其中一些问题的答案,不要担心:没有什么是学习和试错不能够弥补的。如果你曾在面试中被问过其他的一些有趣的问题,不要犹豫,跟我们分享吧,它会帮助很多的开发者。
分享到:
评论

相关推荐

    JavaScript小技巧全集

    这篇“JavaScript小技巧全集”涵盖了各种实用的编程技巧,旨在帮助开发者提升效率,编写出更简洁、更高效的代码。以下是一些重要的JavaScript知识点,基于描述中的提示: 1. **变量声明与作用域**: - `let`、`...

    JavaScript小技巧全集 JavaScript教程 JavaScript源代码集

    这个“JavaScript小技巧全集”提供了丰富的教程和源代码,旨在帮助开发者深入理解和掌握JavaScript的各种实用技巧。 首先,我们来看看JavaScript的基本语法。JavaScript是一种弱类型、解释型的语言,它的变量声明不...

    javaScript小技巧。

    根据提供的文件内容,我们可以总结出以下几个JavaScript小技巧及相关知识点: ### 1. 引入外部JavaScript文件 在HTML文档中,可以通过`&lt;script&gt;`标签引入外部JavaScript文件来执行脚本代码。例如: ```html ...

    1000个javascript小技巧

    这本名为"1000个JavaScript小技巧"的资源集锦涵盖了各种实用的编程技巧,旨在帮助开发者提升效率,解决实际问题。以下是一些关键的知识点,将从这1000个小技巧中提炼出来: 1. **变量声明与作用域**:了解`var`、`...

    Javascript小技巧之生成html元素.docx

    7. **JavaScript编程的10个有用小技巧**和**12个特别有用的JavaScript小技巧【推举】**:这两篇文章分别分享了10个和12个实用的JavaScript编程技巧,是进阶学习的好资源。 总的来说,掌握生成HTML元素的技巧对...

    Javascript小技巧一箩筐

    ### JavaScript小技巧精粹 在Web开发领域,JavaScript作为一门不可或缺的编程语言,其灵活性与功能强大性使得它成为前端开发中的核心技能。本文将基于“JavaScript小技巧一箩筐”这一主题,深入探讨一系列实用的...

    javascript小技巧

    这个"javascript小技巧"的压缩包显然包含了诸多实用的JavaScript技术与窍门,旨在帮助初学者快速上手,同时也为有经验的开发者提供进一步提升技能的资源。以下是基于标题、描述和文件名推测出的一些JavaScript知识点...

    40种javascript小技巧

    ### JavaScript小技巧详解 #### 技巧1:屏蔽鼠标右键 通过在HTML元素上设置`oncontextmenu="window.event.returnValue=false"`属性,可以禁止用户在该元素上使用鼠标右键。例如: ```html ;"&gt; 无法右击此表格 ```...

    javascript小技巧全集

    这个"JavaScript小技巧全集"涵盖了各种实用的编程技巧,旨在帮助开发者提升效率,编写出更优雅、性能更好的代码。无论您是在Windows、MacOS还是Linux等任何操作系统上工作,这些技巧都是通用的。 一、函数与闭包 1....

    JavaScript小技巧整理篇(非常全).pdf

    ### JavaScript小技巧整理篇知识点详述 #### 一、引言 本文档旨在总结一系列JavaScript编程中的实用技巧,涵盖从基本操作到高级功能的应用。这些技巧不仅有助于提升开发效率,还能帮助开发者更好地理解和掌握...

    javascript小技巧合集

    标题:javascript小技巧合集 描述:本文将详细介绍一系列实用的JavaScript技巧,这些技巧涵盖了从基本的用户交互到更复杂的页面控制,旨在帮助开发者优化用户体验,增强网站安全性,并提升开发效率。 ### 重要技巧...

    常用的一些javascript小技巧

    ### 常用的一些JavaScript小技巧详解 在前端开发领域,JavaScript是不可或缺的编程语言,其灵活多变的特性使得开发者能够实现丰富的交互效果。本文将深入探讨一系列实用的JavaScript小技巧,帮助开发者提高编码效率...

    javascript小技巧归纳

    根据提供的文件信息,我们...以上列举的各项JavaScript小技巧涵盖了从基本的用户交互到更高级的功能实现,对于提高网站的用户体验及安全性都有着重要作用。开发者可以根据实际需求灵活运用这些技巧来优化自己的项目。

    JavaScript小技巧全集.doc

    本文将探讨几个实用的JavaScript小技巧,包括鼠标控制、显示日期和时间,以及利用历史记录和前进功能。 首先,让我们来看如何用鼠标控制Web页面。在JavaScript中,`onMouseOver`事件是一个非常有用的特性,允许我们...

Global site tag (gtag.js) - Google Analytics