web前端面试题

目录

  1. css
  2. js基础
  3. 网络&存储
  4. es6
  5. js算法

一、css

1.用纯CSS创建一个三角形的原理是什么?(▲)

上、左、右三条边隐藏掉(颜色设为 transparent)

#demo {
  width: 0;
  height: 0;
  border-width: 20px;
  border-style: solid;
  border-color: transparent transparent red transparent;
}
  • flex布局
    display: flex;
    justify-content: center;
    aligin-items: center; 

二、js基础

1.判断一个对象是否为jquery对象可以用 obj instanceof jQuery

  • 确定一个值是哪种基本类型可以用typeof操作符,
  • 确定一个值是哪种引用类型可以使用instanceof操作符

2.js原生方法操作节点

var box=document.getElementById("box");
var tags=document.getElementsByTagName("*");//获取HTML的所有标签
var box2=document.getElementsByClassName("box");//获取class名为box的所有元素
var formName=document.getElementsByName("user");//含有name属性的元素
var p2=document.createElement("p");  //创建元素节点
p2.className = "info-top";//给元素设置className
var txt=document.createTextNode("这是另一个段落"); //创建文本节点
p2.appendChild(txt); //把创建的文本节点追加到元素节点中
var attr=document.createAttribute("id"); //创建属性节点
attr.value="p2"; //给属性节点设置值
p2.setAttributeNode(attr); //给元素设置属性节点
box.appendChild(p2);  //把创建的p元素追加到box最后
console.log(box);


let box1 = document.querySelector(".box");//仅返回匹配指定选择器的第一个元素
let boxes= document.querySelectorAll(".box");//返回匹配的所有的元素

总结:1.所有获取DOM对象的方法中,只有getElementById()和querySelector()这两个方法直接返回的DOM对象本身,可直接为其绑定事件。
2.getElementXXX类型的方法,除了通过Id获取元素,其他都返回一个集合,如果需要取到具体的DOM元素,需要加索引,如:document.getElementsByClassName(“box”)[0] =>获取class为box的所有元素中的第一个DOM元素。
3.querySelector()与querySelectorAll()两者的联系与区别: 
联系: 两者括号中的取值都是选择器 
区别: 当有多个class相同的元素时,使用querySelector()方法只能获取到第一个class为box的元素,而querySelectorAll()获取到了所有class为box的元素集合。

3.js的拷贝 (这题涉及到的就是你能不能清楚的分辨深拷贝和浅拷贝)

var a = {name:'Tom'};  var b = a;  b.name = 'Peter'; 
请问a.name = ?

正确答案是Peter,如果你的答案是Tom的话,那么你要好好去看看js的深拷贝。

如果要被拷贝的是数组:slice和concat都可以直接让数组进行深拷贝

arr.slice();
arr.concat();

4. javascript的同源策略,jsonp的原理

一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是域名、协议和端口号的组合

 同源策略带来的麻烦:ajax在不同域名下的请求无法实现,如果说想要请求其他来源的js文件,或者json数据,那么可以通过jsonp来解决

JSONP的实现原理:通过动态创建script标签,给请求的地址中添加一个get参数,这个参数代表回调函数,也就是希望服务器处理完我的请求之后,在前端执行这个回调函数

$.ajax({
 //url:"http://localhost:8081/rest/itemcat/list?callback=getMessage",
    url:"http://localhost:8081/rest/itemcat/message",	 
    type:"get",
    cache:false,
    dataType:"jsonp",
    jsonp:"callback", //这里定义了callback的参数名称,以便服务获取callback的函数名即getMessage
    jsonpCallback:"getMessage", //这里定义了jsonp的回调函数
    success:function(data){
        alert("success:"+data);
    },
    error:function(){
        alert("发生异常");
    }
});

jsonp:"callback", jsonpCallback:"getMessage",

这两个参数的值会自动拼接在url后面,所以用jquery的$.ajax方法发出的url可以不用在后面添加callback=getMessage 

5.Js获取当前日期时间

var myDate = new Date();
myDate.getYear();        //获取当前年份(2位)
myDate.getFullYear();    //获取完整的年份(4位,1970-????)
myDate.getMonth();       //获取当前月份(0-11,0代表1月)
myDate.getDate();        //获取当前日(1-31)
myDate.getDay();         //获取当前星期X(0-6,0代表星期天)
myDate.getTime();        //获取当前时间(从1970.1.1开始的毫秒数)
myDate.getHours();       //获取当前小时数(0-23)
myDate.getMinutes();     //获取当前分钟数(0-59)
myDate.getSeconds();     //获取当前秒数(0-59)
myDate.getMilliseconds();    //获取当前毫秒数(0-999)
myDate.toLocaleDateString();     //获取当前日期
var mytime=myDate.toLocaleTimeString();     //获取当前时间
myDate.toLocaleString( );        //获取日期与时间

6.js数据类型

基础数据类型: number,string,null,undefined,boolean,存放在栈内存

引用数据类型:Object ,Array,Function(Date,RegExp),存放在堆内存

7.数组的操作方法

  • slice(start,end) :可提取字符串的某个部分,并以新的字符串返回被提取的部分。slice(开始截取位置,结束截取位置)。start:要抽取的片断的起始下标。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象,且原数组不会被修改。。
  • splice(index,howmany,item)):向/从数组中添加/删除项目,然后返回被删除的项目。会改变原始数组。
  • pop() :用于删除并返回数组的最后一个元素。会改变数组的长度。
  • shift() :用于把数组的第一个元素从其中删除,并返回第一个元素的值。会改变数组的长度。
  • push() :向数组的末尾添加一个或多个元素,并返回新的长度。会改变数组的长度。
  • unshift() :方法可向数组的开头添加一个或更多元素,并返回新的长度。会改变数组的长度。
  • sort() :用于对数组的元素进行排序。
  • reverse() :用于颠倒数组中元素的顺序。
  • concat(array1,array2,arrayX) :用于连接两个或多个数组。
  • join(str) :用于把数组中的所有元素通过指定的分隔符进行分隔放入一个字符串,返回生成的字符串。str(可选): 指定要使用的分隔符,默认使用逗号作为分隔符。
  • indexOf() :查找数组是否存在某个元素,返回下标

8. 字符串的操作

  • charAt():返回返回指定位置的字符串。如果charAt中的参数为负数,或者大于字符串的最大索引,将会返回一个空字符串。
  • split(separator,howmany): 把一个字符串分割成字符串数组,可以指定分隔符。如果把空字符串 ("") 用作分隔符,那么 stringObject 中的每个字符之间都会被分割。String.split() 执行的操作与 Array.join 执行的操作是相反的。
  • indexOf() :返回字符串中特定字符串第一次出现的位置
  • indexOf() :返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
  • toUpperCase():用于把字符串转换为大写
  • toLowerCase():用于把字符串转换为小写。
  • search():用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,它接受一个参数,该参数是你需要查找的字符,如果被查找的字符串中这个字符,则返回它在该字符串中的下标,如果没有则返回-1
  • replace():用于查找并替换字符,该方法不会影响原字符串,可以填入两个参数,第一个参数为需要被替换的字符,第二个是用来替换的字符,返回替换字符后的新字符串
  • match():搭配正则表达式使用,支持全局匹配,参数是匹配的字符或正则,返回一个数组
  • substring(start,stop) :方法用于提取字符串中介于两个指定下标之间的字符。返回一个新的字符串,内容是从 start 处到 stop-1 处的所有字符,其长度为 stop 减 start。不包含stop
  • slice(start,end) :返回字符串中的某个子串,支持负数参数(字符串中倒数第一个字符定为-1)
  • substr(start,length):子串的开始位置和长度,start为要抽取的子串的起始下标。必须是数值。如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推。length可选。子串中的字符数。必须是数值。如果省略了该参数,那么返回从 stringObject 的开始位置到结尾的字串。

总结:

截取字符串:substr、substring、slice这三个方法,它们接收的第一个参数都为开始的位置,而substr(),第二个参数表示截取的长度,slice()和substring(),表示结束的位置,而不包括它。

查找字符:
1.search()、indexOf() / lastIndexOf():查找字符并返回该字符在字符串中的索引,没有则返回-1;
2.match():匹配字符,并返回匹配到的字符组成的数组,没有则返回null,可填入正则;
3.replace():用来查找并替代字符,两个参数,第一个是需要被替代的字符,第二个是用来替代的字符;

str.search(/w3school/i)//忽略大小写的检索

9. 什么叫优雅降级和渐进增强?

渐进增强 :针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

区别:

a. 优雅降级是从复杂的现状开始,并试图减少用户体验的供给

b. 渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要

c. 降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带

10.浏览器的内核分别是什么?

IE: trident内核

Firefox:gecko内核

Safari:webkit内核

Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核

Chrome:Blink(基于webkit,Google与Opera Software共同开发)

11.谈谈垃圾回收机制方式,内存管理,和内存泄漏

垃圾回收机制方式

1、定义和用法:Javascript具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境负责管理代码执行过程中使用的内存。

2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后在函数中使用这些变量,直至函数结束,而闭包中由于内部函数的原因,外部函数并不能算是结束。
3.  垃圾回收策略:标记清除(较为常用)和引用计数。

标记清除:

  定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。

  到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。
内存管理

1.什么时候触发垃圾回收?

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。

2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。

3、GC缺陷:(1)、停止响应其他操作;

4、GC优化策略:

(1)、分代回收(Generation GC):这个和Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。

(2)、增量GC:这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推”。

开发过程中遇到的内存泄露情况,如何解决的?

1、定义和用法:内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。C#和Java等语言采用了自动垃圾回收方法管理内存,几乎不会发生内存泄露。我们知道,浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。

2、内存泄露的几种情况:

(1)、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。

解决方法如下:
    

(2)、由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包。闭包可以维持函数内局部变量,使其得不到释放。

解决方法如下:
function bindEvent(){
    var obj=document.createElement("XXX");
    obj.onclick=function(){
         //Even if it's a empty function
    }
    obj=null;
}

12.display:none和visibility:hidden区别

1.display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;

2.使用visibility:hidden比display:none性能上要好,display:none切换显示时visibility,页面产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流),而visibility切换是否显示时则不会引起回流。

13.JS有哪些手段可以实现继承?

1.原型链继承:将父类的为父类实例添加新特性,作为子类实例返回实例作为子类的原型

2.构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

3.实例继承:为父类实例添加新特性,作为子类实例返回

4.拷贝继承:

5.组合继承:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

6.寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

14.undefined和null的区别, 还有undeclared

  • null表示没有对象, 即此处不该有此值. 典型用法:
    • (1) 作为函数的参数,表示该函数的参数不是对象。

    • (2) 作为对象原型链的终点。

    •  ( 3 )   null可以作为空指针. 只要意在保存对象的值还没有真正保存对象,就应该明确地让该对象保存null值.
  • undefined表示缺少值, 即此处应该有值, 但还未定义.
    • (1)变量被声明了,但没有赋值时,就等于undefined。

      (2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

      (3)对象没有赋值的属性,该属性的值为undefined。

      (4)函数没有返回值时,默认返回undefined。

  • undeclared即为被污染的命名, 访问没有被声明的变量, 则会抛出异常, 终止执行. 即undeclared是一种语法错误

15.什么是闭包? 闭包有什么作用?

  • 闭包是指有权访问另一个函数作用域中的变量的函数. 创建闭包常见方式,就是在一个函数内部创建另一个函数.
  • 作用: 
    • 匿名自执行函数  (function (){ ... })();   创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,关键是这种机制不会污染全局对象。
    • 缓存, 可保留函数内部的值
    • 实现封装
    • 实现模板

16.apply和call的用法和区别?

  • 用法: 都是为了改变函数体内部 this 的指向,都能继承另一个对象的方法和属性,区别在于参数列表不一样
  • 区别:
    • Function.apply(obj, args) args是一个数组,作为参数传给Function
    • Function.call(obj, arg1, arg2,...)  arg*是参数列表
    • apply一个妙用: 可以将一个数组默认的转化为一个参数列表
      • 举个例子: 有一个数组arr要push进一个新的数组中去, 如果用call的话需要把数组中的元素一个个取出来再push, 而用apply只有Array.prototype.push.apply(this, arr)

17.前端开发的优化问题?

       (1) 减少http请求次数:css spirit,data uri

       (2) JS,CSS源码压缩

       (3) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存AJAX请求结果,每次操作本地变量,不用请求,减少请求次数

       (4) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能

       (5) 用setTimeout来避免页面失去响应

       (6) 用hash-table来优化查找

       (7) 当需要设置的样式很多时设置className而不是直接操作style 

       (8) 少用全局变量

       (9) 缓存DOM节点查找的结果

       (10) 避免使用CSS Expression

       (11) 图片预载

       (12) 避免在页面的主体布局中使用table,table要等其中的内容完全下载之后才会显示出来,显示比div+css布局慢

18.javascript中的this是什么,有什么用,指向上面?

  • 全局代码中的this是指向全局对象
  • 作为对象的方法调用时指向调用这个函数的对象
  • 作为构造函数指向创建的对象
  • 使用apply和call设置this

19.使用模块化加载时,模块记载的顺序是怎么样的,如果不知道,根据已有的知识,加载顺序是怎么样的

  • commonjs 同步 循序执行
  • AMD 提前加载,不管是否调用模块,先解析所有模块require速度快 有可能浪费资源(requirejs)
  • CMD提前加载,在真正需要使用(依赖)模块时才解析该模块,(seajs)
  • CMD按需解析,性能比AMD差

20.请用js去除字符串空格?

方法一:使用replace正则匹配的方法

去除所有空格: str = str.replace(/\s*/g,"");      

去除两头空格: str = str.replace(/^\s*|\s*$/g,"");

去除左空格: str = str.replace( /^\s*/, “”);

去除右空格: str = str.replace(/(\s*$)/g, "");

str为要去除空格的字符串,实例如下:

var str = " 23 23 ";
var str2 = str.replace(/\s*/g,"");
console.log(str2); // 2323

方法二:使用str.trim()方法

str.trim()局限性:无法去除中间的空格,实例如下:

var str = "   xiao  ming   ";
var str2 = str.trim();
console.log(str2);   //xiao  ming 

同理,str.trimLeft(),str.trimRight()分别用于去除字符串左右空格。

方法三:使用jquery,$.trim(str)方法

$.trim(str)局限性:无法去除中间的空格,实例如下:

var str = "   xiao  ming   ";
var str2 = $.trim(str)
console.log(str2);   //  xiao  ming

使用正则表达式验证邮箱格式:

var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/;
var email = "[email protected]";
console.log(reg.test(email));  // true  

21.jquery中$.get()提交和$.post()提交有区别吗?

相同点:都是异步请求的方式来获取服务端的数据;

异同点:

1、请求方式不同:$.get() 方法使用GET方法来进行异步请求的。$.post() 方法使用POST方法来进行异步请求的。

2、参数传递方式不同:get请求会将参数跟在URL后进行传递,而POST请求则是作为HTTP消息的实体内容发送给Web服务器的,这种传递是对用户不可见的。

3、数据传输大小不同:get方式传输的数据大小不能超过2KB 而POST要大的多

4、安全问题: GET 方式请求的数据会被浏览器缓存起来,因此有安全问题。

三、网络&存储&优化性能

1.http请求?

一次完整的HTTP请求所经历的7个步骤:

建立TCP连接->发送请求行->发送请求头->(到达服务器)发送状态行->发送响应头->发送响应数据->断TCP连接

2.websocket和ajax轮询

  • websocket:是web应用程序的传输协议,它提供了双向的,按序到达的数据流。他是一个HTML5协议,websocket连接是持久的,通过在客户端和服务器之间保持双向连接,服务器的更新可以被及时推送给客户端,而不需要客户端以一定的时间去轮询。

       优点:只要建立一次连接,就可以连续不断的得到服务器推送消息,节省带宽和服务器端的压力。

  • ajax轮询:模拟常连接就是每隔一段时间(0.5s)就向服务器发起ajax请求,查询服务器是否有数据更新。

       缺点:每次都要建立HTTP连接,即使需要传输的数据非常少,浪费带宽

3.请描述一下 cookies sessionStorage和localstorage区别

   相同点:都存储在客户端
   不同点:1)存储大小

· cookie数据大小不能超过4k。

· sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。

2)有效时间

· localStorage    存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;

· sessionStorage  数据在当前浏览器窗口关闭后自动删除。

· cookie          设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

3)数据与服务器之间的交互方式

· cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端

· sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。

4.计算机网络的分层概述

  • tcp/ip模型:从下往上分别是链路层,网络层,传输层,应用层
  • osi模型:从下往上分别是物理层,链路层,网络层,传输层,会话层,表示层,应用层

5.HTTP和HTTPS

  • HTTP协议通常承载与 TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS
  • 默认HTTP的端口号为80,HTTPS的端口号为443

6.浏览器是如何渲染页面的?

1.解析HTML文件,创建DOM树。

   自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞后续外部脚本的加载)。

2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式

3.将CSS与DOM合并,构建渲染树(Render Tree)

4.布局和绘制,重绘(repaint)和重排(reflow)

四、es6 

1.ES6新特性

      1) 箭头操作符 inputs=>outputs: 操作符左边是输入的参数,而右边则是进行的操作以及返回的值

  2) 支持类, 引入了class关键字. ES6提供的类实际上就是JS原型模式的包装

  3) 增强的对象字面量

    1. 可以在对象字面量中定义原型  __proto__: xxx  //设置其原型为xxx,相当于继承xxx

    2. 定义方法可以不用function关键字

    3. 直接调用父类方法

  4) 字符串模板: ES6中允许使用反引号 ` 来创建字符串,此种方法创建的字符串里面可以包含由美元符号加花括号包裹的变量${vraible}。

  5) 自动解析数组或对象中的值。比如若一个函数要返回多个值,常规的做法是返回一个对象,将每个值做为这个对象的属性返回。但在ES6中,利用解构这一特性,可以直接返回一个数组,然后数组中的值会自动被解析到对应接收该值的变量中。

  6) 默认参数值: 现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了。

  7) 不定参数是在函数中使用命名参数同时接收不定数量的未命名参数。在以前的JavaScript代码中我们可以通过arguments变量来达到这一目的。不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如下面这个例子中,…x代表了所有传入add函数的参数。

  8) 拓展参数则是另一种形式的语法糖,它允许传递数组或者类数组直接做为函数的参数而不用通过apply。

  9) let和const关键字: 可以把let看成var,只是它定义的变量被限定在了特定范围内才能使用,而离开这个范围则无效。const则很直观,用来定义常量,即无法被更改值的变量。

  10) for of值遍历 每次循环它提供的不是序号而是值。

  11) iterator, generator

  12) 模块

  13) Map, Set, WeakMap, WeakSet

  14) Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。一下子让我们对一个对象有了很强的追踪能力,同时在数据绑定方面也很有用处。

  15) Symbols Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。之后就可以用这个返回值做为对象的键了。Symbol还可以用来创建私有属性,外部无法直接访问由symbol做为键的属性值。

  16) Math, Number, String, Object的新API

  17) Promises是处理异步操作的一种模式

五、js算法 

1.js随机生成10000个,长度为8 位的数字号码,找出所有靓号(AAAA,AABB,ABAB,并且后四位不含4 )


2. 写一个原型链继承的例子

//DOM封装查询
function Elem(id){
	this.elem = document.getElementById(id); 
}
Elem.prototype.html = function(val){
	var elem = this.elem;
	if(val){
		elem.innerHTML = val;
		return this;
	}else{
		return elem.innerHTML;
	}
}
Elem.prototype.on = function (type,fn){
	var elem = this.elem;
	elem.addEventListener(type,fn);
	return this;
}
var div1 = new Elem('div1');
div1.html('

hello world

').on('click',function(){ alert('clicked'); }).html('

hello javascript

');

3.用js创建10个标签,点击的时候弹出来对应的序号

var i;
for(i=0;i<10;i++){
	(function(i){
		var a = document.createElement('a');
		a.innerHTML = i + '
'; a.addEventListener('click',function(e){ e.preventDefault(); alert(i); }); document.body.appendChild(a); })(i); }

4.获取2018-4-26格式的日期

function formatDate(dt){
    if(!dt){
        dt = new Date();
    }
    var year = dt.getFullYear();
    var month = dt.getMonth() + 1;
    var date = dt.getDate();
    if(month<10){
        month = '0' + month;    
    }
    if(date<10){
        date = '0' +date;
    }
    return year + '-' + month + '-' + date;
}
var dt = new Date();
var formatDate  = formatDate(dt);
console.log(formatDate);

5.写一个能遍历对象和数组的通用的forEach函数

function forEach(obj,fn){
    var key;
    if(obj instanceof Array){
        obj.forEach(function(item,index){
            fn(index,item);
        });
    }else{
        for(key in obj){
            fn(key,obj[key]);
        }
    }
}
var arr = [1,2,3];//数组
forEach(arr,function(index,item){
    console.log(index,item);
})
var obj = {x:1,y:2};//对象
forEach(obj,function(key,val){
    console.log(key,val);
})

6.冒泡排序

function bubbleSort(arr) {  
    for(let i = 0,l=arr.length;iarr[j]) {
                let tem = arr[i];
                arr[i] = arr[j];
                arr[j] = tem;
            }
        }
    }
    return arr;
}

module.exports = bubbleSort;

//es6写法
let arr = [43, 32, 1, 5, 9, 22];
const sort = arr => {
    let res = []
    arr.forEach((v, i) => {
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                [arr[i],arr[j]] = [arr[j],arr[i]]
            }
        }
    })
    return arr
}
console.log(sort(arr))  // [1, 5, 9, 22, 32, 43]

7.字符串转驼峰 

var str="border-bottom-color";
function Change(str){
   var arr=str.split("-");
   for(var i=1;i

8.查找字符串中出现次数最多的字符和次数

解决方法一:
var str = "sdddrtkjsfkkkasjdddj";
var max = 0;
var char;
function Search(str) {
    var obj = {};
    for (var i = 0; i < str.length; i++) {
        if (!obj[str[i]]) {
            obj[str[i]] = str[i];
        } else {
            obj[str[i]] += str[i];
        }
    }

    for (var i = 0; i < str.length; i++) {
        if (obj[str[i]].length > max) {
            max = obj[str[i]].length;
            char = str[i];
        }
    }
    console.log("出现次数最多的字符是" + char + ",出现了" + max + "次")
}
Search(str);

解决方法二:
function repeatCharNum(str){
    var arr = str.split('');
    str = arr.sort().join('');
    var re = /(\w)\1+/g;
    var index = 0;
    var value = '';
    str.replace(re,function($0,$1){
        if(index < $0.length){
            index = $0.length;
            value = $1 ;
        }
    });
    alert ('最多字符'+value+'出现的次数'+index);
}

9.编写一个函数,将输入的参数中的数字字符追加为一个数字字符串,参数输入不确定

function getStrChange(){
  var len = arguments.length;//参数不确定时使用arguments关键字
  var re = /^\d+$/;
  var str = '';debugger;
  for(var i =0; i< len; i++){
    if(!(re.test(arguments[i]))){ 
      continue;
    }
    if(i == len-1){
      str = str+arguments[i];
    }else{
      str = str+arguments[i]+',';
    }  
  }
  return str;
}
alert(getStrChange('1','a','45','b','3',1));//('1,45,3,1')

10.JS 把url的参数解析成对象

function parseUrl(str) {
    // 判断是否传入参数
    if (str) {
        var obj = {};
        var queryArr = [];
        // 正则表达式规则
        var re = /^(http\w?):\/\/([0-9a-zA-Z\.]+)([a-zA-Z0-9\/]+)\?([a-zA-Z0-9\=\&]+)#([0-9a-zA-Z\.]+)/;
        // 利用正则表达式将字符串分组
        var reArr = re.exec(str);
        if (reArr) {
            obj.peotocol = reArr[1];
            obj.host = reArr[2];
            obj.path = reArr[3];
            queryArr = reArr[4].split(/[\&\=]+/);
            obj.query = {};
            for (var i = 0; i < queryArr.length; i += 2) {
                obj.query[queryArr[i]] = queryArr[i + 1];
            }
            obj.hash = reArr[5]
            return obj;
        } else {
            return null;
        }
    } else {
        return null;
    }
}

方法二:

// url参数解析
function getUrlkey(url) {
  var params = {};
  var urls = url.split("?");                  console.log('1_分割url:', urls)
  var arr = urls[1].split("&");               console.log('2_分割urls[1]:', arr)
  for (var i = 0, l = arr.length; i < l; i++) {
    var a = arr[i].split("=");                console.log('3_遍历 arr 并分割后赋值给a:', a[0], a[1])
    params[a[0]] = a[1];                      console.log('4_a给params对象赋值:', params)
  }                                           console.log('5_结果:', params)
  return params;
}

console.log(6,getUrlkey('http//aaa/txt.php?a=1&b=2&c=3'))

 

web前端面试题_第1张图片web前端面试题_第2张图片

11.JS实现add(1)(2)(3)(4)的调用方式

第一种:

var add = function (m) {
    var temp = function (n) {
        return add(m + n);
    }
    temp.toString = function () {
        return m;
    }
    return temp;
};
 
add(3)(4)(5); // 12
add(3)(6)(9)(25); // 43

这个add函数可以无限次调用循环调用,并且把所有传进去的值相加,最后返回相加总数。这道题咋一看有点特别,但代码量极其少而精,重点技术在于:作用域、交替、匿名函数、toString的巧妙。
让我们来解释这个过程:add(3)(4)(5)
1、先执行add(3),此时m=3,并且返回temp函数;
2、执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数
3、执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数
4、关键性一步来了,后面没有传入参数,等于返回的temp函数不被执行而是打印,了解JS的朋友都知道对象的toString是修改对象转换字符串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。
看到这其实就很明白了,代码中temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,所以这个地方是可以任意修改的,你让它返回什么它就返回什么,比如改写:

temp.toString = function () {
    return “total : ” + m;
}

 执行结果:add(3)(4)(5);  //total : 12

第二种:

function add(x) {
    var sum = x;
    var tmp = function (y) {
        sum = sum + y;
        return tmp;
    };
    tmp.toString = function () {
        return sum;
    };
    return tmp;
}
console.log(add(1)(2)(3)); //6
console.log(add(1)(2)(3)(4)); //10

首先要一个数记住每次的计算值,所以使用了闭包,在tmp中记住了x的值,第一次调用add(),初始化了tmp,并将x保存在tmp的作用链中,然后返回tmp保证了第二次调用的是tmp函数,后面的计算都是在调用tmp, 因为tmp也是返回的自己,保证了第二次之后的调用也是调用tmp,而在tmp中将传入的参数与保存在作用链中x相加并付给sum,这样就保证了计算;

但是在计算完成后还是返回了tmp这个函数,这样就获取不到计算的结果了,我们需要的结果是一个计算的数字那么怎么办呢,首先要知道JavaScript中,打印和相加计算,会分别调用toString或valueOf函数,所以我们重写tmp的toString和valueOf方法,返回sum的值。

你可能感兴趣的:(JavaScript,web前端面试题)