文章目录
- 原生JS
- CSS
原生JS
6个基本数据类型
string、number、null、undefined、boolean,symbol
常用DOM操作
访问元素:
- document.getElementById
- document.getElementsByTagName
- document.getElementsByClassName
- document.querySelector
- document.querySelectorAll等
操作DOM节点的class:
- node.classList.add()
- node.classList.remove()
- node.classList.contains()
- node.classList.toggle()
跨域
发生原因:同源策略(同协议,同域名,同端口)
解决办法:CORS(IE10+,服务器实现,开放非同源请求接口:Access-Control-Allow-Origin: http://api.bob.com),JSONP(仅GET)
如何中断ajax请求:
超时自动断开,手动停止,调用xhr.abort()
事件代理:
为父元素添加事件处理函数,利用事件冒泡机制,判断event.target值来实现处理函数
优缺点:提高性能,向后兼容,可维护性强;但只能为最后一层dom元素执行事件处理函数
target && currentTarget
target为当前触发事件的dom元素
currentTarget为绑定事件的dom元素
闭包:
a函数内部有一个变量b和一个函数c,最后将函数c返回出去,在外面作用域中执行函数a并将其执行结果赋值给d,此时,d可以访问a函数内部的变量b,且b不受外界影响且仅d能访问,多个实例d中的变量b都是自己私有,并不公用。
优缺点:能够读取其他函数内部的变量;让这些变量一直存在于内存中(因为一直存在着引用,js的垃圾回收机制一直不会回收这部分内存),所以会造成内存泄漏
常见用途:防抖节流
继承的几种方式及其优缺点:
-
原型链继承:将新实例的原型赋值为父函数的实例:
-
function Parent() {}; function Child() {}; child.prototype = new Parent();
-
优缺点:子类可以使用父类的方法,但不能向父类的构造函数传参,所有实例共享同一父类的属性与方法,一个实例修改了原型的属性,其他实例也会受影响
-
-
构造函数继承:用call()或apply()将父函数的构造函数拿到子函数中调用一下
-
function Parent(name) { this.name = name; this.say = function () { console.log(this.name); } } function Child(name) { parent.call(this, name); this.age = 18; }
-
优点:
- 可向父级的构造函数中传参;
- 同一个父级的所有实例之间互不影响;
-
缺点:
- 只继承了父级的构造函数的属性与方法,没有继承父级原型上的构造函数与方法;
- 无法实现父级构造函数的复用;
- 每个新实例都有父级构造函数的副本,臃肿
-
-
组合继承:原型链继承 + 构造函数继承 (常用)
-
function Parent(name) { this.name = name; this.say = function () { console.log(this.name); } } function Child(name) { parent.call(this, name); this.age = 18; } Child.prototype = new Parent(); var xiaoming = new Child();
-
优点:可以继承父级原型链上的属性,可传参,可复用
-
缺点:调用了2次父级的构造函数,消耗内存
-
-
原型式继承:
-
function Parent(name) { this.name = name; this.say = function () { console.log(this.name); } } function content(obj) { function f() {}; f.prototype = obj(); return new f(); } var xiaoming = new Parent(); var xiaomei = content(xiaoming);
-
-
寄生式继承:
-
function Parent(name) { this.name = name; this.say = function () { console.log(this.name); } } function content(obj) { function f() {}; f.prototype = obj; return new f(); } var sup = new Parent(); funtion subObj(obj) { var sub = content(obj); sub.name = 'wei'; return sub; } var child = subObj(sup);
-
就是给原型式继承套了个壳子
-
-
寄生组合式继承:(常用)
-
function Parent(name) { this.name = name; this.say = function () { console.log(this.name); } } //寄生 function content(obj) { function f() {}; f.prototype = obj; return new f(); } //content就是F实例的另一种表示法 var con = content(Parent.prototype); //con实例(F实例)的原型继承了父函数的原型 //上述更像是原型链继承,只不过只继承了原型链属性 //组合 function Sub() { Persion.call(this);//这个继承了父类构造函数的属性 } //解决了组合式继承两次调用构造函数的问题 //重点 Sub.prototype = con;//继承了con实例 con.constructor = Sub;//一定要修复实例 var sub1 = new Sub(); //Sub的实例就继承了构造函数的属性,父类实例,con的函数属性 console.log(sub1.age)
-
export && export default
export可以先定义在导出,export default只能直接导出
export导出的模块导入方法:
import {a, b} from ‘./c’
export default导出的模块导入方法:
import a from ‘./a’
数组去重:
set方法:arr = […new Set(arr)];
空间换时间:数组下标判断法 + 双向循环 && 利用对象属性名的唯一性
get && post
- get请求数据在地址栏中,post在http包内,所以post相对于get更加安全
- get后退不会有影响,post后退会重新提交表单
- get一般作用于向服务器请求数据,post一般用于向服务器传数据,服务器解析数据并执行相应命令,如操作数据库
- 我们如果使用GET请求做增删改查的时候,遇到网络不好可能会多次操作,造成数据库的混乱,这是一个很严重的问题,但是使用POST就不会有这种情况。
常见的http响应码及其含义
- 1xx(临时响应)
- 100:继续提交请求
- 2xx(成功)
- 200:成功
- 201:资源被正确创建
- 3xx(已重定向)
- 301:请求成功,但资源已被永久转移
- 304:请求的资源并没有被修改过
- 4xx(请求错误)
- 400:请求错误,如请求头不对
- 403:权限不够
- 404:请求的内容不存在
- 5xx(服务器错误)
- 500:服务器代码错误
线程 && 进程
一个程序中有一个或多个进程,一个进程中有一个或多个线程,多线程程序并发性高;
一个进程独立拥有一个内存单元,其中的多个线程共享一个内存单元;
async await
是微任务
async将一个函数定义为异步函数,await只能在async的函数中执行,并且会返回一个promise对象。程序会等await后面的代码执行完成之后再向下执行,这也就是为什么await必须在async函数中出现的原因。
null && undefined
null本质上是一个空对象指针,所以typeof null -->object,undefined是定义了但未初始化的值
null == undefined true 因为 undefined 派生自 null
null === undefined false
null 会被转为0
undefined会被转为 NaN
map && set
map:键值对,任何值都可以作为键或者值,键值有序,size = 键值对个数
var myMap = new Map();
myMap.set(‘name’, ‘wei’),
myMap.get(‘name’)
obj:键值对,键只能是str或symbol,键值无序,键值对个数只能计算
set:存在唯一值的对象
var mySet = new Set();
mySet.add(5);
… …
myset --> {1, 5, {‘a’: ‘wei’}, ‘some’}
回流 && 重绘
回流:元素的布局、尺寸以及状态(显隐)发生改变会执行回流。
重绘:元素仅外观(如颜色)发生改变会执行重绘。
回流必重绘。
优化:
- 将多次回流重绘的操作放到一个队列中一起执行,就变成了一次回流重绘。
- 减少引起回流重绘的操作:改变dom样式时直接改变class,而不是改变多个属性;插入多个元素时将其用一个元素包起来一次性插入。
浅拷贝
ES6:let newObj = Object.assign({}, obj);
let newObj = {…obj};
深拷贝
jQuery && zepto:$.extend(是否深拷贝tf, 拷贝对象,被拷贝对象)
lodash:let 拷贝对象 = _.cloneDeep(被拷贝对象);
实现原理:创建新对象,遍历旧对象自有属性,判断值是否为引用类型object,是则递归复制,否则简单复制。
function deepClone(obj) => {
let deepObj = Array.isArray(obj) ? [] : {};
for(let item in obj) {
if(obj.hasOwnProperty(item)) {
if(obj[item] && typeof obj[item] === 'object') {
deepObj[item] = deepClone(obj[item]);
} else {
deepObj[item] = obj[item];
}
}
}
return deepObj;
}
for in && for of
for in 中的i 为数组下标或对象的键,可遍历数组和对象;
for of中的i为值,可遍历数组。
洗牌算法
sort(乱序排序):
let arr = [1,2,3,4,5];
function shuffle(arr) {
return arr.sort((a, b) => {
return Math.random() - 0.5;//sort()根据返回值tf判断a, b位置如何摆放,0~1随机数 - 0.5就是-0.5 ~ 0.5之间随机数
})
};
//随机获取旧数组中的值依次插入到新数组中并在旧数组中删除
function shuffle2(arr) {
let newArr = [],
preArr = arr,
len = arr.length;
while(len > 0) {
let randomNum = Math.floor(Math.random() * len --);
newArr.push(preArr.splice(randomNum, 1)[0]);//splice返回一个数组,(位置,删除个数,添加数据)
}
return newArr;
}
快排
原理:找基准值,小的放左面,大的放右面;新数组 = 左面数组 + 基准值 + 右面数组;最后左面数组与右面数组递归快排函数;
function quickSort(arr) {
let len = arr.length,
preArr = arr,
mid = Math.floor(len / 2),
baseNum = preArr.splice(mid, 1)[0],
leftArr = [],
rightArr = [];
if(len <= 1) {
reutrn arr;
}
preArr.forEach(v => {
if(v > baseNum) {
rightArr.push(v);
} else {
leftArr.push(v);
}
})
return quickSort(leftArr).concat(baseNum, quickSort(rightArr));
}
前后端交互
后端写接口和API文档,前端拿到后用ajax或fetch请求数据
ajax封装:new xhr --> open() --> send() -->onreadystatechange() -->responseText
function ajax(options){
options = options ||{}; //调用函数时如果options没有指定,就给它赋值{},一个空的Object
options.type=(options.type || "GET").toUpperCase();/// 请求格式GET、POST,默认为GET
options.dataType=options.dataType || "json"; //响应数据格式,默认json
var params=formatParams(options.data);//options.data请求的数据
var xhr;
//考虑兼容性
if(window.XMLHttpRequest){
xhr=new XMLHttpRequest();
}else if(window.ActiveObject){//兼容IE6以下版本
xhr=new ActiveXobject('Microsoft.XMLHTTP');
}
//启动并发送一个请求
if(options.type=="GET"){
xhr.open("GET",options.url+"?"+params,true);
xhr.send(null);
}else if(options.type=="POST"){
xhr.open("post",options.url,true);
//设置表单提交时的内容类型
//Content-type数据请求的格式
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(params);
}
// 设置有效时间
setTimeout(function(){
if(xhr.readySate!=4){
xhr.abort();
}
},options.timeout)
// 接收
// options.success成功之后的回调函数 options.error失败后的回调函数
//xhr.responseText,xhr.responseXML 获得字符串形式的响应数据或者XML形式的响应数据
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
var status=xhr.status;
if(status>=200&& status<300 || status==304){
options.success&&options.success(xhr.responseText,xhr.responseXML);
}else{
options.error&&options.error(status);
}
}
}
}
//格式化请求参数
function formatParams(data){
var arr=[];
for(var name in data){
arr.push(encodeURIComponent(name)+"="+encodeURIComponent(data[name]));
}
arr.push(("v="+Math.random()).replace(".",""));
return arr.join("&");
}
//基本的使用实例
ajax({
url:"http://server-name/login",
type:'post',
data:{
username:'username',
password:'password'
},
dataType:'json',
timeout:10000,
contentType:"application/json",
success:function(data){
。。。。。。//服务器返回响应,根据响应结果,分析是否登录成功
},
//异常处理
error:function(e){
console.log(e);
}
})
call apply bind
均用来改变this指向
apply中第二个参数是数组
bind不执行,返回函数
堆栈、队列
堆栈:先进后出,应用:
-
原型链继承,一个子类查询方法时,会一层一层查询直到最后的Object,但设计最初Object是最先放入的,然后是一个一个的继承对象。
-
作用域嵌套
-
基本数据类型的值放在栈中,引用数据类型值放在堆中。
-
实现栈:数组 + push() + pop()
-
括号匹配:(【((【{【)】))】}是否为正确的
- 解决:定义栈,遇到左括号压栈,遇到又括号则从栈顶开始查找是否有对应的左括号,如果有,二者私奔,如果没有,返回false即可;所有括号入栈完成后,如果站内还有括号,返回false。
队列:先进先出,应用:
- 消息队列,vue react都会有一个操作DOM的队列,将多个DOM操作放在一个队列中一起执行
浏览器的event loop
指浏览器或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
宏队列:定时器等
微队列:promise等
全局javascript执行——>当前所有微队列——>宏队列第一个——>执行上一个宏队列时产生的微队列——>下一个宏队列——>执行上一个宏队列时产生的微队列——>… …
大神文章:
https://segmentfault.com/a/1190000016278115
垃圾回收机制!
标记清除法:大部分浏览器;为所有变量添加标记,然后为有引用的变量删除标记,最后清除还带有标记的变量以释放内存。
引用计数法:IE9-
BOM对象模型
- screen
- window
- navigator
- location
- document
- history
Location对象属性
- hash 设置或返回从#开始的URL
- host 设置或返回主机名和当前URL的端口号
- hostname 设置或返回当前URL的主机名
- href 设置或返回完整的URL
- pathname 设置或返回当前URL的路径部分
- port 设置或返回当前URL的端口号
- search 设置或返回从?开始的URL(查询部分)
CSS
css选择器权重计算:
- !import : infinity
- 行间:1000
- id:100
- class、属性、伪类:10
- 标签、伪元素:1
- 通配符:0
#app .div1 > span {/*权重计算:100 + 10 + 1 = 111*/
}
.div2 > div > input[tyle="checkbox"] {/*权重计算:10 + 1 + 1 + 10 = 22*/
}
.div2 {/*权重计算:10*/
}
div.div2 {/*权重计算:1 + 10 = 11*/
}
CSS3新增属性:
-
flex盒子:display:flex;
-
媒体查询:@media
-
动画:@keyframes
-
边框:
- border-color
- border-image
- border-radius
- box-shadow
-
背景:
- background-size
- background-image
- background-position
-
渐变:
- 线性渐变:background-image:linear-gradient(to right, #f40, #fff);
- 径向渐变:background-iamge:radial-gradient(red, yellow, green);
-
2D/3D转换:
- transform()
- translate 平移
- rotate 旋转
- scale 放大缩小
- skew 倾斜
- rotateX 横轴旋转
- rotateY 纵轴旋转
- transform()
-
过渡:
- transition: width 1s linear 2s;
可继承属性
- font-size:设置字体的尺寸,但a标签不继承
- text-indent:文本缩进
- text-align:文本水平对齐
- text-shadow:设置文本阴影
- line-height:行高
- 元素可见性:visibility
- 光标属性:cursor
CSS水平居中:
行内元素:text-align:center;
flex:display: flex; flex-flow:row nowrap; justify-content: center;
定位:父元素:position:relative;子元素:position:absolute;left:50%;margin-left:transform:translateX(-50%);
子元素:margin:0 auto;
CSS垂直居中:
行内元素:line-height = height
flex:display:flex;flex-flow:row nowrap;align-items:center;
定位:父元素:position:relative;子元素:position:absolute;top:50%;margin-left:transform:translateY(-50%);
伪元素:div1::before {content: ‘’; display:inline-block; width:0; height: 100%; vertical-align:middle}
px&em&rem&vh&vw:
px为像素,绝对单位
em为相对单位,相对于其父元素的font-size属性值的倍数
rem为相对单位,相对于html的font-size属性值的倍数
vh为相对单位,100vh = 屏幕高度
vw为相对单位,100vw = 屏幕宽度
盒模型:
2种盒模型:
- box-sizing:border-box IE盒模型
- width = 左右边框 + 左右内边距 + 内容宽度;(外边距不算)
- 内容宽度会减小
- box-sizing:content-box W3C盒模型
- width = 内容宽度
- 内容宽度始终不变,盒子会向外扩张
画三角:
原理:盒子宽高为0,border指定值与颜色,四调边调整color是否为透明即可
清除浮动:
父元素:div1::after{content: ‘’;display:block;visibility:hidden;clear:both}
BFC:
块级格式化上下文,让内外区域元素定位互不影响
触发条件:position display float overflow等属性
两栏布局,左边固定右边自适应
浮动:左边浮动,并清除即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.parent > div {
height: 200px;
border: 1px solid #ddd;
}
.left {
float: left;
}
.right {
overflow: hidden;
}
</style>
</head>
<body>
<div class="parent">
<div class="left">left</div>
<div class="right">right</div>
</div>
</body>
</html>
绝对定位:左边绝对定位,右边设置margin-left
flex:父元素flex,左边固定宽度,右边flex-grow:1;
性能优化
DNS预解析:
DNS 实现域名到IP的映射。通过域名访问站点,每次请求都要做DNS解析。目前每次DNS解析,通常在200ms以下。
DNS Prefetch 是一种DNS 预解析技术,当浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在单击当前网页中的连接时就无需进行DNS的解析,减少用户等待时间,提高用户体验。
总结:让浏览器提前解析资源或接口对应的服务器ip地址。
手动预解析:
<link rel=“dns-prefetch” href=“www.baidu.com”>
注:dns-prefetch需慎用,多页面重复DNS预解析会增加重复DNS查询次数。
添加CDN服务:
阿里云CDN服务、腾讯云CDN服务等
优化了本地DNS系统请求到对应url的IP地址的请求时间。
点击url之后,本地DNS系统会将域名解析权交个CNAME指向的CDN专用的DNS服务器。DNS服务器会经过一系列优化计算(距离用户近,有用户需要的内容,缓存服务器负载情况允许),计算出一个最优的缓存服务器的IP地址,并将用户的请求重定向到该服务器,该缓存服务器返回给用户对应url的IP地址。
CDN优化原理
在网络中增加一层缓存(CACHE)层,将添加CDN的网站内容放到多个地方,使用户访问网站时可以就近获取数据。
工作原理就是将您网站的资源放到全球各个CDN节点上,用户请求资源时就近返回。
什么是负载均衡:
网络中的负载均衡就是将网络上的流量尽可能的均匀分配到几个能完成相同任务的网络节点上(如服务器),由此来避免部分网络节点过载。
服务器中的负载均衡则是在性能不同的服务器之间进行任务分配,既能保证性能差的服务器不会拖后腿,也能保证性能高的服务器得到充分的利用。
资源预加载
<link rel=“preload” href="./static/css/font/pmzd.ttf">
用来预加载一些首屏之外也比较重要的文件,如字体文件。这些文件会在首屏渲染完成后立即被加载,就不用等到解析css文件中发现引用了字体文件时进行加载了。
手动图片预加载
var preloadImgList = [
'images/1.jpg',
'images/2.jpg',
'images/3.jpg'
];
preloadImgList.forEach(function(v) {
var img = new Image();
img.src = v;
});
页面懒加载/路由懒加载
只加载用户当前需要的和即将需要的数据。
防抖 && 节流
防止短时间内频繁触发事件:
防抖:仅执行最后一次触发的事件
function debounce(fn, delay) {
let timer = null;
return () => {
timer && clearTimeout(timer);
timer = setTimeout(fn.bind(this,arguments), delay);
}
}
节流:根据延迟时间依次执行
//计时器
function throttle(fn, delay) {
let timer = null;
return () => {
if(!timer) {
timer = setTimeout(() => {
fn.bind(this, arguments);
timer = null;
}, delay);
}
}
}
//时间戳
function throttle2(fn, delay) {
let prev = Date.now(),
timer = null;
return () => {
let next = Date.now();
if(next - prev > delay) {
timer = setTimeout(() => {
fn.bind(this, arguments);
timer = null;
}, delay);
}
}
}
cookie && localStorage && sessionStorage
客户端存储:
cookie:一个域名的小数据库,存放在用户硬盘中的一个文件;可以存储用户名等数据,以及用来页面之间数据交互。
可选参数:
- name=value 键值对数据(必选参数)
- expires=new Date().toUTCString() 有效时间,默认当前会话
- path=pvalue 限制访问cookie的目录,默认当前网页同一目录下所有页面有效
- secure=true/false true为http传输,false为https传输
官网解释:
-
以下可选的cookie属性值可以跟在键值对后,用来具体化对cookie的设定/更新,使用分号以作分隔:
-
;path=*path*
(例如 ‘/’, ‘/mydir’) 如果没有定义,默认为当前文档位置的路径。 -
;domain=*domain*
(例如 ‘example.com’, ‘subdomain.example.com’) 如果没有定义,默认为当前文档位置的路径的域名部分。与早期规范相反的是,在域名前面加 . 符将会被忽视,因为浏览器也许会拒绝设置这样的cookie。如果指定了一个域,那么子域也包含在内。 -
;max-age=*max-age-in-seconds*
(例如一年为606024*365) -
;expires=date-in-GMTString-format
如果没有定义,cookie会在对话结束时过期
- 这个值的格式参见Date.toUTCString()
-
;secure
(cookie只通过https协议传输)
-
-
cookie的值字符串可以用encodeURIComponent()来保证它不包含任何逗号、分号或空格(cookie值中禁止使用这些值).
//写入cookie:
//为了防止中文乱码,我们可以使用encodeURIComponent()编码;decodeURIComponent()解码
document.cookie = 'name=wei;age=18;user=1151042726;password:****';
localStorage:永久保存,直到手动删除
sessionStorage:当前会话中保存,会话结束后删除数据
二者api相同:
//存
window.localStorage.setItem('key', 'value');
//取
window.localStorage.getItem('key');
//删
window.localStorage.removeItem('key');
//删所有
window.localStorage.clear();
细节
释放内存:组件销毁前将事件监听器和定时器等销毁掉以释放内存。
路由懒加载
第三方插件按需引入
浏览器兼容性问题
不同浏览器标签默认的padding margin不同
解决:*{padding:0; margin:0}
设计模式
什么是设计模式
假设有一个空房间,我们要日复一日地往里面放东西。最简单的办法当然是把这些东西直接扔进去,但是时间久了,就会发现很难从这 个房子里找到自己想要的东西,要调整某几样东西的位置也不容易。所以在房间里做一些柜子也 许是个更好的选择,虽然柜子会增加我们的成 本,但它可以在维护阶段为我们带来好处。使用 这些柜子存放东西的规则,或许就是一种模式。
三大原则
单一职责:一个对象实体尽可能只做一件事
最少知识:尽量不与其他实体交互
开放封闭:增加功能应增加代码,而不是改源码
总结:少做少交加码勿改
网络
在浏览器输入url回车之后发生了什么?
https://blog.csdn.net/qq_41176306/article/details/113848108?spm=1001.2014.3001.5501
浏览器渲染页面过程:
- 请求源码
- 构建DOM树
- 构建CSS树
- DOM树 + CSS树 => 渲染树
- 绘制页面
http && https
http + ssl证书 = https
端口:http80,https443
cookie && session
cookie存在于客户端
session存在于服务器端
常见HTTP首部
通用首部
- Cache-Control: 控制缓存的行为
- Connection:逐跳首部,连接的管理
- Date:创建报文的日期时间
- Pragma:报文指令
- Trailer:报文末端的首部一览
- Transfer-Encoding:指定报文主体的传输编码方式
- Upgrade:升级为其他协议
请求首部
- Accept: 用户代理可处理的媒体类型
- Accept-Charset: 优先的字符集
- Accept-Encoding: 优先的内容编码
- Accept-Language: 优先的语言
- Authorization: web 认证信息
- From: 用户的电子邮箱地址
- Host: 请求资源所在服务器
- if-Match: 比较实体标记
- if-Modified-Since: 比较资源的更新时间
- if-None-Match: 比较实体标记(与if-Match相反)
- if-Range: 资源为更新时发送实体Byte的范围请求
- if-Unmodified-Since: 比较资源的更新时间
- Referer: 对请求中的 Url 的原始获取方法
- User-Agent: HTTP 客户端程序的信息
响应首部
- Accept-Ranges: 是否接受字节范围请求
- Age: 推算资源创建经过时间
- ETag: 资源的匹配信息
- Location: 令客户端重定向至指定的URL
- Proxy-Authenticate: 代理服务器对客户端的认证信息
- Rety-After: 对再次发起请求的时机要求
- Server: HTTP服务器的安装信息
- Vary: 代理服务器缓存的管理信息
- WWW-Authenticate: 服务器对客户端的认证信息
网络安全
浏览器安全
同源策略:协议相同、域名相同、端口相同
XSS(跨站脚本攻击)
也就是js注入,比如在评论区等地方插入js代码,提交到后台,如果没有保护措施,那么服务器就会执行恶意代码,影响极大;
或者修改url参数来向后台插入攻击代码。
防范:添加校验,转义字符
CSRF(跨站请求伪造)
拿到用户在登录状态下的cookie向服务器发起恶意请求。
比如用户A在登录状态下点击了弹出来的恶意按钮,这样入侵者就可以获取A在登录状态下的cookie,可以利用该cookie向其服务器发起恶意请求。
防范:同源策略,双重cookie验证,使用token验证。
点击劫持
视觉欺骗。
攻击者将要攻击的网页使用iframe嵌套到自己的网页中,并将iframe设置为透明,在页面中又出一个按钮诱导用户点击。
防范:添加X-FRAME-OPTIONS响应头
node
连接数据库
//引入
let mysql = require('mysql');
//初始化
let connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
port: '3306',
database: 'test'
});
//连接
connection.connect();
//语句
let sql = 'select * from beijing';
//查询
connection.query(sql, function (err, res) {
if(err) {
console.err(err.message);
}
console.log(res);
})
vue && react
二者的区别
react是函数式思想,把组件设计成纯组件,状态和逻辑通过参数传入,所以在react中是单向数据流。
vue是响应式思想,也就是基于数据是可变的,响应式更新DOM,所以在vue中是双向数据流。
react性能优化需要手动去做,操作shouldComponentUpdate或pureComponent等。
vue则自动优化性能,但可控性不如react,所以很多大型项目都会选择react。
react的思路是一切都是js,通过jsx生成html元素,通过js操作css,class等。
vue是html + css + js,分工明确,所以vue对初学者比较友好。
react可通过HOC进行组件扩展。
vue使用mixin进行组件扩展。
react本身的功能不是很全,很依靠社区,如create-react-app、redux、react-router等
vue很多东西都是内置的,写起来更加方便一些。
vue双向数据绑定实现
数据劫持 + 发布-订阅者模式
数据劫持核心是Object.defineProperty(obj, prop, descriptor)
let obj = {};
Object.defineProperty(obj, 'name', {
get: function () {
console.log('获取name值')
},
set: function (newVal) {
console.log('新值:' + newVal);
}
})
obj.name;
obj.name = 'wei';
发布-订阅者模式:
举例:公众号,很多用户关注同一个公众号,公众号有新消息了会依次推送给每一个关注他的用户
在这里vue中的数据是发布者,页面中的数据引用是订阅者,公众号系统是消息分发器。
SPA单页面应用
优点:
- 用户体验好,快,更改内容不需要加载整个页面,避免了不必要的跳转与重复渲染。
- 对服务器压力小。
- 前后端分离,架构清晰。
缺点:
- 首次加载耗时较长。
- 不能使用浏览器的前进后退,因为跳转都是本页面的路由之间的跳转。
SSR服务端渲染
在服务端将整个html页面渲染完成后直接发送给客户端。
首屏加载更快。
增加服务器负载。
2种常见的路由模式
- hash:常见,在url后面加#号进行跳转
- history:url后面没有#号,但需要服务端的配合 是H5的新特性
- 主要api有两个:history.pushState() history.replaceState() 用来操作浏览器的历史记录
Proxy && Object.defineProperty
vue3.0用proxy重写了双向绑定功能
proxy可以直接监听对象、数组
proxy拦截方法更多,不仅是get set
proxy返回一个新对象,可以直接操作新对象达到目的
proxy兼容性差,IE不支持
Object.defineProperty兼容性更好,支持IE9+
vue不能检测哪些属性变化
数组
- 使用下标更新数组元素
- 使用赋值方式改变数组长度
- 使用下标增删数组元素
官方应对方法: - Vue.set( target, key, value ) - vm.items.splice(indexOfItem, 1, newValue)
对象
- 增删属性
官方应对方法:
- Vue.set(target, propertyName, value);
- Vue.delete( target, propertyName/index )
vue.$set()
vue本身无法监听对象属性
vue.$set(obj, propertyName, value)可以为obj对象添加可监听属性。
vue Diff && react Diff
相同点:不跨级,仅同级比较
不同点:
- vue Diff会调用patch方法比较新老节点是否相同,不同则直接return,
- 进一步比较则调用patchVnode方法,进行一系列算法比较并替换
虚拟DOM优缺点
优点:
- 保证性能下限
- 无需手动操作DOM
- 跨平台
缺点:无法进行极致优化。
show && v-if
v-show控制css的display;
v-if控制元素是否存在
vue生命周期
- beforeCreate:实例初始化前
- created:实例初始化后 ajax请求
- beforeMount:实例挂载前
- mounted:实例挂载后 访问DOM
- beforeUpdate:数据更新前
- updated:数据更新后
- beforeDestroy:实例销毁前
- destroyed:实例销毁后
Vue 的父组件和子组件生命周期钩子函数执行顺序
Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:(类似于洋葱环机制)
- 加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted - 子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated - 父组件更新过程
父 beforeUpdate -> 父 updated - 销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
父组件如何监听子组件生命周期
子组件生命周期中调用this.$emit()告诉父组件
keep-alive
vue的内置组件,用来缓存被包含的组件,一般与路由或动态组件一起使用,避免重新渲染。
对应2个生命周期钩子:activated和deactivated,组件被激活和被移除触发。
组件中data为什么是一个函数
因为组件会复用,如果data是一个对象,对象的属性是引用关系,也就是说会导致多个复用该组件的地方共用一组data,一个改了data会影响其他的组件。
但data是一个函数然后返回一个对象就不一样了,这样每个组件实例都有自己独立的data对象,互不影响。
vue组件通信
(1)props / $emit
适用 父子组件通信
这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。
(2)ref
与 $parent / $children
适用 父子组件通信
ref
:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例$parent
/$children
:访问父 / 子实例
(3)EventBus ($emit / $on)
适用于 父子、隔代、兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
(4)$attrs
/$listeners
适用于 隔代组件通信
$attrs
:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过v-bind="$attrs"
传入内部组件。通常配合 inheritAttrs 选项一起使用。$listeners
:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过v-on="$listeners"
传入内部组件
(5)provide / inject
适用于 隔代组件通信
祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
(6)Vuex 适用于 父子、隔代、兄弟组件通信
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
- Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。
react性能优化
shouldComponentUpdate、pureComponent避免重复渲染
组件尽可能的拆分、解耦
列表类组件优化:唯一的key,尽量在列表底部增删元素(diff优化)
用最优的绑定this的方式:
-
constructor(props) { super(props); this.handleClick = this.handleClick.bind(this);//仅在初始化时执行一次(最优) } handleClick() { //do something } //然后 <p onclick={this.handleClick}>
-
<p onclick={this.handleClick.bind(this)}>//每次render都会执行一次
-
<p onclick={() => {this.handleClick()}}>//每次render都会生成一个新的箭头函数 //例:Test组件的click属性是个箭头函数,组件重新渲染的时候Test组件就会因为这个新生成的箭头函数而进行更新,从而产生Test组件的不必要渲染。
ReactDOMServer进行服务端渲染组件(SSR):渲染更快
少用HOC
vue性能优化
v-for设置唯一key,有利于diff算法优化,同样适用react
将路由设置为懒加载,加快首屏渲染速度
component: resolve => require([’./static/view/main’], reslove)
及时释放内存
使用keep-alive缓存组件。
HOC
是一个方法,作用是不改变一个组件代码的前提下为该组件添加功能或属性。
缺点:导致该组件的静态方法丢失,解决办法:手动拷贝组件的静态方法,或者使用hoist-non-react-statics包(推荐)
refs属性不能传递
mixin
将多个组件的公共方法提取出来放到一个对象myMixin中,然后在多个组件内部:mixins:[myMixin],即可实现将公共方法一次性放到组件中
与HOC的不同之处是改变了原组件
WebGL
webGL是一个js的API,无需插件在浏览器上渲染高性能的交互式2D和3D图形。IE11+
threejs
webGL框架
WebGL和Three.js的关系,相当于JavaScript和Jquery的关系。
基于webGL的三维引擎
创建Three.js的初衷是:利用基于Web的渲染器来创建GPU增强的3D图形和动画。这样,该框架对网络图形采用了非常广泛的方法,而无需关注任何单个动画细节。
可用于物联网3D可视化、商品720度展示、数据可视化、开发3D小游戏等。
<script src="three.js"></script>
Babylon.js
webGL框架
基于webGL的三维引擎
Babylon.js最初是作为Silverlight游戏引擎设计的,并通过碰撞检测和抗锯齿等功能保持了对基于Web的游戏开发的热情。
Babylon.js提供了对碰撞检测、场景重力、面向游戏的照相机,Three.js本身不自带,需要依靠引入插件实现。
Babylon.js具有依赖项,因此也需要包含开源Hand.js。
<script src="babylon.js"></script> <script src="hand.js"></script>
playCanvas
基于webGL游戏引擎的企业级开源js框架
cesium
用于创建3D地球和地图的js框架
electorn
使用HTML css js创建桌面应用程序的框架
serverless
无服务器计算,按需提供后端服务。
webSocket
WebSocket是一种通信协议,可在单个TCP连接上进行全双工通信。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。
首先,要明白WebSocket是一种通信协议,区别于HTTP协议,HTTP协议只能实现客户端请求,服务端响应的这种单向通信。
而WebSocket可以实现客户端与服务端的双向通讯,说白了,最大也是最明显的区别就是可以做到服务端主动将消息推送给客户端。
webSocket通信原理
- 客户端会先发送一个HTTP请求,包含一个Upgrade请求头来告诉服务端要升级为WebSocket协议
- 服务器就会返回101状态码并切换为WebSocket协议建立全双工连接,后续信息将会通过这个协议进行传输
有几个头信息需要注意一下:
Sec-WebSocket-Key:客户端随机生成的一个base64编码 Sec-WebSocket-Accept:服务端经过算法处理后回传给客户端 Connection和Upgrade字段告诉服务器,客户端发起的是WebSocket协议请求