面试题WEB前端常见面试题汇总:(一).docx
试题WEB前端常见试题汇总:( )1. JS找字符串中出现最多的字符例如:求字符串'nininihaoa'中出现次数最多字符var str = "nininihaoa" var o = ;for (var i = 0, length = str.length; i < length; i+) var char = str.charAt(i);if (ochar) ochar+; /次数加1 else ochar = 1; /若第次出现,次数记为1console.log(o); /输出的是完整的对象,记录着每个字符及其出现的次数/遍历对象,找到出现次数最多的字符的次数var max = 0;for (var key in o) if (max < okey) max = okey; /max始终储存次数最的那个for (var key in o) if (okey = max) /console.log(key);console.log("最多的字符是" + key); console.log("出现的次数是" + max);法:结果如图所:var arrString = 'abcdaabc' arrString.split('').reduce(function(res, cur) rescur ? rescur + : rescur = 1return res;, )法,当然还可以使reduce法来实现:想详细了解reduce()法,可以参考:2. JS实现九九乘法表var sum=0; var wite;for (var i = 1; i < 10; i+)var div=$('<div class="class'+i+'"></div>');$("body").append(div);for(var j = i; j > 0; j-) sum = j * i;wite = (j+"X"+i+"="+sum);div.prepend($('<span style="padding-right:10px">'+wite+'</span>');jQuery实现式:实现结果如图所:原js实现式: css代码:html,body,ul,li padding: 0;margin: 0;border: 0;ul width: 900px; overflow: hidden; margin-top: 4px; font-size: 12px; line-height: 36px;li float: left; width: 90px; margin: 0 4px;display: inline-block; text-align: center; border: 1px solid #333;background:yellowgreen;js代码:for(var i = 1; i <= 9; i+)var myUl = document.createElement('ul'); for(var j = 1; j <= i; j+)var myLi = document.createElement('li');var myText = document.createTextNode(j + " × " + i + " = " + i*j); myLi.appendChild(myText);myUl.appendChild(myLi);document.getElementsByTagName('body')0.appendChild(myUl);原js实现效果如图所3. 前端试:这道前端试题很绕吗?做对了道?第题var fun = function() this.name = 'peter' return name: 'jack'var p = new fun();/请问p.name是:第题var fun = function() this.name = 'peter'return 'jack'var p = new fun();/请问p.name是:第三题var fun = function() fun.prototype = info : name : 'peter', age : 25var a = new fun(); var b = new fun();a.info.name = 'jack' b.info.name = 'tom'/请问a.info.name和b.info.name分别是:第四题var fun = function() this.info = name : 'peter', age : 25var a = new fun(); var b = new fun();a.info.name = 'jack' b.info.name = 'tom'/请问a.info.name和b.info.name分别是:第五题var fun = function() fun.prototype = name : 'peter', age : 25var a = new fun(); var b = new fun();a.name = 'jack' b.name = 'tom'/请问a.name和b.name分别是:第六题var fun = function() this.info = name : 'peter', age : 25fun.prototype = info : name : 'peter', age : 25var a = new fun(); var b = new fun();a.info.name = 'jack' b.info.name = 'tom'/请问a.info.name和b.info.name分别是:解答:1,2题考察的是构造函数的返回值的问题。每个函数都有返回值,如果使了return语句,则返回return后跟的值,如果没有使return,则默认返回undefined.特别的,如果这个函数是构造函数,则默认返回this对象,如果构造函数内使了return语句,并且return后跟的是个对象,则这个构造函数返回的是这个对 象,否则返回this.所以1题中的p = name: 'jack',2题中的p = name: 'peter'.3, 4, 5, 6题都是考察prototype的知识。1. 先查找构造函数实例的属性或法,如果有,就即返回。2. 如果构造函数的实例没有,就去它的原型对象找,如果有,就即返回3. 两个都输出tom。先你要知道原型模式的执流程:4 .a.info.name 为jack,b.info.name为tom。原因我想你从第三题已经得出来了。5.a.name输出jack,b.name输出tom。原因我想你从第三题已经得出来了。6.a.info.name 为jack,b.info.name为tom。原因我想你从第三题已经得出来了。注意:第三题 a.info.name这段代码,先去访问了实例对象本是否有info这个对象,发现没有就去原型上查找了,发现原型上有,所以地址共享了得到的值都是Tom;第五题是有区别的,a.name实例本没有,给当前a这个实例对象执赋值操作,没有去访问原型上的name。就相当于第 三题先访问了原型上的info对象,第五题没有访问过程,只是在实例上添加了name属性值。4. 通过例搞懂JS闭包例1function sayHello(name)var text = 'Hello ' + name;var sayAlert = function() console.log(text); sayAlert();sayHello("Bob") / 输出"Hello Bob"在sayHello()函数中定义并调了sayAlert()函数;sayAlert()作为内层函数,可以访问外层函数sayHello()中的text变量。例2function sayHello2(name)var text = 'Hello ' + name; / 局部变量var sayAlert = function() console.log(text); return sayAlert;var say2 = sayHello2("Jane"); say2(); / 输出"Hello Jane"例3function buildList(list) var result = ;for(var i = 0; i < list.length; i+) var item = 'item' + listi; result.push(function() console.log(item + ' ' + listi););return result;var fnlist = buildList(1,2,3);for (var j = 0; j < fnlist.length; j+) fnlistj();得到的结果:连续输出3个"item3 undefined"解析:通过执buildList函数,返回了个result,那么这个result存放的是3个匿名函数。然这三个匿名函数其实就是三个闭包,因为它可以访问到函数 的局部变量。所以闭包内的保留的i是最终的值为3.所以list3肯定是undefined. item变量值为item3.function buildList(list) var result = ;for(var i = 0; i < list.length; i+) var item = 'item' + listi; result.push(function(i) console.log(item + ' ' + listi);)(i);return result;var fnlist = buildList(1,2,3);改成如下代码:得到的结果:item1 1item2 2item3 3解释:这虽然传递了个数组进去,但是返回的是三个执的函数。例4function newClosure(someNum, someRef)var anArray = 1,2,3; var num = someNum; var ref = someRef; return function(x)num += x; anArray.push(num);console.log('num: ' + num + " " + 'anArray ' + anArray.toString() + " " + 'ref.someVar ' + ref.someVar);closure1 = newClosure(40, someVar: "closure 1"); closure2 = newClosure(1000, someVar: "closure 2");closure1(5); / 打印"num: 45; anArray 1,2,3,45; ref.someVar closure 1"closure2(-10); / 打印"num: 990; anArray 1,2,3,990; ref.someVar closure 2"每次调newClosure()都会创建独的闭包,它们的局部变量num与ref的值并不相同。例5function sayAlice()var sayAlert = function() console.log(alice); var alice = 'Hello Alice'return sayAlert;var sayAlice2 = sayAlice(); sayAlice2(); / 输出"Hello Alice"alice变量在sayAlert函数之后定义,这并未影响代码执。因为返回函数sayAlice2所指向的闭包会包含sayAlice()函数中的所有局部变量,这然包括了alice 变量,因此可以正常打印”Hello Alice”。例6function setupSomeGlobals() var num = 666;gAlertNumber = function() console.log(num); gIncreaseNumber = function() num+; gSetNumber = function(x) num = x; setupSomeGlobals(); gAlertNumber(); / 输出666 gIncreaseNumber(); gAlertNumber(); / 输出667 gSetNumber(5); gAlertNumber(); / 输出5解释:先gAlertNumber,gIncreaseNumber,gSetNumber是三个全局变量,并且其三个值都是匿名函数,然这三个匿名函数本都是闭包。他们操 作的num都是保存在内存中的同个num,所有会得出上的结果。/ 这个代码是错误的,因为变量i从来就没背locked住/ 相反,当循环执以后,我们在点击的时候i才获得数值/ 因为这个时候i操真正获得值/ 所以说论点击那个连接,最终显的都是I am link #10(如果有10个a元素的话)var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i+) elemsi.addEventListener('click', function (e) e.preventDefault();alert('I am link #' + i);, 'false');/ 这个是可以的,因为他在执函数表达式闭包内部/ i的值作为locked的索引存在,在循环执结束以后,尽管最后i的值变成了a元素总数(例如10)/ 但闭包内部的lockedInIndex值是没有改变,因为他已经执完毕了/ 所以当点击连接的时候,结果是正确的var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i+) (function (lockedInIndex) elemsi.addEventListener('click', function (e) e.preventDefault();alert('I am link #' + lockedInIndex);, 'false');)(i);/ 你也可以像下这样应,在处理函数那使执函数表达式/ 不是在addEventListener外部下看个dom操作,使闭包的例:/ 但是相对来说,上的代码更具可读性var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i+) elemsi.addEventListener('click', (function (lockedInIndex) return function (e) e.preventDefault();alert('I am link #' + lockedInIndex);)(i), 'false');5. JS重复输出个给定的字符串如下:function repeatStringNumTimes(str, num) return str;repeatStringNumTimes("abc", 3);重复输出个给定的字符串(str第个参数)n 次 (num第个参数),如果第个参数num不是正数的时候,返回空字符串。提供测试情况:repeatStringNumTimes("*", 3) / 应 该 返 回 "*". repeatStringNumTimes("abc", 3) /应该返回 "abcabcabc". repeatStringNumTimes("abc", 4) /应该返回 "abcabcabcabc". repeatStringNumTimes("abc", 1) / 应 该 返 回 "abc". repeatStringNumTimes("*", 8) / 应 该 返 回 "*". repeatStringNumTimes("abc", -2) /应该返回 "".解题思路我将介绍三种法:1. 使 while 循环2. 使递归3. 使ES6 repeat()法1 : 通过 while 循环重复输出个字符串function repeatStringNumTimes(string, times) var repeatedString = ""while (times > 0) repeatedString += string; times-;return repeatedString;repeatStringNumTimes("abc", 3);不过这还可以有个变种:function repeatStringNumTimes(string, times) var repeatedArr = ; /while (times > 0) repeatedArr.push(string); times-;return repeatedArr.join("");repeatStringNumTimes("abc", 3)对于前端来说,先个可能会将字符串拼接,修改为 数组join()拼接字符串,例如:很多前端都有数组join()拼接字符串的“情怀”,因为很早以前普遍认为数组join()拼接字符串字符串+拼接速度要快得多。不过现在未必,例如,V8 下+拼接字符串,要数组join()拼接字符串快。我这两个法测试了3万次重复输出,只相差了毫秒。另个变种可以 for 循环:function repeatStringNumTimes(string, times) var repeatedString = ""for(var i = 0; i < times ;i+) repeatedString += string;return repeatedString;repeatStringNumTimes("abc", 3)法2 : 通过条件判断和递归重复输出个字符串function repeatStringNumTimes(string, times) if(times < 0)return "" if(times = 1) return string; elsereturn string + repeatStringNumTimes(string, times - 1);repeatStringNumTimes("abc", 3);递归是种通过重复地调函数本,直到它达到达结果为的迭代操作的技术。为了使其正常作,必须包括递归的些关键特征。法3 : 使ES 6 re p e at() 法重复输出个字符串这个解决案较新潮,您将使 String.prototype.repeat() 法:repeat() 法构造并返回个新字符串,该字符串包含被连接在起的指定数量的字符串的副本。 这个法有个参数 count 表重复次数,介于0和正穷之间的整数 : 0, +) 。表在新构造的字符串中重复了多少遍原字符串。重复次数不能为负数。重复次数必须于 infinity,且长度不会于最长的字符串。function repeatStringNumTimes(string, times) if (times > 0)return string.repeat(times); elsereturn ""repeatStringNumTimes("abc", 3);您可以使三元表达式作为 if/else 语句的快捷式,如下所:function repeatStringNumTimes(string, times) return times > 0 ? string.repeat(times) : ""repeatStringNumTimes("abc", 3);6. 函数声明相关var x=1, y=0, z=0;function add(n) n=n+1;y=add(x); z=x+y;console.log("y1:"+y);console.log("z1:"+z);function add(n) n=n+3;y=add(x); z=x+y;console.log("y2:"+y);console.log("z2:"+z);求y,z的值。结果为:y1:undefined z1:NaN y2:undefined z2:NaNvar x=1, y=0, z=0;function add(n) return n=n+1;y=add(x); z=x+y;console.log("y1:"+y);console.log("z1:"+z);function add(n) return n=n+3;y=add(x); z=x+y;console.log("y2:"+y);console.log("z2:"+z);变化下:求y,z的值答案:y1:4 z1:5 y2:4 z2:57. 作域范围(Scope)(function()var a = b = 5;)();console.log(b);思考以下代码:控制台(console)会打印出什么?答案上述代码会打印出5。这个问题的陷阱就是,在即执函数表达式(IIFE)中,有两个命名,但是其中变量是通过关键词var来声明的。这就意味着a是这个函数的局部变量。与此相 反,b是在全局作域下的。这个问题另个陷阱就是,在函数中他没有使"严格模式"('usestrict')。如果严格模式开启,那么代码就会报出未捕获引错误(Uncaught ReferenceError):b没有定义。记住,严格模式要求你在需要使全局变量时,明确地引该变量。因此,你需要像下这么写:(function() 'use strict'var a = window.b = 5;)();console.log(b);再看如下个例:var a = 6; setTimeout(function () alert(a); a = 666;, 1000);a = 66;结果:668. 创建 “原(native)” 法console.log('hello'.repeatify(3);在 String 对象上定义个 repeatify 函数。这个函数接受个整数参数,来明确字符串需要重复次。这个函数要求字符串重复指定的次数。举个例:应该打印出hellohellohello. 答案:String.prototype.repeatify = String.prototype.repeatify | function(times) var str = ''for (var i = 0; i < times; i+) str += this;return str;String.prototype.repeatify = String.prototype.repeatify | function(times)/*code here*/;在这,另个关键点是,看你怎样避免重写可能已经定义了的法。这可以通过在定义的法之前,检测法是否已经存在。当你需要为旧浏览器实现向后兼容的函数时,这技巧分有。9. 变量提升(Hoisting)function test() console.log(a); console.log(foo();var a = 1; function foo() return 2;test();执以下代码的结果是什么?为什么?答案:这段代码的执结果是undefined 和 2。这个结果的原因是,变量和函数都被提升(hoisted)到了函数体的顶部。因此,当打印变量a时,它虽存在于函数体(因为a已经被声明),但仍然 是undefined。换之,上的代码等同于下的代码:function test() var a;function foo() return 2;console.log(a); console.log(foo();a = 1;test();再看如下代码:(function() console.log(typeof foo); console.log(typeof bar);var foo = 'hello', bar = function() return 'world'function foo() return 'hello'();function undefined结果:10. 在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,在本例中即为第代码设置的。11. call() 和 apply()修复前个问题,让最后个console.log() 打印输出Aurelio De Rosa. 答案:console.log(test.call(obj.prop);这个问题可以通过运call()或者apply()法强制转换上下环境。12. 闭包(Closures)var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i+) nodesi.addEventListener('click', function() console.log('You clicked element #' + i););考虑下的代码:请问,如果户点击第个和第四个按钮的时候,控制台分别打印的结果是什么?为什么? 答案:两次打印都是nodes.length的值。那么修复上题的问题,使得点击第个按钮时输出0,点击第个按钮时输出1,依此类推。 有多种办法可以解决这个问题,下主要使两种法解决这个问题。第个解决案使即执函数表达式(IIFE)再创建个闭包,从得到所期望的i的值。实现此法的代码如下:var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i+) nodesi.addEventListener('click', (function(i) return function() console.log('You clicked element #' + i);)(i);function handlerWrapper(i) return function() console.log('You clicked element #' + i);var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i+) nodesi.addEventListener('click', handlerWrapper(i);另个解决案不使IIFE,是将函数移到循环的外。这种法由下的代码实现:代码段:var name = "The Window" var object = name : "My Object", getNameFunc : function()return function()return this.name;alert(object.getNameFunc()();结果:The Windowvar name = "The Window" var object = name : "My Object", getNameFunc : function()var that = this; return function()return that.name;alert(object.getNameFunc()();代码段:结果:My Object章地址:13. 数据类型问题console.log(typeof null); console.log(typeof ); console.log(typeof ); console.log(typeof undefined);考虑如下代码:答案:object object object undefined14. 事件循环function printing() console.log(1);setTimeout(function() console.log(2); , 1000); setTimeout(function() console.log(3); , 0); console.log(4);printing();下代码运结果是什么?请解释。答案:1432想知道为什么输出顺序是这样的,你需要弄了解setTimeout()做了什么,以及浏览器的事件循环原理。浏览器有个事件循环于检查事件队列,处理延迟的事 件。UI事件(例如,点击,滚动等),Ajax回调,以及提供给setTimeout()和setInterval()的回调都会依次被事件循环处理。因此,当调setTimeout()函数时,即使延迟的时间被设置为0,提供的回调也会被排队。回调会呆在队列中,直到指定的时间完后,引擎开始执动作(如果它在当前不执其他的动 作)。因此,即使setTimeout()回调被延迟0毫秒,它仍然会被排队,并且直到函数中其他延迟的语句被执完了之后,才会执。15. 算法问题写个isPrime()函数,当其为质数时返回true,否则返回false。答案:我认为这是试中最常见的问题之。然,尽管这个问题经常出现并且也很简单,但是从被试提供的答案中能很好地看出被试的数学和算法平。先, 因为JavaScript不同于C或者Java,因此你不能信任传递来的数据类型。如果试官没有明确地告诉你,你应该