HTML
如何理解 HTML 语义化
HTML 语义化就是使用正确的标签, 比如段落就写 p 标签,标题就写 h1 标签,文章就写 article 标签,视频就写 video 标签,等等。总之核心就是反对大篇幅的使用无语义化的 div + css + span,而鼓励使用 HTML 定义好的语义化标签。
meta viewport
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
viewport 可以翻译为窗口或视图,主要用于移动端。主要属性:
width:控制viewport的宽度initial-scale:默认缩放比例minimum-scale:最小缩放比例maximum-scale:最大缩放比例user-scalable:是否允许手动缩放
用过哪些 HTML 5 标签
h1,h2...:文档标签a超链接:div:通用的容器,没有特殊含义header:页面或章节的头部(Logo、标题、导航栏目录...)footer:页面或章节的尾部(版权信息、法律信息、反馈建议...)
SEO 友好
SEO 即 引擎优化,能让百度、谷歌搜索排名靠前。
如何让 SEO 友好?
- 静态url,便于搜索引擎抓取
- 避免使用框架
- 符合W3C标准代码
title、meta、content、h1、a标签写好
CSS
两种盒模型
- 标准盒模型:
box-sizing: content-box;只是对content-box设置了宽高,那么这个元素的真正宽高还要加上内边距(padding)、边距(border)、外边距(margin),于是我们布局的时候就要好好计算一下了。 - IE 盒模型:
box-sizing: border-box;常用的盒模型。content部分包含了内边距(padding)和边距(border),把整个盒子看作了一个整体,给整个盒子定义了宽高。
Flex 怎么用
display: flex;
BFC 是什么
BFC(Block Formatting Context)就是块级格式化上下文,就是一个独立的容器,形成一个独立的空间,不受外部影响,也不影响外部。
- 浮动元素(元素的 float 不是 none)
- 绝对定位元素(元素的 position 为 absolute 或 fixed; position不为 relative 和 static)
- 行内块元素(元素的 display 为 inline-block)
- overflow 值不为 visible 的块元素; overflow为auto、scroll和hidden
- 弹性元素(display为 flex 或 table-cell 或 inline-flex元素的直接子元素)
CSS 选择器优先级
<style>
#box a {
color: green !important; // 第一优等生(!important)
}
#box a { // 第三优等生(ID选择器)
color: green;
}
[class="box"] a { // 第五优等生(class选择器)
color: gold;
}
.box a { // 第四优等生(class选择器 比上面等级高,因为靠后覆盖了)
color: brown;
}
a { 第七优等生
color: red;
}
p a { // 第六优等生
color: yellow;
}
* { // 最后一名
color: red;
}
</style>
<p id='box' class="box">
<a style="color: red"> // 第二优等生(内联样式)
hi
</a>
</p>
- 越具体优先级越高
- 同样优先级 写在后面的, 覆盖写在前面的
!important优先级最高,但是要少用
JS
ES6 语法
let、const- 箭头函数
Promise- 展开操作符
- 默认参数
import、export- 析构赋值
Promise
- 介绍:异步操作返回的对象,用来传递异步操作的消息。
- 优势:解决了回调地狱,不会导致难以维护,合并多个异步请求,节约时间。
- 状态:
pending初始、fulfilled成功、rejected失败 Promise用法:
function getPromise(URL) {
let promise = new Promise(function (resolve, reject) {
let req = new XMLHttpRequest();
req.open("GET", URL);
req.onload = function () {
if (req.status == 200) {
resolve(req.response);
} else {
reject("There is an Error!");
}
};
req.send();
});
return promise;
}
Promise.all用法
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
// p1 和 p2 都成功才能调用
Promise.all([p1, p2]).then(values => {
console.log(values) // ['one','two']
})
Promise.race用法
// 比赛谁跑得快,无论是先成功还是先失败
const p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
const p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
// p1 和 p2 都成功才能调用
Promise.race([p1, p2]).then(values => {
console.log(values) // 'one'
})
Promise.allSettled用法:解决了Promise.all的痛点,即永远不会被rejectPromise.prototype.finally()用法:无论结果是Resolved或者是Rejected都需要执行的代码提供了一种方式,避免同样的语句需要在then()和catch()中各写一次的情况。Promise缺点:- 无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
Axios
基于 Promise 的 HTTP 库。
优点
- 安全性高
- 支持请求取消
- 批量发送多个请求
- 支持 Promise 所有的 API
- 可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON 类型的数据
防抖、节流
- 防抖:触发事件后n秒后才执行函数,如果n秒内执行,则重新计算函数执行事件。(立即施行 与 非立即执行)
- 节流:无论怎么点击,每过n秒只执行一次函数
call、apply、bind
// call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。
const numbers = [1, 2, 3];
const maxInNumbers = Math.max.apply(Math, numbers); // 3
const maxInNumbers = Math.max.call(Math, 1, 2, 3); // 3
// bind 接受的参数跟 call 一致,只是 bind 不会立即调用,它会生成一个新的函数,你想什么时候调就什么时候调。
function f1(p1, p2){
console.log(this, p1, p2);
}
let f2 = f1.bind({name:'liang'}); //f2为f1绑定了this之后的新函数
let f3 = f1.bind({name:'liang','hi'}) //f3为f1绑定了this之后的新函数,并且传入了一个参数‘hi’
f2(); // {name:'liang'} undefined undefined
f3(); // {name:'liang'} "hi" undefined
闭包
函数 和 函数内部能访问到的变量 的总和,就叫一个闭包。如下,local 变量和 bar 函数就组成了一个闭包。
用途:隐藏一个变量,防止变成全局变量受到外界干扰。
缺点:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题;在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
function foo() {
let local = 1;
function bar() {
local++;
return local;
}
return bar;
}
const func = foo();
func() // 2
立即执行函数
创建一个独立的作用域,这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
(function(){alert('我是匿名函数')})()
同源、跨域、JSONP、CORS
- 同源:协议、域名、端口 都相同
- 跨域:不同源的两个源受到浏览器阻止
- CORS:
Access-Control-Allow-Origin - JSONP:由于浏览器不支持CORS(IE小于9),并且JSONP只能解决GET,无法POST。
深拷贝、浅拷贝
深拷贝:
JSON.parse(JSON.stringify(data)); // 不能处理函数( [1, 2, function(){}] )
浅拷贝:
data.slice(); // 仅仅复制指针值,没有复制指向的对象。
DOM
事件委托
事件委托可以理解为【事件】和【委托】。【事件】就是指onclick或onmouseover等,【委托】就是让别的元素来完成自己本该完成的事件,也就是通过事件冒泡。
不必为每个元素分配一个处理程序,而是将单个处理程序放在他们的共同组建身上。
优点:减少监听器
缺点:不支持冒泡的事件不能使用事件委托。
HTTP
HTTP 状态码
| 200 | OK | 请求成功, 一般用于GET与POST请求 |
| 304 | Not Modified | 请求的资源未修改,服务器不会返回任何资源 |
| 400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
| 403 | Forbidden | 服务端拒绝客户端的请求 |
| 404 | Not Found | 服务端无法根据客户端的请求找到资源 |
| 500 | Internal Server Error | 服务端内部错误 |
HTTP 缓存有哪几种
ETag:通过对比浏览器和服务器资源的特征值(如MD5)来决定是否要发送文件内容,如果一样就只发送 304(not modified)Expires:设置过期时间(绝对时间)CacheControl:设置过期时间(相对时间)
HTTP 请求方法
GET:用于获取资源HEAD:和 GET 类似,只不过返回的没有具体的内容,用于获取报头POST:提交请求体(数据)到指定提交、创建资源PUT:客户端发送数据来修改文档的内容DELETE:请求服务器删除指定数据PATCH:类似 PUT,用来对已知资源进行局部更新
GET vs POST
- GET 参数通过 URL 传递,POST 是放在 request body 里,因此 POST 更安全
- GET 请求参数有上线,POST 没有
- GET 请求会保存在cache、收藏栏、浏览器历史记录里,POST 不会
- GET 请求回退时无害的,而 POST 会再次提交请求
- GET 的参数类型只接受ASCII字符,POST 无限制
Session vs Cookie
- Cookie 存在浏览器的文件里,Session 存在服务器的文件里
- Session 是基于 Cookie 实现的,具体做法就是把 SessionID 存在 Cookie 里
Cookie vs LocalStorage
- 主要区别是 Cookie 会被发送到服务器,而 LocalStorage 不会
- Cookie 一般最大 4k,LocalStorage 可以用 5Mb 甚至 10Mb(各浏览器不同)
LocalStorage vs SessionStorage
LocalStorage 一般不会自动过期(除非用户手动清除),而 SessionStorage 在会话结束时过期(如关闭浏览器)
Vue
Vue 与 MVVM
Vue 并不完全遵循 MVVM。
MVVM 指 Model(数据) 变更触发 View(视图) 更新时必须通过 ViewModel(Vue实例)。同理,View 变更触发 Model 也必须通过 ViewModel(使用 v-model)。
而 Vue 可以通过 ref 拿到 dom 对象,去操作视图,这一点,保留了 MVC,违背了 MVVM,总之就是结合了两者优势。
Vue 与 React 区别
Vue 是自动挡,React 是手动挡。React 推荐函数式编程,是单向数据流,当然也可以双向,通过setState等。有人说 Vue 是双向数据流,非也。Vue 也是单向,只是 v-model 用了语法糖(change和input事件以及value属性)。
Vue3 与 Vue2 区别
- Vue3 速度快,体积小。
tree-shaking,将无用的模块剪辑,仅打包需要的 Composition API:可与Options API一起使用,可复用,更易维护- 拥抱 TypeScript
diff算法优化(静态标记:在发生变化的位置添加flag标记,下次发生变化的时候直接找该地方进行比较)- 在
vue2中,数据劫持是通过Object.defineProperty,这个 API 有一些缺陷,并不能检测对象属性的添加和删除。vue3是通过proxy监听整个对象,那么对于删除还是监听当然也能监听到 - 组建支持多个根节点(
<template>...</template>) Teleport
Vue3 - Teleport
任意门,能够把模块移动到其他位置。eg:有ABC三个组件,分别是父、子、孙。孙组件里有个button,点击后添加触发弹窗。如果不用 Teleport,父组件和子组件的UI会受到影响,如果通过任意门把该弹窗组件放在外出,就不用受到影响,这也是 UI 框架常用的手段。
SPA(单页面应用)首屏加载慢如何解决
SPA(Single Page Application)。一开始(首屏)就会加载所有必需的代码,这样一来,以后用户的每一个动作都不会重新加载页面。
如何优化首屏加载速度?
- 减小入口文件积
// 路由懒加载,在 `vue-router` 配置路由中,采用动态加载路由(函数式)的形式。
routes:[
path: 'Blogs',
name: 'ShowBlogs',
component: () => import('./components/ShowBlogs.vue')
]
- 静态资源本地缓存
采用
HTTP缓存,设置Cache-Control,Last-Modified,Etag等响应头
- 使用SSR
Server Side,服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
- UI框架按需加载
- 图片资源的压缩
v-show 与 v-if 区别
- 作用是相通的,都能控制元素在页面上的显示。
v-show隐藏通过 css:display: none,dom 元素依旧还在。v-if则把整个dom元素添加或删除。v-if有更高的切换消耗,且其是惰性的,如果一开始条件为false,是不会操作的。- 如果追求性能,总体上
v-show是更好的选择,除非需要else if,那就用v-if。
v-if 和 v-for 区别及优先级
v-for 比 v-if 层级高。不要把这两个放在一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)。应该在外层放一层 template,然后在内部进行循环。
<template v-if="isShow">
<p v-for="item in items">
</template>
watch / computed / methods
watch是监听,computed是计算,methods是方法。computed有缓存,methods、watch无缓存。methods每次渲染都会执行,
.sync / v-model
实现自组件和父组件之间的双向绑定。父组件通过 props 传值给子组件,子组件通过 $emit 传值给父组件。.sync 和 v-model 都是语法糖。
生命周期
beforeCreate:created:beforeMount:mounted:beforeUpdate:updated:activated:deactivated:beforeDestroy:destroyed:
组件间通信
props/$emit:父子组件$emit/on:任意组件provide/inject:祖先组件eventBus:任意组件VueX
数据响应式
修改数据时,视图重新渲染。
Vue2 使用 Object.defineProperty 把属性转换为 getter 和 setter,由于无法检测到对象属性的添加和删除,就有了 this.$set
Vue3 使用 ref 或 reactive 来创建响应式数据。
VueX
用于管理数据的一个工具,用于实现组件之间的数据共享。
state:存放共享变量的地方
getter:获取数据,不会修改 state,只起到包装作用。类似于computed。
mutations:存放修改 state 的方法。
actions:存放修改 state 的方法,在 mutations 上做异步的操作。
commit:调用这些操作的 API
Vue Router
路由模式:
hash:# 符号之前的包含在请求中,因此即使后端没有对路由全覆盖,也不会产生404。history:依赖服务器配置,因此如果 URL 匹配不到任何静态资源,则返回之前页面。abstract:支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.
TS
简介
TS 是强类型的 JS 超集,可以实现静态类型检查。其不能直接在浏览器上运行,需要通过编译器转换为 JS 再运行。
Webpack
XSS / CSRF
什么是 XSS,如何预防
Cross Site Scripting,跨站脚本攻击。在Vue中当用v-html在填入等地区时,容易触发。
如何攻击?
- 表单输入、onClick等情况下,黑客输入代码,获取你的cookie或sessionID
如何预防?
- 输入过滤,例如:邮箱,电话号码,用户名,密码等
- httpOnly,在 cookie 中设置 HttpOnly 属性后,js脚本将无法读取到 cookie 信息
- 转义 HTML,对于引号,尖括号,斜杠等
什么是 CSRF,如何预防
Cross-site request forgery,跨站请求伪造。
攻击过程:
- 用户小张登录安全网页A,验证通过,A网站给小张发送cookie许可。
- 小张在没有访问A网站的情况下,登录黑客网站B,不小心点击了按钮,B网站向A网站发送请求。
- B网站偷到小张的cookie后访问A,A网站不知情,黑客成功入侵。
如何预防?
- 验证码
- token
XSS 与 CSRF 区别
- 通常CSRF是由XSS实现的,比如用户A去了黑客网站,黑客网站通过按钮或通过命令行发起请求。
- XSS是代码注入、没有过滤造成的问题;CSRF时HTTP问题,即发起请求的时候自动带上受害者的cookie。
手撕代码
清除浮动
.clearfix:after{
content: '';
display: block; /*或者 table*/
clear: both;
}
.clearfix{
zoom: 1; /* IE 兼容*/
}
垂直居中
display: flex;
justify-content: center;
align-items: center
防抖
let timerID = null;
const debounce = (e) => {
timerID && clearTimeOut(timerID);
timerID = setTimeOut(() => {
const value = e.target.value;
...
}, 500)
}
数组去重
// 开发时用法
const newArr = [...new Set(arr)]
// 面试时用法 (哈希Map)
const arr = [1,1,3,3,2];
function removeDup(arr) {
let map = new Map();
let newArr = [];
for(let o = 0; o < arr.length; o++) {
if(map.has(arr[o])) {
map.set(arr[o], true);
} else {
map.set(arr[o], false);
newArr.push(arr[o]);
}
}
return newArr;
}
手写 AJAX
//创建 XMLHttpRequest 对象
let ajaxReq = XMLHttpReuqest();
//规定请求的类型、URL 以及是否异步处理请求。
ajaxReq.open('GET', url, true);
//发送请求
ajaxReq.send();
//接受服务器响应数据
ajaxReq.onreadystatechange = function() {
if(ajaxReq.status === 200 && ajaxReq.readyState === 4) {
console.log(ajaxReq.responseText);
}
}
快排
function quickSort(arr) {
if(arr.length <= 1) return arr;
let pivotIndex = Math.floor(arr.length / 2);
let pivot = arr.splice(pivotIndex, 1)[0];
let left = [], right = [];
for(let o = 0; o < arr.length; o++) {
arr[o] < pivot ? left.push(arr[o]) : right.push(arr[o]);
}
return quickSort(left).concat([pivot],quickSort(right));
}
冒泡排序
function bubbleSort(arr) {
let done = false;
for(let o = 0; o < arr.length - 1; o++) {
if(arr[o] > arr[o+1]) {
[arr[o], arr[o+1]] = [arr[o+1], arr[o]];
done = false;
}
if(o === arr.length - 2) {
if(done) return arr;
o = -1;
done = true;
}
}
}