前端面试题整理
1、请将一个URL的search部分参数与值转换成一个json对象?
function getJson(url){
if(url === undefined || typeof url !== 'string') {
return null
}
var items = url.split('?')[1].split('&');
var json = {};
for(var i = 0; i<items.length; i++){
var item = items[i].split('=');
json[item[0]] = item[1];
}
return json;
}
console.log(getJson('http://item.taobao.com.htm?a=1&b=2&d=xxx&e'))
2、数组去重的方法
es6:
function clearRepeat(arr){
var at = new Set(arr);
return Array.from(at);
}
from()方法用于通过拥有 length 属性的对象或可迭代的对象来返回一个数组。如果对象是数组返回 true,否则返回 false。
es5数组去重的方法:
function unqiue(arr){
for(var i = 0; i<arr.length; i++){
for(var j= i+1; j<arr.length; j++){
if(arr[i] === arr[j]){
arr.splice(j,1)
j--;
}
}
}
return arr
}
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
注释:该方法会改变原始数组。
arrayObject.splice(index,howmany,item1,…,itemX)
参数 描述
index 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, …, itemX 可选。向数组添加的新项目。
3、连字符转驼峰形式
function toUpcase(str){
var arr = str.split('-');
var newArr = [];
for(var i= 1; i<arr.length; i++){
newArr[0] = arr[0];
newArr.push(arr[i].charAt(0).toUpperCase() + arr[i].slice(1));
var newArr1 = newArr.join('')
}
return newArr1;
}
slice() 方法可从已有的数组中返回选定的元素。
语法
arrayObject.slice(start,end)
参数 描述
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
返回值
返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。
说明
请注意,该方法并不会修改数组,而是返回一个子数组。如果想删除数组中的一段元素,应该使用方法 Array.splice()。
4、字符串翻转
function reverse(str){
var arr = str.split('');
arr.reverse();
var str1 = arr.join('')
return str1;
}
console.log(reverse('1234567'))
5、作用域考题:分别输出1、2、3
for (var i = 1; i<= 3; i++) {
(function (i){
setTimeout(function(){
console.log(i);
},1000)
})(i);
}
6、js实现随机取10-100之间的10个数字,存入一个数组,并排序
var arr = [];
function getRandom(num1,num2){
var transition = num2 - num1 + 1;
var res = Math.floor(Math.random() * transition + num1);
return res;
}
for(var i = 0; i<10; i++){
arr.push(getRandom(10,100))
}
arr.sort(function(a,b){
return b-a;
})
console.log(arr);
7、连接两个数组
var arr1 = [1,2,3];
var arr2 = [4,5,6];
arr1 = arr1.concat(arr2);
console.log(arr1)
8、继承的例子
原型链继承
function Father(name){
this.name = name;
this.say = function (){
console.log('我的名字是' + this.name)
}
}
function Son(name){
this.name = name;
}
var f= new Father('lisi');
Son.prototype = f;
var s = new Son('zhangsan');
console.log(s.name);
s.say1();
缺点:
引用类型的属性被所有实例共享
在创建Son 的实例时, 不能向Father传参
借用构造函数(经典继承)
function Parent(name,age){
this.name = name;
this.age = age;
this.list = [1,2,3]
}
Parent.prototype.say = function(){
console.log('hello')
}
function Child(sex,name){
this.sex = sex;
Parent.call(this,name);
}
var kid = new Child('man','lihong');
var kid2 = new Child('woman','wansi');
kid.list.push('2');
console.log(kid.sex);
console.log(kid.name);
console.log(kid.list);
console.log(kid2.sex);
console.log(kid2.name);
console.log(kid2.list);
console.log(kid instanceof Parent);
复制父类构造函数内的属性
优点:
1.避免了引用类型的属性被所有实例共享
2.可以在Child中向Parent传参
缺点:
1.只是子类的实例,不是父类的实例
2.方法都在构造函数中定义,每次创建实例都会创建一遍方法
组合继承
组合 原型链继承 和 借用构造函数继承
背后的思路是:使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。
function Parent(name){
this.name = name;
this.list = [1,2,3]
}
Parent.prototype.say = function(){
console.log(this.name);
}
function Child(age, name){
Parent.call(this,name)
this.age = age;
}
Child.prototype = new Parent();
var kid = new Child(12,'lisi');
var kid2 = new Child(13,'hhh');
kid.say();
kid2.say();
kid.list.push(5);
console.log(kid.list)
console.log(kid2.list)
优点:融合原型链继承和构造函数的优点,是JavaScript中最常用的继承模式
缺点:调用了两次父类构造函数
(组合继承最大的问题是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部)
寄生组合式继承
function Parent (name){
this.name = name;
this.list = [1,2,3]
}
Parent.prototype.say = function(){
console.log(this.name)
}
function Child(name,age){
Parent.call(this,name)
this.age = age;
}
function prototype(child,parent){
var prototype = Object.create(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
prototype(Child,Parent);
var child = new Child('xiaohua', 18);
child.say(); //xiaohua
es5写法
function Parent(name){
this.name = name;
this.colors = ['red', 'blue', 'green'];
}
Parent.prototype.sayName = function(){
console.log(this.name);
}
function Child(name,age){
Parent.call(this,name);
this.age = age;
}
function CreateObj(o){
function F(){};
F.prototype = o;
return new F();
}
// Child.prototype = new Parent(); // 这里换成下面
function prototype(child,parent){
var prototype = CreateObj(parent.prototype);
prototype.constructor = child;
child.prototype = prototype;
}
prototype(Child,Parent);
var child1 = new Child('xiaopao', 18);
console.log(child1);
优点: 这种方式的高效率体现它只调用了一次Parent构造函数,并且因此避免了再Parent.prototype上面创建不必要的,多余的属性。普遍认为寄生组合式继承是引用类型最理想的继承方式
9、http协议中get和post的区别
1.GET使用URL或Cookie传参。而POST将数据放在请求体中。
2.GET的URL会有长度上的限制,而POST的数据则可以非常大。
3.POST比GET安全,因为数据在地址栏上不可见。
实际上是没有区别的,都是http底层TCP/IP决定的。
对于GET和POST的理解,是纯粹地来源于HTTP协议。他们只有一点根本区别,简单点儿说,一个用于获取数据,一个用于修改数据。具体的请参考RFC文档。
如果一个人一开始就做Web开发,很可能把HTML对HTTP协议的使用方式,当成HTTP协议的唯一的合理使用方式。从而犯了以偏概全的错误。
10、WEB应用从服务器主动推送Data到客户端有那些方式?
- html5 websocket
(WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。) - WebSocket 通过 Flash
- XHR长时间连接
- XHR Multipart Streaming
- 不可见的Iframe
- <\script>标签的长时间连接(可跨域)
Javascript数据推送
Commet:基于HTTP长连接的服务器推送技术
基于WebSocket的推送方案
SSE(Server-Send Event):服务器推送数据新方式
11、浏览器本地存储数据有哪些方法,有什么区别?
cookie,localstorage,sessionstorage,而其实还有userData和IndexedDB这两种数据存储
点击查看
12、你怎么看待前端程序员
对前端界面工程师这个职位是怎么样理解的?它的前景会怎么样?
前端是最贴近用户的程序员,比后端、数据库、产品经理、运营、安全都近。
1、实现界面交互
2、提升用户体验
3、有了Node.js,前端可以实现服务端的一些事情
前端是最贴近用户的程序员,前端的能力就是能让产品从 90分进化到100 分,甚至更好,
参与项目,快速高质量完成实现效果图,精确到1px;
与团队成员,UI设计,产品经理的沟通;
做好的页面结构,页面重构和用户体验;
处理hack,兼容、写出优美的代码格式;
针对服务器的优化、拥抱最新前端技术。
你如何优化自己的代码?
前端的性能优化主要分为三部分:
HTML优化
避免 HTML 中书写 CSS 代码,因为这样难以维护。
使用Viewport加速页面的渲染。
使用语义化标签,减少 CSS 代码,增加可读性和 SEO。
减少标签的使用,DOM解析是一个大量遍历的过程,减少不必要的标签,能降低遍历的次数。
避免 src、href等的值为空,因为即时它们为空,浏览器也会发起 HTTP 请求。
减少 DNS 查询的次数。
CSS优化
优化选择器路径:使用 .c {} 而不是 .a .b .c {}。
选择器合并:共同的属性内容提起出来,压缩空间和资源开销。
精准样式:使用padding-left: 10px 而不是 padding: 0 0 0 10px。
雪碧图:将小的图标合并到一张图中,这样所有的图片只需要请求一次。
避免通配符:.a .b * {} 这样的选择器,根据从右到左的解析顺序在解析过程中遇到通配符 * {} 会遍历整个DOM,性能大大损耗。
少用 float:float 在渲染时计算量比较大,可以使用 flex布局。
为 0 值去单位:增加兼容性。
压缩文件大小,减少资源下载负担。
JavaScript优化
尽可能把 <\script> 标签放在 body 之后,避免JS 的执行卡住 DOM 的渲染,最大程度保证页面尽快地展示出来。
尽可能合并 JS代码:提取公共方法,进行面向对象设计等……
CSS 能做的事情,尽量不用JS 来做,毕竟 JS 的解析执行比较粗暴,而CSS 效率更高。
尽可能逐条操作 DOM,并预定好 CSS 样式,从而减少 reflow 或者 repaint的次数。
尽可能少地创建 DOM,而是在HTML 和 CSS中使用 display: none 来隐藏,按需显示。
压缩文件大小,减少资源下载负担。