JavaScript面试有什么ppt实用技巧的技巧吗?

JavaScript(39)
前端面试(6)
原文链接:
JavaScript 未声明变量直接使用会抛出异常:var name is not defined,如果没有处理异常,代码就停止运行了。
但是,使用typeof undeclared_variable并不会产生异常,会直接返回&undefined。
console.log(x);
console.log(typeof&y);&
console.log(z);&
var y = 1;
if (function f(){}) {
y += typeof
console.log(y);
正确的答案应该是&1undefined。
JavaScript中if语句求值其实使用eval函数,eval(function
f(){})&返回&function f(){}&也就是&true。
下面我们可以把代码改造下,变成其等效代码。
var k = 1;
eval(function foo(){});
k += typeof
console.log(k);
上面的代码输出其实就是&1undefined。为什么那?我们查看下&eval()&说明文档即可获得答案
该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。
恰恰&function f(){}&语句的返回值是&undefined,所以一切都说通了。
注意上面代码和以下代码不同。
var k = 1;
function foo(){};
k += typeof
console.log(k);
每一个对象都会创建一个private方法的方法,这样很耗费内存
观察下面代码
var Employee = function (name, company, salary) {
this.name = name || &&;
this.company = company || &&;
this.salary = salary || 5000;
var increaseSalary = function () {
this.salary = this.salary + 1000;
this.dispalyIncreasedSalary = function() {
increaseSlary();
console.log(this.salary);
var emp1 = new Employee(&John&,&Pluto&,3000);
var emp2 = new Employee(&Merry&,&Pluto&,2000);
var emp3 = new Employee(&Ren&,&Pluto&,2500);
在这里 emp1,emp2,emp3都有一个increaseSalary私有方法的副本。
所以我们除非必要,非常不推荐使用私有方法。
老生常谈的问题了,闭包是在一个函数里声明了另外一个函数,并且这个函数访问了父函数作用域里的变量。
下面给出一个闭包例子,它访问了三个域的变量
它自己作用域的变量
父函数作用域的变量
全局作用域的变量
var globalVar = &abc&;
(function outerFunction (outerArg) {
var outerFuncVar = 'x';
(function innerFunction (innerArg) {
var innerFuncVar = &y&;
console.log(
&outerArg = & + outerArg + &\n& +
&outerFuncVar = & + outerFuncVar + &\n& +
&innerArg = & + innerArg + &\n& +
&innerFuncVar = & + innerFuncVar + &\n& +
&globalVar = & + globalVar);
innerFunction is closure that is defined inside outerFunc
输出很简单:
outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc
console.log(mul(2)(3)(4));
console.log(mul(4)(3)(4));
答案直接给出:
function mul (x) {
return function (y) {
return function (z) {
return x * y *
简单说明下: mul 返回一个匿名函数,运行这个匿名函数又返回一个匿名函数,最里面的匿名函数可以访问 x,y,z 进而算出乘积返回即可。
对于JavaScript中的函数一般可以考察如下知识点:
函数是一等公民
函数可以有属性,并且能连接到它的构造方法
函数可以像一个变量一样存在内存中
函数可以当做参数传给其他函数
函数可以返回其他函数
var&arrayList = ['a','b','c','d','e','f'];
怎么清空&arrayList
arrayList = [];
直接改变arrayList所指向的对象,原对象并不改变。
arrayList.length =&0;
这种方法通过设置length=0 使原数组清除元素。
arrayList.splice(0, arrayList.length);
和方法2相似
使用 Object.prototype.toString 来判断是否是数组
function isArray(obj){
return Object.prototype.toString.call( obj ) === '[object Array]';
这里使用call来使 toString 中 this 指向 obj。进而完成判断
使用 原型链 来完成判断
function isArray(obj){
return obj.__proto__ === Array.
基本思想是利用 实例如果是某个构造函数构造出来的那么 它的&__proto__是指向构造函数的&prototype属性。
利用JQuery
function isArray(obj){
return $.isArray(obj)
JQuery isArray 的实现其实就是方法1
var output = (function(x){
console.log(output);
输出是&0。&delete&操作符是将object的属性删去的操作。但是这里的&x&是并不是对象的属性,&delete&操作符并不能作用。
var x = 1;
var output = (function(){
console.log(output);
输出是&1。delete&操作符是将object的属性删去的操作。但是这里的&x&是并不是对象的属性,&delete&操作符并不能作用。
var x = { foo : 1};
var output = (function(){
console.log(output);
输出是&undefined。x虽然是全局变量,但是它是一个object。delete作用在x.foo上,成功的将x.foo删去。所以返回undefined
var Employee = {
company: 'xyz'
var emp1 = Object.create(Employee);
delete pany
console.pany);
输出是&xyz,这里的 emp1 通过 prototype 继承了 Employee的 company。emp1自己并没有company属性。所以delete操作符的作用是无效的。
在chrome下执行如下代码,我们就可以看到undefined x 1的身影。
var trees = [&redwood&,&bay&,&cedar&,&oak&,&maple&];
delete trees[3];
console.log(trees);
当我们使用 delete 操作符删除一个数组中的元素,这个元素的位置就会变成一个占位符。打印出来就是undefined x 1。
注意如果我们使用trees[3] === 'undefined × 1'返回的是&false。因为它仅仅是一种打印表示,并不是值变为undefined
var trees = [&xyz&,&xxxx&,&test&,&ryan&,&apple&];
delete trees[3];
console.log(trees.length);
输出是5。因为delete操作符并不是影响数组的长度。
var bar = true;
console.log(bar + 0);
console.log(bar + &xyz&);
console.log(bar + true);
console.log(bar + false);
下面给出一个加法操作表
Number + Number -& 加法
Boolean + Number -& 加法
Boolean + Boolean -& 加法
Number + String -& 连接
String + Boolean -& 连接
String + String -& 连接
var z = 1, y = z = typeof
console.log(y);
输出是&undefined。js中赋值操作结合律是右至左的 ,即从最右边开始计算值赋值给左边的变量。
上面代码等价于
z = typeof
console.log(y);
var foo = function bar(){ return 12; };
typeof bar();
输出是抛出异常,bar is not defined。
如果想让代码正常运行,需要这样修改代码:
var bar = function(){ return 12; };
typeof bar();
function bar(){ return 12; };
typeof bar();
明确说明这个下问题
var foo = function bar(){
console.log(typeof bar());
var foo = function(){
function bar(){
foo的定义是在运行时。想系统说明这个问题,我们要引入变量提升的这一概念。
我们可以运行下如下代码看看结果。
console.log(foo)
console.log(bar)
var foo = function(){
function bar(){
function bar(){
为什么那?为什么 foo 打印出来是 undefined,而 bar打印出来却是函数?
JavaScript在执行时,会将变量提升。
所以上面代码JavaScript 引擎在实际执行时按这个顺序执行。
function bar(){
console.log(foo)
console.log(bar)
foo = function(){
原代码的输出合理解释了。
var salary = &1000$&;
(function () {
console.log(&Original salary was & + salary);
var salary = &5000$&;
console.log(&My New Salary & + salary);
Original salary was undefined
My New Salary 5000$
这题同样考察的是变量提升。等价于以下代码
var salary = &1000$&;
(function () {
console.log(&Original salary was & + salary);
salary = &5000$&;
console.log(&My New Salary & + salary);
function foo(){
console.log(new foo() instanceof foo);
instanceof操作符用来判断是否当前对象是特定类的对象。
function Animal(){
return this;
var dog = new Animal();
dog instanceof Animal
但是,这里的foo定义为
function foo(){
var bar = new foo();
所以&new foo() instanceof foo&返回 false
var counterArray = {
counterArray[&C&] = 1;
其实答案很简单,直接计算key的数量就可以了。
Object.keys(counterArray).length&
面试题参考自:&
本文给出的面试题答案只是很多合理答案中的几个,可能会不全面,欢迎大家补充。
由于个人疏忽等原因,本文中难免会存在少量错误,欢迎大家批评指正。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:9163次
排名:千里之外
原创:43篇
转载:58篇
(2)(27)(19)(27)(17)(3)(6)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;
欢迎您订阅我们的技术周刊
我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,
欢迎分享您的观点,经验,技巧,心得
让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;
本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(
订阅邮件周刊
我被问得最多的十个JavaScript前端面试问题
注意 转载须保留原文链接,译文链接,作者译者等信息。&&
过去几个月我一直在面试前端有关的职位,在面试环节经常被问到一些技术问题。我觉得可以跟大家分享一下。两次面试是通过在线答题进行的,两次是面对面,还有两是通过skype。我申请的职位都是非常非常初级的,不是 中级/资深的职位。我知道有很多人不同意这种类型的面试。其实不管你喜不喜欢,你都得接受。尤其当你是自学的,而且要申请第一份工作时。我估计很多有人其它方法来证明他自己,像Github/ 项目地址可能是非常理想的证明方法,但也别全都指望这些。好消息是有一些很难的问题,在有限的时间里我没答上来(比如说Event Loop和杨辉三角),一些其它面试侯选人也承认他们也没答上来,这会让讨论变得轻松很多。坏消息是有些面试之后就没有任何反馈了。有三家公司再也没联系过。这点击打击自信,而且没有受到尊重。然后你可能会有心理斗争,“面试的不够好?”,“他们不喜欢我这种类型?”。所以如果你是面试官,请给你的面试者一个明确的答复,即使是自动回复也比什么都没有的强。1. 设计一个函数返回第n行的杨辉三角。(整个面试只有这一个问题)注* 杨辉三角也叫Pascal’s Triangle
...2. 设计一个函数,返回一串字符串中重复次最多的单词。3. 使用递归打印长度为n的费波那契数列。注* 费波那契数列由0和1开始,之后就由之前的两数相加 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 2334. 解释一下 bind, apply和call的用法和区别。5. 解释一下什么是event delegation(事件代理)和它为什么有用。6. 什么是event loop (事件循环)?7. hoisting(声明提升)在JavaScript里是怎么工作的?8. 描述一下你在设计应用或网站时的流程。9. 你最希望JavaScript或浏览器中添加哪些功能,为什么?10. 函数式编程和命令式编程之间的区别?你喜欢哪一个?注* 答案请参考 reddit 原文注*
原文地址:
&热门文章 - 分享最多
&相关阅读 - 求职面试
&关键字 - 前端
&欢迎订阅 - 技术周刊
我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;
我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊502 Bad Gateway
502 Bad Gateway
openresty/1.11.2.2中国领先的IT技术网站
51CTO旗下网站
25个最基本的JavaScript面试问题及答案
本文主要分享一下25个最基本的JavaScript面试问题及答案,希望对大家有所帮助。
作者:佚名来源:| 10:36
1、使用 typeof bar === &object& 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱?
尽管 typeof bar === &object& 是检查 bar 是否对象的可靠方法,令人惊讶的是在JavaScript中 null
也被认为是对象!
因此,令大多数开发人员惊讶的是,下面的代码将输出 true (而不是false) 到控制台:
var&bar&=&null;&console.log(typeof&bar&===&&object&);&//&logs&true!&
只要清楚这一点,同时检查 bar 是否为 null,就可以很容易地避免问题:
console.log((bar&!==&null)&&&&(typeof&bar&===&&object&));&//&logs&false&
要答全问题,还有其他两件事情值得注意:
首先,上述解决方案将返回 false,当 bar 是一个函数的时候。在大多数情况下,这是期望行为,但当你也想对函数返回 true
的话,你可以修改上面的解决方案为:
console.log((bar&!==&null)&&&&((typeof&bar&===&&object&)&||&(typeof&bar&===&&function&)));&
第二,上述解决方案将返回 true,当 bar 是一个数组(例如,当 var bar =
[];)的时候。在大多数情况下,这是期望行为,因为数组是真正的对象,但当你也想对数组返回 false 时,你可以修改上面的解决方案为:
console.log((bar&!==&null)&&&&(typeof&bar&===&&object&)&&&&(toString.call(bar)&!==&&[object&Array]&));&
或者,如果你使用jQuery的话:
console.log((bar&!==&null)&&&&(typeof&bar&===&&object&)&&&&(!&$.isArray(bar)));&
2.下面的代码将输出什么到控制台,为什么?
(function(){&var&a&=&b&=&3;&})();console.log(&a&defined?&&&+&(typeof&a&!==&'undefined'));&console.log(&b&defined?&&&+&(typeof&b&!==&'undefined'));&
由于 a 和 b 都定义在函数的封闭范围内,并且都始于 var关键字,大多数JavaScript开发人员期望 typeof a 和 typeof b
在上面的例子中都是undefined。
然而,事实并非如此。这里的问题是,大多数开发人员将语句 var a = b = 3; 错误地理解为是以下声明的简写:
var&b&=&3;&var&a&=&b;&
但事实上,var a = b = 3; 实际是以下声明的简写:
b&=&3;&&var&a&=&b;&
因此(如果你不使用严格模式的话),该代码段的输出是:
a&defined?&falseb&defined?&true&
但是, b 如何才能被定义在封闭函数的范围之外呢?是的,既然语句 var a = b =3; 是语句 b = 3; 和 var a =的简写, b 最终成为了一个全局变量(因为它没有前缀 var
关键字),因此仍然在范围内甚至封闭函数之外。
需要注意的是,在严格模式下(即使用 use strict),语句var a = b = 3; 将生成ReferenceError: b is not
defined的运行时错误,从而避免任何否则可能会导致的headfakes /bug。 (还是你为什么应该理所当然地在代码中使用 use strict
的最好例子!)
3.下面的代码将输出什么到控制台,为什么?
var&myObject&=&{&&&&&&&foo:&&bar&,&&&&&&&&&&&func:&function()&{&&&&&&&&&&&&&&var&self&=&&&&&&&&&&&&&&&&&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&=&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命名空间。在完成这项工作之后,你的代码仍然可以使用$ 利用这种闭包技术,如下所示:
(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.考虑以下两个函数。它们会返回相同的东西吗? 为什么相同或为什么不相同?
function&foo1()&{&&return&{&bar:&&hello&&};&&}&&function&foo2()&{&&return&{&bar:&&hello&&};&&}&
出人意料的是,这两个函数返回的内容并不相同。更确切地说是:
console.log(&foo1&returns:&);&&console.log(foo1());&&console.log(&foo2&returns:&);&&console.log(foo2());&
foo1&returns:Object&{&&&bar:&&hello&&}&foo2&returns:undefined&
这不仅是令人惊讶,而且特别让人困惑的是, foo2()返回undefined却没有任何错误抛出。
原因与这样一个事实有关,即分号在JavaScript中是一个可选项(尽管省略它们通常是非常糟糕的形式)。其结果就是,当碰到 foo2()中包含
return语句的代码行(代码行上没有其他任何代码),分号会立即自动插入到返回语句之后。
也不会抛出错误,因为代码的其余部分是完全有效的,即使它没有得到调用或做任何事情(相当于它就是是一个未使用的代码块,定义了等同于字符串 &hello&的属性
这种行为也支持放置左括号于JavaScript代码行的末尾,而不是新代码行开头的约定。正如这里所示,这不仅仅只是JavaScript中的一个风格偏好。
7. NaN 是什么?它的类型是什么?你如何可靠地测试一个值是否等于 NaN ?
NaN 属性代表一个&不是数字&的值。这个特殊的值是因为运算不能执行而导致的,不能执行的原因要么是因为其中的运算对象之一非数字(例如, &abc& /
4),要么是因为运算的结果非数字(例如,除数为零)。
虽然这看上去很简单,但 NaN 有一些令人惊讶的特点,如果你不知道它们的话,可能会导致令人头痛的bug。
首先,虽然 NaN 意味着&不是数字&,但是它的类型,不管你信不信,是 Number:
console.log(typeof&NaN&===&&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.00004&false&
9.讨论写函数 isInteger(x) 的可能方法,用于确定x是否是整数。
这可能听起来是小菜一碟,但事实上,这很琐碎,因为ECMAScript 6引入了一个新的正以此为目的 Number.isInteger()
函数。然而,之前的ECMAScript 6,会更复杂一点,因为没有提供类似的 Number.isInteger() 方法。
问题是,在ECMAScript规格说明中,整数只概念上存在:即,数字值总是存储为浮点值。
考虑到这一点,最简单又最干净的ECMAScript6之前的解决方法(同时也非常稳健地返回 false ,即使一个非数字的值,如字符串或 null
,被传递给函数)如下:
function&isInteger(x)&{&&&&return&(x^0)&===&x;&}&
下面的解决方法也是可行的,虽然不如上面那个方法优雅:
function&isInteger(x)&{&&&&return&Math.round(x)&===&x;&}&
请注意 Math.ceil() 和 Math.floor() 在上面的实现中等同于 Math.round()。
function&isInteger(x)&{&&&&return&(typeof&x&===&'number')&&&&(x&%&1&===&0);&}&
相当普遍的一个不正确的解决方案是:
function&isInteger(x)&{&&&&return&parseInt(x,&10)&===&x;&&}&
虽然这个以 parseInt函数为基础的方法在 x 取许多值时都能工作良好,但一旦 x 取值相当大的时候,就会无法正常工作。问题在于 parseInt()
在解析数字之前强制其第一个参数到字符串。因此,一旦数目变得足够大,它的字符串就会表达为指数形式(例如, 1e+21)。因此,parseInt() 函数就会去解析
1e+21,但当到达 e字符串的时候,就会停止解析,因此只会返回值 1。注意:
&&String()&&&'1e+21'&&&&&&parseInt(,&10)&&&1&&&&&&parseInt(,&10)&===&&&&&false&
10.下列代码行1-4如何排序,使之能够在执行代码时输出到控制台? 为什么?
(function()&{&&&&console.log(1);&&&setTimeout(function(){console.log(2)},&1000);&&&&&&&setTimeout(function(){console.log(3)},&0);&&&&console.log(4);&&})();&
序号如下:
让我们先来解释比较明显而易见的那部分:
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。
function&isPalindrome(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&5&console.log(sum(2)(3));&//&Outputs&5&
(至少)有两种方法可以做到:
function&sum(x)&{&&&&if&(arguments.length&==&2)&{&&&&&&&&return&arguments[0]&+&arguments[1];&&&}&&&&else&&&{&&&&&&&&return&function(y)&{&return&x&+&y;&};&&&&&}&}&
在JavaScript中,函数可以提供到 arguments 对象的访问,arguments 对象提供传递到函数的实际参数的访问。这使我们能够使用
length 属性来确定在运行时传递给函数的参数数量。
如果传递两个参数,那么只需加在一起,并返回。
否则,我们假设它被以 sum(2)(3)这样的形式调用,所以我们返回一个匿名函数,这个匿名函数合并了传递到
sum()的参数和传递给匿名函数的参数。
function&sum(x,&y)&{&&&&if&(y&!==&undefined)&{&&&&&&&&return&x&+&y;&&&&&}&&&&else&&&&{&&&&&&&&&return&function(y)&{&return&x&+&y;&};&&&&&}&}&
当调用一个函数的时候,JavaScript不要求参数的数目匹配函数定义中的参数数量。如果传递的参数数量大于函数定义中参数数量,那么多余参数将简单地被忽略。另一方面,如果传递的参数数量小于函数定义中的参数数量,那么缺少的参数在函数中被引用时将会给一个
undefined值。所以,在上面的例子中,简单地检查第2个参数是否未定义,就可以相应地确定函数被调用以及进行的方式。
13.请看下面的代码片段:
for&(var&i&=&0;&i&&&5;&i++)&{&&&&var&btn&=&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&(var&i&=&0;&i&&&5;&i++)&{&&&&&&var&btn&=&document.createElement('button');&&&&&&btn.appendChild(document.createTextNode('Button&'&+&i));&&&&&&btn.addEventListener('click',&(function(i)&{&return&&function()&{&console.log(i);&};&})(i));&&&&&&document.body.appendChild(btn);&}&
或者,你可以封装全部调用到在新匿名函数中的 btn.addEventListener :
for&(var&i&=&0;&i&&&5;&i++)&{&&&&&&var&btn&=&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)&{&&&&&&var&btn&=&document.createElement('button');&&&&&&&&&btn.appendChild(document.createTextNode('Button&'&+&i));&&&&&&&&&&btn.addEventListener('click',&function()&{&console.log(i);&});&&&&&&&&&&document.body.appendChild(btn);&&&});&
14.下面的代码将输出什么到控制台,为什么?
var&arr1&=&&john&.split('');&var&arr2&=&arr1.reverse();&&var&arr3&=&&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.下面的递归代码在数组列表偏大的情况下会导致堆栈溢出。在保留递归模式的基础上,你怎么解决这个问题?
var&list&=&readHugeList();&&var&nextListItem&=&function()&{&&&&&&var&item&=&list.pop();&&&&&&if&(item)&{&&&&&&&&//&process&the&list&item...&nextListItem();&&&&&&}&};&
潜在的堆栈溢出可以通过修改nextListItem 函数避免:
var&list&=&readHugeList();&&var&nextListItem&=&function()&{&&&&&&var&item&=&list.pop();&&&&&&if&(item)&{&&&&&&&&&&//&process&the&list&item...&setTimeout(&nextListItem,&0);&&&&&&&&&&}&};&
堆栈溢出之所以会被消除,是因为事件循环操纵了递归,而不是调用堆栈。
当 nextListItem 运行时,如果
item不为空,timeout函数(nextListItem)就会被推到事件队列,该函数退出,因此就清空调用堆栈。当事件队列运行其timeout事件,且进行到下一个
item 时,定时器被设置为再次调用
nextListItem。因此,该方法从头到尾都没有直接的递归调用,所以无论迭代次数的多少,调用堆栈保持清空的状态。
17.JavaScript中的&闭包&是什么?请举一个例子。
闭包是一个可以访问外部(封闭)函数作用域链中的变量的内部函数。闭包可以访问三种范围中的变量:这三个范围具体为:(1)自己范围内的变量,(2)封闭函数范围内的变量,以及(3)全局变量。
下面是一个简单的例子:
var&globalVar&=&&xyz&;&(function&outerFunc(outerArg)&{&&&&&var&outerVar&=&'a';&&&&&&(function&innerFunc(innerArg)&{&&&&&&&&&&var&innerVar&=&'b';&&&&&&&&&&console.log(&&outerArg&=&&&+&outerArg&+&&&&+&&innerArg&=&&&+&innerArg&+&&&&+&&outerVar&=&&&+&outerVar&+&&&&+&&innerVar&=&&&+&innerVar&+&&&&+&&globalVar&=&&&+&globalVar);&&&&&})(456);&})(123);&
在上面的例子中,来自于 innerFunc, outerFunc和全局命名空间的变量都在 innerFunc的范围内。因此,上面的代码将输出如下:
outerArg&=&123&&innerArg&=&456&&outerVar&=&a&&innerVar&=&b&&globalVar&=&xyz&
18.下面的代码将输出什么:
解释你的答案。闭包在这里能起什么作用?
上面的代码不会按预期显示值0,1,2,3,和4,而是会显示5,5,5,5,和5。
原因是,在循环中执行的每个函数将整个循环完成之后被执行,因此,将会引用存储在 i中的最后一个值,那就是5。
闭包可以通过为每次迭代创建一个唯一的范围,存储范围内变量的每个唯一的值,来防止这个问题,如下:
for&(var&i&=&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&=&1&&&&1&||&2&=&1&&&&0&&&&1&=&0&&&&1&&&&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')&
代码将输出:
true&&false&
在JavaScript中,有两种等式运算符。三个等于运算符 ===
的作用类似传统的等于运算符:如果两侧的表达式有着相同的类型和相同的值,那么计算结果为true。而双等于运算符,会只强制比较它们的值。因此,总体上而言,使用
===而不是 ==的做法更好。 !==vs !=亦是同理。
21.以下代码将输出什么?并解释你的答案。
var&a={},&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((function&f(n){return&((n&&&1)&?&n&*&f(n-1)&:&n)})(10));&
并解释你的答案。
代码将输出10!的值(即10!或3628800)。
f(1): returns n, which is 1 f(2): returns 2 * f(1), which is 2 f(3): returns
3 * f(2), which is 6 f(4): returns 4 * f(3), which is 24 f(5): returns 5 * f(4),
which is 120 f(6): returns 6 * f(5), which is 720 f(7): returns 7 * f(6), which
is 5040 f(8): returns 8 * f(7), which is 40320 f(9): returns 9 * f(8), which is
362880 f(10): returns 10 * f(9), which is 3628800
命名函数 f()递归地调用本身,当调用 f(1)的时候,只简单地返回1。下面就是它的调用过程:
23.请看下面的代码段。控制台将输出什么,为什么?
(function(x)&{&return&(function(y)&{&console.log(x);&})(2)&})(1);&
控制台将输出 1,即使从来没有在函数内部设置过x的值。原因是:
正如我们在JavaScript招聘指南中解释过的那样,闭包是一个函数,连同在闭包创建的时候,其范围内的所有变量或函数一起。在JavaScript中,闭包是作为一个&内部函数&实施的:即,另一个函数主体内定义的函数。闭包的一个重要特征是,内部函数仍然有权访问外部函数的变量。
因此,在本例中,由于 x未在函数内部中定义,因此在外部函数范围中搜索定义的变量 x,且被发现具有1的值。
24.下面的代码将输出什么到控制台,为什么:
var&hero&=&{&_name:&'John&Doe',&getSecretIdentity:&function&(){&return&this._&}&};&var&stoleSecretIdentity&=&hero.getSecretI&console.log(stoleSecretIdentity());&console.log(hero.getSecretIdentity());&
代码有什么问题,以及应该如何修复。
代码将输出:
undefined&&John&&Doe&
第一个 console.log之所以输出 undefined,是因为我们正在从 hero对象提取方法,所以调用了全局上下文中(即窗口对象)的
stoleSecretIdentity(),而在此全局上下文中, _name属性不存在。
其中一种修复stoleSecretIdentity() 函数的方法如下:
var&stoleSecretIdentity&=&hero.getSecretIdentity.bind(hero);&
25.创建一个给定页面上的一个DOM元素,就会去访问元素本身及其所有子元素(不只是它的直接子元素)的函数。对于每个被访问的元素,函数应该传递元素到提供的回调函数。
此函数的参数为:
回调函数(将DOM元素作为其参数)
访问树(DOM)的所有元素是经典的深度优先搜索算法应用。下面是一个示范的解决方案:
function&Traverse(p_element,p_callback)&{&&&&&&p_callback(p_element);&&&&&&var&list&=&p_element.&&&&&&for&(var&i&=&0;&i&&&list.&i++)&{&&&&&&&&&&&&&Traverse(list[i],p_callback);&&&&&&&&&&&//&recursive&call&&&&&&}&}&&【编辑推荐】【责任编辑: TEL:(010)】
大家都在看猜你喜欢
头条头条热点头条原创
24H热文一周话题本月最赞
讲师:431226人学习过
讲师:747789人学习过
讲师:131861人学习过
精选博文论坛热帖下载排行
本书重点讲解如何用实用的代码来解决具体的实际问题。本书的内容覆盖面很广,从新的C#范型到Web服务,从反射到安全等都有涉及。系统地介绍...
订阅51CTO邮刊}

我要回帖

更多关于 游泳必备基础实用技巧 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信