前端面试总结——持续更新
前端面试题总结
写在前面的话:
- 写文目的:总结前端面试过程中没回答上来的点,深化印象,也方便日后温习。
- 写文方法:写之前先自己看相关知识,理解好后过段时间根据记忆来写,最后对比纠正。
准备面试流程:
1.更新简历,多参考其他的优秀简历
2.复习面试题
笔者就是因为只更新了简历没有复习导致基础不过关,错过两家心仪的公司。
顺便说下,平时工作中的确很多时候用不到也不会去背某些面试中的问题,不过面试题中基础部分很重要,理解好基础才更轻松掌握新框架新知识。时不时去看看面试题也不失为一种巩固基础的方法。一般一面面基础,二面面项目,项目经验再多,一面过不了,什么戏也不会有。
被面过的面试题:
css
css优先级,属性选择器的优先级在哪
0.类型选择器(如, h1)和伪元素(如, ::before)
1.类选择器,属性选择器,伪类(如,:hover)
3.ID选择器
通用选择器(universal selector)(*), 组合子(combinators) (+, >, ~, ' ') 和 否定伪类(negation pseudo-class)(:not()) 对特异性没有影响。(但是,在 :not() 内部声明的选择器是会影响优先级,在计算选择器数量时还是会把其中的选择器当做普通选择器进行计数)。
4.给元素添加的内联样式总会覆盖外部样式表的任何样式 ,因此可看作是具有最高的优先级。
权重记忆口诀。一个元素名,或者伪元素+1,一个属性选择器/class或者伪类+10,一个id+100,一个行内样式+1000。
**!important 规则例外
当在一个样式声明中使用一个!important 规则时,此声明将覆盖任何其他声明。**
直接定位的样式权重大于继承的样式,无论继承的规则的特异性(优先级)如何。
Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.
h1 {
color: purple;
}
#parent {
color: green;
}
当它应用在下面的HTML时:
<html>
<body id="parent">
<h1>Here is a title!</h1>
</body>
</html>
浏览器会将h1渲染成紫色。
因为h1选择器清晰地定位了元素。
~ 组合器
A + B 匹配任意元素,满足条件:B是A的下一个兄弟节点(AB有相同的父结点,并且B紧跟在A的后面)
A ~ B 满足条件:B是A之后的兄弟节点中的任意一个(AB有相同的父节点,B在A之后,但不一定是紧挨着A)(会尽可能多匹配)
js基础
什么是闭包
闭包是由函数与创建该函数的环境所组成的
优点:减少全局变量污染
缺点:影响脚本性能
3==true 打印出什么
会打印出false,这里会将true转变成1
Number 和 String 或者 Bool 类型比较,会对String 或者 Bool 类型进行ToNumber()转换
Number(true) // 1
Number(false) // 0
1==true //true
1===true //false
3==true //false
变量声明提升
变量声明无论出现在代码的任何位置,都会在代码执行前处理。所以在代码的任何位置声明变量就好像在代码开头声明一样。
var a = 100;
function fn() {
alert(a);
var a = 200;
alert(a);
}
fn();
alert(a);
var a;
alert(a); //这里alert出100
var a = 300;
alert(a);
not defined 与 undefined
console.log(a) //报错 Uncaught ReferenceError: a is not defined
var b;
console.log(b) //undefined
判断变量是不是数组的几个方法
var a=[];
a.constructor===Array //true
a instanceof Array === true //true
⚠️ 注意:以上方法在跨frame时会有问题,跨frame实例化的对象不共享原型
var iframe = document.createElement('iframe'); //创建iframe
document.body.appendChild(iframe); //添加到body中
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // 声明数组[1,2,3]
alert(arr instanceof Array); // false
alert(arr.constructor === Array); // false
解决:
Object.prototype.toString.call(a) // "[object Array]"
Array.isArray(a) //true
bind,call,apply用法与区别
用法:都是改变函数内this指向
bind:返回一个新的函数,调用新的函数才执行,新函数里this永久地被绑定到了bind的第一个参数上
而call与apply能直接执行
fuc.call(thisObj,a,b,c)
fuc.apply(thisObj,[a,b,c]) // apply 传数组
原型 与 prototype属性
- 原型:
JavaScript的对象中都包含了一个" [[Prototype]]"内部属性,这个属性所对应的就是该对象的原型。对象从原型继承方法与属性。原型可能也有原型,这种关系被称为原型链。
"[[Prototype]]"作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,大多数现代浏览器还是提供了一个名为"__proto__"这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问"Object.getPrototype(object)")。
原型是由构造器函数创建的。从原型继承的方法与属性是在构造器函数中定义的。
- prototype属性:
prototype属性并不指向当前对象的原型对象(原型对象是一个内部对象,应当使用 __proto__ 访问)。prototype属性是继承成员被定义的地方。
常见的对象定义模式是,在构造器(函数体)中定义属性、在 prototype 属性上定义方法。(在prototype属性中定义属性会不够灵活)
发现的比较奇异的点:一个变量不是函数的话默认没有 prototype属性,是函数的话默认就有 prototype属性,并且prototype对象中的constructor属性就是它本身
var a = {};
console.log(a.__proto__) //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(a.__proto__ === Object.prototype) //true
console.log(a.constructor) //ƒ Object() { [native code] }
console.log(a.constructor === Object) //true
//******不是函数的话默认没有 prototype属性
console.log(a.prototype) //undefined
console.log('b:')
var b = function c() { };
console.log(b.__proto__) //ƒ () { [native code] }
console.log(b.__proto__ === Function.prototype) //true
console.log(b.constructor) //ƒ Function() { [native code] }
console.log(b.constructor === Function) //true
//******函数默认就有 prototype属性,并且prototype对象中的constructor属性就是它本身
console.log(b.prototype) //{constructor: ƒ}
console.log(b.prototype.constructor) //ƒ c() { }
console.log(b.prototype.constructor===b) //true
constructor
每个对象实例都具有 constructor 属性,它指向创建该实例的构造器函数。
可以将此属性作为构造器使用:
var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
获得某个对象实例的构造器的名字,可以这么用:
person1.constructor.name
该属性的值是那个函数本身,而不是一个包含函数名称的字符串。对于原始值(js中有5种:null undefined number boolean string),该属性为只读。
var a = 1;
console.log(a.prototype) //undefined
console.log(a.constructor) //ƒ Number() { [native code] }
var b = [];
console.log(b.prototype) //undefined
console.log(b.constructor) //ƒ Array() { [native code] }
//改变 a b 的constructor为 {}
a.constructor = {}
b.constructor = {}
console.log(a.constructor) //没有变,还是 ƒ Number() { [native code] }
console.log(b.constructor) //{}
new
class
函数堆栈
ECMAScript中变量的两种类型
原始值:
引用值:
js三大组成部分
1.ECMAScript
2.dom
3.bom
http协议
除了 GET POST,还有哪些方法
keep-alive
http返回码100 200 300 400分别代表什么,即响应的5种类型
100:信息响应
200:成功
300:重定向
400:客户端错误
500:服务端错误
理解重定向
http无状态含义
解释三次握手,四次挥手
三次握手
1.客户端发syn包给服务端,等待服务器确认(syn:同步序列编号(Synchronize Sequence Numbers))
2.服务端发syn+ack包给客户端
3.客户端发确认包ack给服务端
四次挥手
中断连接端可以是Client端,也可以是Server端。
1.关闭主动方发送fin包
2.被动方发送ack包
3.被动方关闭连接,发送fin包
4.主动方发送ack包确认
数据结构与算法
链表和数组的区别
了解过哪些排序算法
js代码实现
自己实现个jQuery,可以传选择器进去,然后实现css()与height()方法
var myJquery4 = function (selector) {
//console.log(this) //window
return new jqNodes(selector) //new会创造一个对象实例,对象实例继承自构造函数的prototype,这里是jqNodes.prototype
}
var jqNodes = function (selector) {
console.log(this)
//1.以new调用时this指向即将创建的新对象
//2.直接调用则指向 window
this._items = document.querySelectorAll(selector)
return this
}
var myJqueryCore = {
//放核心方法
css: function () {
console.log(this) //myJquery4('li').css('color') 这样调用时是作为new出来的对象原型里的方法调用的,this指向new出来的对象
var prop = arguments[0],
val = arguments[1]
if (!val) return getComputedStyle(this._items[0]).getPropertyValue(prop);
Array.prototype.map.call(this._items, function (c) {
return c.setAttribute('style', prop + ':' + val)
})
return this
}
}
jqNodes.prototype = myJqueryCore //关键
写个轮播图
之前感觉比较困扰的是从最后一页到第一页如何无缝滑动。无缝滑动的关键在于在第一页前放上最后一页,在最后一页后面再放上第一页。在最后一页点击后一页时,先滑动到放置在后边的第一页,滑动完成后立刻改变父元素的left值到排列在第二个的第一页。
html结构:
<div id="list" style="left: -600px;">
<div>5</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>1</div>
</div>
关键js:
$('#list').animate({ left: newLeft }, function () {
if (newLeft < -3000) {
list.style.left = -600 + 'px';
} else if (newLeft > -600) {
list.style.left = -3000 + 'px';
}
})
菜单高亮滚动监听
主要参考了 http://blog.csdn.net/sinrryzh...
我修改成了可以有多个固定导航的
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.fix-menu {
position: fixed;
right: 30px;
top: 30px;
width: 160px;
list-style-type: none;
font-size: 14px;
padding: 0;
}
.fix-menu ul {
list-style-type: none;
padding: 0;
}
._h2 a{
padding-left: 20px;
}
._h3 a{
padding-left: 40px;
}
.fix-menu a {
color: #333;
text-decoration: none;
line-height: 28px;
display: block;
width: 100%;
}
.fix-menu .active {
background: #f4f6fb;
color: green;
border-left: 4px solid green;
}
.fix-menu .active a {
color: green;
}
</style>
</head>
<body>
<div class="main" id="main1">
<div class="m-cloumn" id="c1">
<h2>栏目1内容</h2>
</div>
<div class="m-cloumn" id="c2">
<h2>栏目2内容</h2>
</div>
<div class="m-cloumn" id="c3">
<h2>栏目3内容</h2>
</div>
<div class="m-cloumn" id="c4">
<h2>栏目4内容</h2>
</div>
<div class="m-cloumn" id="c5">
<h2>栏目5内容</h2>
</div>
<div class="m-cloumn" id="c6">
<h2>栏目6内容</h2>
</div>
<div class="m-cloumn" id="c7">
<h2>栏目7内容</h2>
</div>
</div>
<div class="right-cloumn" id="menu1">
<a href="#c1" class="curr">栏目1</a>
<a href="#c2">栏目2</a>
<a href="#c3">栏目3</a>
<a href="#c4">栏目4</a>
<a href="#c5">栏目5</a>
<a href="#c6">栏目6</a>
<a href="#c7">栏目7</a>
</div>
<div class="main" id="main2">
<div class="m-cloumn" id="c2-1">
<h2>栏目2-1内容</h2>
</div>
<div class="m-cloumn" id="c2-2">
<h2>栏目2-2内容</h2>
</div>
<div class="m-cloumn" id="c2-3">
<h2>栏目2-3内容</h2>
</div>
<div class="m-cloumn" id="c2-4">
<h2>栏目2-4内容</h2>
</div>
<div class="m-cloumn" id="c2-5">
<h2>栏目2-5内容</h2>
</div>
<div class="m-cloumn" id="c2-6">
<h2>栏目2-6内容</h2>
</div>
<div class="m-cloumn" id="c2-7">
<h2>栏目2-7内容</h2>
</div>
</div>
<div class="right-cloumn" id="menu2">
<a href="#c2-1">栏目2-1</a>
<a href="#c2-2">栏目2-2</a>
<a href="#c2-3">栏目2-3</a>
<a href="#c2-4">栏目2-4</a>
<a href="#c2-5">栏目2-5</a>
<a href="#c2-6">栏目2-6</a>
<a href="#c2-7">栏目2-7</a>
</div>
<script src="../jquery.min.js" type="text/javascript"></script>
<script>
(function ($, win, doc) {
var scroll_highlight = function (obj) {
return new scroll_rsilder(obj)
}
var scroll_rsilder = function (obj) {
this.init(obj)
}
scroll_rsilder.prototype = {
win_evet: function () {
var _this = this._this
$(win).on("scroll", function () {
var scrollTop = $(this).scrollTop();
_this.ele_evet(scrollTop);
})
},
ele_evet: function (scrollTop) {
var _this = this._this
$(this.cloumn).each(function (index) {
var offsetTop = $(this).offset().top;
var xd = parseInt(offsetTop - scrollTop);
//console.log(index, offsetTop, scrollTop, xd, _this)
if (xd < _this.spacing) {
$(_this.silder).eq(index).addClass(_this.curr).siblings().removeClass();
}
})
},
init: function (obj) {
this._this = this,
this.cloumn = obj.cloumn,
this.silder = obj.silder,
this.spacing = obj.spacing || 100,
this.curr = obj.curr || "curr";
if (!this.cloumn) return;
this.win_evet();
}
}
win.scroll_highlight = scroll_highlight;
})(jQuery, window, document)
</script>
<script>
$(function () {
scroll_highlight({
cloumn: "#main1 .m-cloumn",
silder: "#menu1 a",
spacing: 80,
curr: "curr"
})
scroll_highlight({
cloumn: "#main2 .m-cloumn",
silder: "#menu2 a",
spacing: 80,
curr: "curr"
})
})
</script>
</body>
</html>
网上看的面试题&自己发现的面试知识点
注:自己发现的面试知识点一般是在工作学习中发现的基础重要但之前被自己忽略的知识点。
js基础
全等号优先级大于逻辑与
var a=1===2&&3?4:5
逗号操作符
逗号操作符 对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
var x=(0,1) //x=1
比较对象
两个独立声明的对象永远也不会相等,即使他们有相同的属性,只有在比较一个对象和这个对象的引用时,才会返回true.
encodeURI encodeURIComponent
- encodeURI
encodeURI 会替换所有的字符,但不包括以下字符,即使它们具有适当的UTF-8转义序列:
类型 包含
保留字符 ; , / ? : @ & = + $
非转义的字符 字母 数字 - _ . ! ~ * ' ( )
数字符号 #
encodeURI自身无法产生能适用于HTTP GET 或 POST 请求的URI,例如对于 XMLHTTPRequests, 因为 "&", "+", 和 "=" 不会被编码,然而在 GET 和 POST 请求中它们是特殊字符。然而encodeURIComponent这个方法会对这些字符编码。
- encodeURIComponent
转义除了字母、数字、(、)、.、!、~、*、'、-和_之外的所有字符。
dangerouslysethtml会过滤掉__html属性里的 ,是因为用了encodeURI函数来避免xss攻击
encodeURI('/\/\//') -->”////“
encodeURI('\') --> Uncaught SyntaxError: Invalid or unexpected token
encodeURIComponent('/\/\//') -->"%2F%2F%2F%2F"
encodeURIComponent('/') --> "%2F"
encodeURIComponent('\') --> Uncaught SyntaxError: Invalid or unexpected token
http协议
xss
cross-site scripting,跨站脚本,属于代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了html以及用户端脚本语言。
攻击实例:用户A提交表单事加入类似以下代码,如果提交表单时没有做检测,而之后的结果页面是其他用户也能看到的,那么其他页面看到的结果页就会受到影响。
<script>
document.write('...')
</script>
解决办法:不信赖用户输入,对特殊字符如”<”,”>”转义。
uri url urn
uri:统一资源标识符
url:统一资源定位符
urn:统一资源名称
url与urn是uri的子集。
让uri能成为url的是那个“访问机制”,“网络位置”。e.g. http:// or ftp://.。
urn是唯一标识的一部分,就是一个特殊的名字。
etag是什么
ETag(entity tag)唯一地表示一份资源的实体标签。
标签是由 ASCII 字符组成的字符串,用双引号括起来(如 "675af34563dc-tr34")。前面可以加上 W/ 前缀表示应该采用弱比较算法。
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
ETag由Web服务器根据URL上的资源的特定版本而指定。如果那个URL上的资源内容改变,一个新的不一样的ETag就会被分配。ETag的比较只对同一个URL有意义——不同URL上的资源的ETag值可能相同也可能不同,从他们的ETag的比较中无从推断。
用法:
1.检测"空中碰撞"(资源同步更新而相互覆盖):
在ETag和 If-Match 头部的帮助下,可以检测到"空中碰撞"的编辑冲突。
2.缓存未更改的资源
如果用户再次访问给定的URL(设有ETag字段),显示资源过期了且不可用,客户端就发送值为ETag的If-None-Match header字段:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
服务器将客户端的ETag(作为If-None-Match字段的值一起发送)与其当前版本的资源的ETag进行比较,如果两个值匹配(即资源未更改),服务器将返回不带任何内容的304未修改状态,告诉客户端缓存版本可用(新鲜)。
If-Match 头部
请求首部 If-Match 的使用表示这是一个条件请求。在请求方法为 GET 和 HEAD 的情况下,服务器仅在请求的资源满足此首部列出的 ETag 之一时才会返回资源。而对于 PUT 或其他非安全方法来说,只有在满足条件的情况下才可以将资源上传。
应用:
- GET 和 HEAD 方法,搭配 Range首部使用,可以用来保证新请求的范围与之前请求的范围是对同一份资源的请求。如果 ETag 无法匹配,那么需要返回 416 (Range Not Satisfiable,范围请求无法满足) 响应。
2.对于其他方法来说,尤其是 PUT, If-Match 首部可以用来检测用户想要上传的不会覆盖获取原始资源之后做出的更新。如果请求的条件不满足,那么需要返回 412 (Precondition Failed,先决条件失败) 响应。
语法:
If-Match: <etag_value>, <etag_value>, …
乐观并发控制
ASCII字符串
ASCII (发音: /ˈæski/ ,American Standard Code for Information Interchange,美国信息交换标准码) 是计算机中最常用的编码方式,用于将字母,数字,标点符号和控制字符转换为计算机可以理解的数字形式。
ASCII的局限在于只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如naïve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。而ASCII虽然解决了部分西欧语言的显示问题,但对更多其他语言依然无能为力。因此现在的软件系统大多采用Unicode。
ASCII主要用于显示现代英语和其他西欧语言。从2007年开始逐渐被UTF-8 代替。
Unicode
Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。
UTF-8
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部分修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或发送文字的应用中,优先采用的编码。
Range首部
Range 是一个请求首部,告知服务器返回文件的哪一部分。在一个 Range 首部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。如果服务器返回的是范围响应,需要使用 206 Partial Content 状态码。假如所请求的范围不合法,那么服务器会返回 416 Range Not Satisfiable 状态码,表示客户端错误。服务器允许忽略 Range 首部,从而返回整个文件,状态码用 200 。
语法:
Range: <unit>=<range-start>-
Range: <unit>=<range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>
Range: bytes=200-1000, 2000-6576, 19000-
一级域名,二级域名
以www.baidu.com为例子
最右边一个点右边的为顶级域名(一级域名)com
一级域名左边是二级域名 baidu
主域,子域
子域名域名系统等级中,属于更高一层域的域。比如,mail.example.com
和calendar.example.com是example.com的两个子域,而example.com
则是顶级域.com的子域
非技术问题
为什么换工作
不要说是因为钱少。上一家的薪资不要做假,因为公司可能会查。期望薪资可以要高点,说明。
<script src="../jquery.min.js"></script>
<script src="../scroll-highlight.js"></script>
<script src="../fix-menu.js"></script>