<!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>
</head>
<body>
<script>
/*
html5新特性:
语义化标签:
<header>
定义文档的头部区域
<footer>
定义文档的尾部区域
<nav>
定义文档的导航区域
<section>
定义文档的节
<article>
定义文章
<aside>
定义页面以外的内容(侧边栏)
<figure>
定义自包含内容,图表
<main>
定义文档内容
webwork(开启多线程)
websocket(实时通信)
音频(audio,video:音频和视频)
localStorage和seessionStorage
animation:(动画)
1.使用@keyframes关键字定义动画过渡的效果,0%代表开始,100%代表结束
@keyframes myAnimation {
0% {
transform: scale(0.8);
}
50% {
transform: scale(100%);
}
100%{
transform: scale(0.88);
}
}
2.定义动画效果animation下面的参数
名字 动画持续时间 执行速度(后续有) 开始时间 循环次数(infinite) 播放方向 控制动画播放的状态(runing代表播放,paused代表停止播放)
animation: name duration timing-function delay iteration-count direction anmation-play-state
timing-function:(ease:逐渐变慢;linear:匀速;ease-in: 加速;ease-out:减速;ease-in-out: 先加速后减速)
direction:(normal:默认值向前播放;alternate:偶数向前,奇数向后播放)
除了百分比:还可以使用from和to关键字来实现
@keyframes mayAnimation {
from {
}
to {
}
}
响应式布局:
1.百分比布局:
i:有父元素相对于父元素
ii:无父元素相对于视口
iii:或者继承于父元素
2.rem布局:
rem是指相对于根元素字体大小的单位,rem只是一个相对单位(em是一个相对单位)
1.设置完美视口
2.获取当前文档宽度
3.设置rem值 = 当前文档宽度 * 100 / (设计稿宽度)
4.设置当前文档的跟标签字体宽度 = rem值 + px
5.设置元素宽度 = 设计元素宽度/100 rem;
3.媒体查询:
@media screen and (min-widht:1200px) {
html {
font-size: 20px;
}
}
@media screen and (max-width: 1200px) {
html {
font-size: 10px;
}
}
4.vw 和 vh
vw 相对于视窗的宽度,1vw等于视口宽度的1%;即视窗宽度是100vw
vh 相对于视窗高度,1vh等于视口高度的1%;即视窗高度是100vh
1.视口宽度:为x;设计稿宽度为y
2.目的:你要书写的是设计稿元素宽度(这个代表着视口中元素宽度)
3.设置设计稿元素宽度 = (X/Y)*设计稿尺寸*vw;
CSS:
1.垂直居中:
定位方法:(父元素:position:relative;子元素:postion:absolute;top:50%;left:50%;margin-top:子元素高度一半;margin-left:-子元素宽度一半 ;)
绝对定位:(父元素: position: relative; 子元素: position: absolute; top: 0; bottom: 0;left:0;right:0; margin: auto;)
transform:(父元素:position:relative;子元素:position: absolute; transform:translate(-50%, -50%);)
flex: (父元素: justify-content: center; align-items: center; display: flex)
2.flex:
父元素:(justify-content; align-items;) (可选值: flex-start;flex-end;space-between: 空隙在中间;space-around;center;baseline:基线对齐;stretch:与父元素顶线对齐)
子元素:(align-self;flex: 可以写数字123;或者1px 2px 3px)
轴: flex-direction: (可以为row或者column;row-reverse;column-reverse)
换行方式:flex-wrap:(可以nowrap;wrap;wrap-reverse)
多行排列:align-content: (可以是flex-start;flex-end;center;space-between;space-around;stretch)
flex-basis: 设置子元素:表示在不伸缩情况下子容器原始尺寸。主轴为横向时候代表宽度,纵向时候代表高度 (可选值: 20px)
flex-grow: 设置子元素: 表示弹性伸展比列。可选值(1;2)
flex-shrink: 设置子元素:表示子元素弹性收缩的比列: (子元素1: flex-shrink:1;子元素2: flex-shrink:2;超出部分按1比2比列给子元素中减去)
order: 给子元素进行排序: (数值越小排序越靠前;默认值为0;可以为负数)
3.deep:::deep();/deep/;id属性;
3.rem:(postcss-pxtorem;和px2rem-loader;两个webpack来处理rem适配问题)
rem原理:1.设置完美视口,html文档宽度等于屏幕宽度
2.获取html文档宽度 const htmlWidth = document.documentElement.clientWidth;
3.设置rem值:(设计稿宽度为375px) const htmlFontSize(rem)= (htmlWidth * 100)/375; (获取设计稿每一个px对应的文档宽度)
4.document.documentElement.style.fontSize = htmlFontSize + 'px'; (根标签字体等于: 1rem的数值 px)
5.其他元素设置: 设计稿值/100 rem;
(理解: 完美视口下html宽度;设计稿宽度;这个两个需要形成一一对应关系;htmlFontSize这个代表的是设计稿中的1px代表的文档宽度*100;
但是我们写的元素肯定是按设计稿的宽度书写;但是又得对应上文档的宽度;
当我们书写20rem的时候,那么就是20*rem(20是设计稿宽度;rem是每一个px设计稿宽度对应的文档宽度。那么得到的结果就是设置的设计稿对应下的文档宽度)
)
4.vw
5.less
6.eslint:
7.三角形:
*/
/*
版本控制:
git:
*/
/*
JS:
浅拷贝:(Object.assign()以及下面的方法)
直接对单层对象拷贝(for in 遍历赋值)
var a1 = {
'id':'01',
'name':'aaa',
'sex': new Array('man','woman') //这里sex也是一个对象
}
var a2 = {};
for (let key in a1){
a2[key] = a1[key];
}
a2.sex[0]= '1111'; // 改变sex的第一个属性值
console.log(a1);
console.log(a2);
深拷贝:(1.创建判断数据类型函数,2.创建拷贝函数(如果是数组和对象直接新建数组和对象;如果是普通类型则直接返回;3.在拷贝函数中for in 遍历 执行新生成的对象或数组 等于 拷贝函数的调用(递归)))
var obj1 = {
name: "laowang",
age: 18,
do: function () {
console.log("study");
},
hobby: ["唱", "跳", "rap", [1, 2, 3]]
};
function checkType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
//深拷贝函数
function deepClone(obj) {
//刚进入函数需要判断 当前要拷贝的值是什么类型
if (checkType(obj) === 'object') {
//如果当前拷贝的是一个对象,则需要定一个新的对象
var newObj = {};
} else if (checkType(obj) === "array") {
//如果当前拷贝的是一个数组,则需要定一个新的数组
var newObj = [];
} else {
//如果当前拷贝的值既不是数组也不是对象,则直接返回即可
return obj;
}
//开始拷贝
// ["唱", "跳", "rap", [1, 2, 3]]
for (var key in obj) {
//在拷贝之前 需要判断当前的obj[key]是一个对象还是数组,如果是对象或数组,则需要重新拷贝 再赋值
newObj[key] = deepClone(obj[key]);
}
return newObj;
}
var obj2 = deepClone(obj1);
console.log(obj2 === obj1);
console.log(obj2.hobby === obj1.hobby)
console.log(obj2.hobby[3] === obj1.hobby[3])
JSON.Stringfy:(函数和undefined和null会丢失;object中的RegExp、Error对象序列化后得到空对象;时间对象会变为字符串)
闭包:(1.函数嵌套函数,闭包就是内部嵌套的函数;2.闭包就是包含被引用变量的closure对象,在嵌套的内部函数中)
产生闭包的情况:
函数嵌套;内部函数引用了外部函数的变量;调用了外部函数;
闭包的作用:
延长了局部变量的生命周期;可以在外部操作局部变量
闭包的生命周期:
产生: 只要内部函数被定义就产生了
死亡: 内部函数成为垃圾对象的时候 闭包结束
闭包的缺点:
函数的局部变量占用内存时间过长,容易导致内存泄露
解决:1.减少使用闭包,2.及时清理闭包
function fn1() {
debugger;
var a = 1;
var b = 2;
function fn2() {
console.log(a);
}
return fn2; //把当前函数return出去 就可以看到closure对象
}
fn1();
function fn() {
var a = 1;
function add() {
a++;
console.log(a);
}
return add;
}
var f = fn();
f(); //2
f(); //3
f(); //4
f(); //5
var f2 = fn();
f2(); //2
f2(); //3
f(); //6
//以后再也不用f了,要及时释放
f = null; //内部函数没有被引用了 变成了垃圾对象
原型链:(原型和原型链)
原型:(显示原型和隐式原型)
显示原型:每一个函数都有一个prototype属性(prototype其实是一个指针,默认指向一个空对象;prototype指向的对象被成为当前函数的显示原型,也成为原型对象;每一个原型对象都有一个constructor属性,指向其构造函数)
隐式原型: 每一个函数都有一个prototype属性,即显示原型;每一个实例对象都有一个__proto__属性,即隐式原型;对象的隐式原型指向其构造函数的显示原型;
注意:1.当函数定义的时候,就已经有显示原型了,是一个空对象 (constructor属性除外),但是只有当前函数实例化对象可以使用
2.隐式原型在创建对象的时候就自动添加了,当访问对象的属性的时候可能会沿着隐式原型查找
3.只有实例化对象才可以访问构造函数的原型对象(显示原型)
A instanceof B:(判断B是否在A的原型链上)
原型链:
1.
prototype
---------->
构造函数(Person) 构造函数原型对象(Person.prototype)
<----------
constructor
2. constructor
__proto__ __proto__ ---------> Object函数(new Object())
实例化对象(person) -------> 构造函数原型对象(Person.prototype) -------> Object原型对象(Object.prototype)
----------> null
prototype __proto__
3.对象函数Object(new Object()) --------> 对象函数原型(Object.prototype)
作用域:(作用域和执行上下文)
作用域: 一段代码所在的区域
作用域在函数声明的时候就确定了,是静态的。
执行上下文是函数执行的时候才确定的,是动态的
作用域链:(作用域链的最前端一定是当前执行环境的变量对象,末端一定都是全局变量对象)
1.函数在创建的时候就会创建一个包含全局变量对象的作用域链接(scope chain)
2.作用域链:保证对执行环境有权访问的所有变量和函数的有序访问
3.搜索标识符的过程是从作用域链的最前端向最末端逐级搜索过程,如果搜索不到可能会报错。
手写new:
节流:(一段时间只能触发一次;核心:需要计算上一次触发时间和当前时间差;当前时间减去你的上一个触发时间,如果小于你设置的一段时间值,则return,大于你设置的一段时间则执行执行函数;执行函数使用.call改变以下this指向)
//通用的节流函数(一段时间内只触发第一次)
//把真正的逻辑代码的事件函数提炼出来
function move(e) {
//直接写逻辑代码
console.log("逻辑代码");
console.log(this);
console.log(e);
}
oBox.onmousemove = throttle(move, 100);
function throttle(fn, time) {
var lastTime = 0;
return function () {
//获取当前的时间
var nowTime = Date.now();
if (nowTime - lastTime < time) {
return;
}
//在这个函数中 this是真正指向事件调用者Box的
//当间隔时间到达time的时候 才调用fn
fn.call(this, arguments[0])
//并且把当前时间变成上一次的时间
lastTime = nowTime;
}
}
防抖:(防止事件重复触发: 每次重新点击都会重新计算时间,多少秒后触发;核心:就是setTimeout 延时计时器;计时器触发前要把之前没有触发的计时器清除)
var oIpt = document.getElementById("ipt");
function getData(e) {
console.log("ajax请求")
console.log(this);
console.log(e)
}
oIpt.oninput = debounce(getData, 1300);
//通用防抖函数
function debounce(fn, time) {
var timer = null;
return function () {
//每次进入函数的时候,如果上一次的计时器没有执行,则直接给清掉,重新设置新的计时器
clearTimeout(timer);
//每次进到函数中的时候 让延迟time时间 执行函数fn
//这个位置的this才是真正的事件触发的对象
var _this = this;
console.log(this,'this是谁');
var arg = arguments[0];
timer = setTimeout(function () {
fn.call(this, arg);
}, time)
}
}
继承:(1.构造函数的实例对象指向构造函数的原型对象,当我们将子类构造函数的原型对象指向父类的实例对象的时候,我们就可以通过子类实例对象来访问父类原型对象上的方法,这就是组合继承;2.注意当我们修改构造函数的原型对象指向的时候,原型对象上的constructor属性会被自动删除,需要重新设定)
//构造函数+原型 组合继承
//父类
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.eat = function () {
console.log("eat方法")
}
//子类
function Teacher(name, age, type, classNum) {
//构造函数继承
//调用父类,并让父类的this指向当前子类的this
Person.call(this, name, age);
this.type = type;
this.classNum = classNum
}
//原型链继承
//不能直接把Person.prototype赋值给子类,这样改变子类就会影响父类
//父类的实例化对象,也能访问父类的原型对象,故把父类的实例化对象赋值给子类的原型对象
// 当手动修改构造函数的原型对象的时候,他的contructor属性会自动被删除,那么就需要重新设置他的contructor属性(修正构造器指向);
Teacher.prototype = new Person();
//修正构造器指向
Teacher.prototype.constructor = Teacher;
Teacher.prototype.do = function () {
console.log("备课")
}
var teacher1 = new Teacher("haijing", 40, "html5", 0223);
console.log(teacher1)
console.log(teacher1.eat)
console.log(teacher1.constructor)
事件轮询机制:(1.代码分类:同步代码,异步代码;2.执行顺序:先同步代码,后异步代码;3.事件模型:事件管理模块,回调队列)
1.代码分类:
同步代码:绑定事件、设置计时器,for循环等等
异步代码:事件回调函数,计时器回调函数,ajax回调函数
2.JS先执行同步代码,再执行异步代码
3.事件模型主要组成部分:1.事件管理模块,2.回调队列
4.事件轮询过程:
i:先执行同步代码,将异步代码的回调函数交给事件管理模块管理
ii:事件管理模块中的事件发生了,就会把回调函数交给回调队列(callback queue)
iii:当同步代码执行完毕后,会遍历回调队列中的函数执行。
this指向: (call,apply,bind)
什么是this:
1.一个关键字,是一个引用变量。
2.函数中可以出现this(全局的this指向window)
3.this指向其所在函数的调用者,如果没有调用者则指向window
4.this的指向是在函数调用的时候确定的
this的指向:(其实就是看函数的调用方式)
1.this 默认绑定(函数默认调用)
2.this指向调用函数上下文(函数是上下文调用的)
3.注意隐式丢失现象(通过一个上下文对象拿到了一个函数,但是没有调用,而是赋值给了他人)
4.this指向实例化对象(函数实例化调用)
5.强制绑定,this指向call,apply,bind修改的对象(函数是call,apply,bind调用)
如果判断this指向:
1.先看函数是否是被call,apply,bind调用
2.看函数是不是实例化调用
3.看函数是否是上下文对象调用(注意隐式丢失现象)
4.如果以上都不是,则直接指向window
console.log(this);
//self是window的引用
console.log(self);
console.log(window.self);
//默认绑定
function fn() {
console.log(this);
}
fn(); //window
var obj = {
name: "xiaowang",
do: function () {
fn(); //默认调用 this指向window
setTimeout(fn, 1000) //fn也是默认调用window
},
fn: fn
}
obj.do(); //
obj.fn(); //fn函数是obj调用的 所以fn的this指向obj
var f2 = obj.fn;
f2(); //window
function Person() {
console.log(this)
}
var p1 = new Person();
fn.call(p1); //fn的this指向p1
var x = 1;
var obj = {
f: function () {
console.log(this.x)
},
x: 2
}
obj.f(); //2
var f1 = obj.f;
f1(); //1
call:
在使用一个指定的this的值,和指定若干个参数的前提下,调用了某个函数
作用:1.调用函数 2.改变函数上下文(this指向)
fn.call(thisArg, arg1,arg2,arg3...);
thisArg(指定的this值)
如果fn需要参数,则依次在call的第二个函数开始传参数
执行的this值的可能性:
null,undefined:把this指向window;
基本类型:把this指向当前值的包装对象
对象类型:把this指向当前对象
function fn(a, b) {
console.log(this, a + b);
}
fn.call(undefined, 1, 2); //window
fn.call(null, 1, 2); //window
fn.call(1, 1, 2); //Number(1)
fn.call("h", 1, 2); //String("1")
fn.call(true, 1, 2); //Boolean(true)
fn.call([], 1, 2); //[]
fn.call({}, 1, 2); //{}
fn.call(new Date, 1, 2); //new Date
fn.call(Math, 1, 2); //math
fn.call(/\s/gi, 1, 2); //当前正则
fn.call(function () {}, 1, 2); //当前函数
手写call:
//所有的函数都能使用 所以myCall应该放在Function的构造函数上
//参数context是指定的this指向
Function.prototype.myCall = function (context) {
//context可能有三种类型 1.null和undefined 2.基本类型值 3.对象类型
//首先判断null和undefined类型,如果符合,context应该是window
if (context === null || context === undefined) {
context = window;
}
//再次判断context是基本类型值的时候,context应该是这个值的包装对象
if (typeof context !== 'object' && typeof context !== 'undefined' && typeof context !== "function") {
// Object方法可以把一个基本类型变成他的包装对象
context = Object(context);
}
//获取用户调用fn函数应该传递的参数,这个参数是myCall函数的第二个实参之后所有的参数,使用arguments获取
// console.log(arguments)
//截取我们需要的参数
var argArr = Array.from(arguments).slice(1);
// console.log(argArr)
//1.在这里 this 就是 调用myCall的函数fn
//2.context就是指定的this指向
//myCall的作用是 调用fn 并且把fn的this指向context 故可以书写 context.fn();
//先给context扩展一个方法 这个方法就是this
//给context扩展的方法名可能会重名,所以用一个独一无二的值
var uniqKey = Date.now().toString(36);
context[uniqKey] = this;
//调用context的这个方法
// [1,2,3]
// context[uniqKey]();
eval("context[uniqKey](" + argArr.toString() + ")")
//用完context的uniqKey的属性 要删掉 否则影响原来的对象
delete context[uniqKey];
}
var obj = {
name: "laowang"
}
function fn(a, b) {
console.log(a + b);
console.log(this);
}
fn.myCall(obj, 1, 2, 3);
fn.myCall(undefined, 1, 2); //window
fn.myCall(null, 1, 2); //window
fn.myCall(1, 1, 2); //Number(1)
fn.myCall("h", 1, 2); //String("1")
fn.myCall(true, 1, 2); //Boolean(true)
fn.myCall([], 1, 2); //[]
fn.myCall({}, 1, 2); //{}
fn.myCall(new Date, 1, 2); //new Date
fn.myCall(Math, 1, 2); //math
fn.myCall(/\s/gi, 1, 2); //当前正则
fn.myCall(function () {}, 1, 2); //当前函数
apply:
语法与call()方法的语法几乎完全相同,唯一的区别在于,apply的第二个参数必须是一个包含多个参数的数组(或者类数组对象)
function fn(a, b) {
console.log(this, a + b);
}
fn.apply(undefined, [1, 2]); //window
fn.apply(null, [1, 2]); //window
fn.apply(1, [1, 2]); //Number(1)
fn.apply("h", [1, 2]); //String("1")
fn.apply(true, [1, 2]); //Boolean(true)
fn.apply([], [1, 2]); //[]
fn.apply({}, [1, 2]); //{}
fn.apply(new Date, [1, 2]); //new Date
fn.apply(Math, [1, 2]); //math
fn.apply(/\s/gi, [1, 2]); //当前正则
fn.apply(function () {}, [1, 2]); //当前函数
var arr = [2, 3, 4];
function fn1(a, b, c) {
console.log(a + b + c)
}
console.log(arr.toString())
eval("fn1(" + arr.toString() + ")")
bind:
bind语法和call一样
但是bind并不会去调用函数,而是改变函数的this执行,并返回改变this指向后的函数
bind会返回一个函数,返回的是改变了this指向的fn
function fn(a, b) {
console.log(this, a + b);
}
var re = fn.bind([], 1, 2);
console.log(re);
console.log(re === fn) //false
re();
var obj = {
name: "laowang",
do: function () {
// console.log(this) //obj
setTimeout((function () {
console.log(this);
}).bind(this), 1000)
}
}
obj.do();
fn.bind(undefined, 1, 2)(); //window
fn.bind(null, 1, 2)(); //window
fn.bind(1, 1, 2)(); //Number(1)
fn.bind("h", 1, 2)(); //String("1")
fn.bind(true, 1, 2)(); //Boolean(true)
fn.bind([], 1, 2)(); //[]
fn.bind({}, 1, 2)(); //{}
fn.bind(new Date, 1, 2)(); //new Date
fn.bind(Math, 1, 2)(); //math
fn.bind(/\s/gi, 1, 2)(); //当前正则
fn.bind(function () {}, 1, 2)(); //当前函数
冒泡和捕获:(冒泡:从父子元素中目标元素向外触发事件到最外层元素(document);捕获:从父子元素最外层(document)向内触发到目标元素)
1.冒泡和捕获只能使用DOM2绑定事件,(addEventListener('事件名称',()=>{}, true))
2.第三个参数true为事件捕获,默认false为事件冒泡
cookie和sessionStorage和localStorage:
1.生命周期:
cookie:可设置失效时间,没有设置的话,默认是关闭浏览器后
localStorage: 永久保存,除非手动清除。
sessionStorage: 仅仅在当前网页绘话下,关闭浏览器或浏览器后被清除。
2.存储数据大小:
cookie:4kb左右
localStorage和sessionStorage:可以保存5Mb
3.http请求:
cookie:每次都会携带在http请求头中,如果使用cookie保存过多的数据会带来性能问题
localStorage和seessionStorage:仅仅在客户端保存,不参与服务器通信。
4.易用性:
cookie:需要自己封装,原生的cookie接口不友好
localStorage和sessionStorage:原生接口可以接受,可以再次封装对Object和Array更好支持。
indexDB(数据库)
js前端缓存:(web缓存:浏览器缓存和http缓存(核心:强制缓存和协商缓存))
1.注意,我们的缓存主要是针对html,css,img等静态资源,常规情况下,我们不会去缓存一些动态资源,因为缓存动态资源的话,数据的实时性就不会不太好,所以我们一般都只会去缓存一些不太容易被改变的静态资源
2.减少不必要的网络传输,节约宽带(就是省钱)
更快的加载页面(就是加速)
减少服务器负载,避免服务器过载的情况出现。(就是减载)
3.强制缓存:(如果浏览器判断请求的目标资源有效命中强缓存,则可以直接从内存中读取目标资源,无需与服务器做任何通讯)
i:通常使用响应头中Expires字段(设置一个强缓存时间)去实现强缓存。(Expires已经废弃,而使用cache-control)
ii:cache-control:的六个属性
max-age决定客户端资源被缓存多久。
s-maxage决定代理服务器缓存的时长。
no-cache表示是强制进行协商缓存。
no-store是表示禁止任何缓存策略。
public表示资源即可以被浏览器缓存也可以被代理服务器缓存。
private表示资源只能被浏览器缓存。
4.协商缓存:
1.首先需要在服务器读取文件修改的时间
2.将读取出来的修改时间赋值给响应头的last-modified字段。
3.最后设置Cache-control:no-cache
当客户端读取到last-modified的时候,会在下次的请求标头中携带一个字段:If-Modified-Since
那么之后每次对该资源的请求,都会带上If-Modified-Since这个字段,而务端就需要拿到这个时间并再次读取该资源的修改时间,让他们两个做一个比对来决定是读取缓存还是返回新的资源。
1.读取返回给客户端的修改文件时间
2.读取第一次返回给客户端的修改时间
3.两个时间相同,没改过;
4.设置最后修改时间字段last-modified字段。
http请求到页面显示发生了什么?(http协议,https协议)
1.当用户通过客户端输入url地址,首先要通过dns解析把域名解析为ip,通过ip才能找到对应的服务器
2.dns解析是从浏览器中找url对应的ip,如果浏览器没有缓存,那么就会到dns服务器上寻找域名对应的ip
//会先对//static.360buyimg.com这个域名解析dns解析,解析结果保存到浏览器缓存中
<link rel="dns-prefetch" href="//static.360buyimg.com" >
3.网络协议ip协议几乎是最底层协议,ip协议的基础上有tcp协议,通过dns找到ip后,才可以发送tcp协议,tcp协议是确保网络链接的协议
4.TCP协议的三次握手和四次挥手
三次握手:
i:客户端通过ip找到服务器
ii:服务器回复客户端
iii:客户端携带数据再次访问服务器
四次挥手:
i:客户端向服务器发送请求告诉服务器我要断开了
ii:服务器接收到信息后,回复我知道了
iii:等服务器处理完数据后,告诉客户端
iiii:客户端收到服务端发送过来的请求消息后,向服务器表示ok,断开
5.http链接服务器并返回响应(可能是html文件)
6.解析dom
1.将html解析为dom树
2.将css解析成css树
3.将dom树和css树形成渲染树,开始渲染页面
5.js执行(js执行可以是异步的,js会阻塞浏览器解析;js执行可以修改dom树结构,可以修改css规则)
6.调用系统api进行绘制,页面就出来了。
跨域: jsonp;cores(允许所有请求跨域);proxy代理()
1.同源策略:(浏览器的安全机制:协议(http://);域名:www.baidu.com;端口号:8080;)三个都相同代表同一个ip
2.允许跨域的三个标签(script;link;img)
3.跨域解决方案:
jsonp没有跨域限制
cors后端解决跨域问题(Access-Control-Allow-Origin)可以设置所有跨域请求
proxy代理:
module.exports = {
devServer: {
port: 8000,
proxy: {
"/api": {
target: "http://localhost:8080"
}
}
}
};
es6:(箭头函数;promise;map;set;数组方法,...运算符;字符串方法;解构赋值;class(自定义事件机制))
1.箭头函数:
i:只能用赋值式写法,不能用声明式写法
ii:参数只有一个可以不加括号
iii:函数体只有一句话,可以不加花括号
iiii:可以不写return
iiiii:箭头函数没有this,他的this只想他的外层函数,如果没有指向window(window.setTimeout,window.setInterval的this都指向window)
2.箭头函数和普通函数的区别:
i:外形区别:箭头函数使用箭头定义,普通函数没有箭头
ii:箭头函数都是匿名函数,普通函数可以具名函数也可以匿名函数
匿名: let func = () =>{}
具名: function fn() {}
iii:箭头函数不能用于构造函数,不能new调用(构造函数可以通过new调用创建实例化对象)
iiii:箭头函数this指向他的外层普通函数或者window,普通函数this指向调用者
iiiii:箭头函数不可以绑定arguments,取而代之的是rest(...运算符)解决
iiiiii:箭头函数没有prototype原型对象。
2.数据类型(map,set)
set:
i:无序,没有重复的类似数组
ii:Set是一个构造函数,来生成set数据结构
iii:for of 可以用来遍历Set类数组
iiii: [...new Set(array)] 浅拷贝数组
操作方法:
操作方法:
add(value):向集合添加一个新的项
delete(value):从集合中移除一个值
has(value):如果值在集合中存在,返回true,否则false
clear(): 移除集合里所有的项
遍历方法:
keys():返回一个包含集合中所有键的数组
values():返回一个包含集合中所有值的数组
entries:返回一个包含集合中所有键值对的数组(感觉没什么用就不实现了)
forEach():用于对集合成员执行某种操作,没有返回值
map:
属性:
size:返回字典所包含的元素个数
操作方法:
set(key, val): 向字典中添加新元素
get(key):通过键值查找特定的数值并返回
has(key):如果键存在字典中返回true,否则false
delete(key): 通过键值从字典中移除对应的数据
clear():将这个字典中的所有元素删除
遍历方法:
keys():将字典中包含的所有键名以数组形式返回
values():将字典中包含的所有数值以数组形式返回
forEach():遍历字典的所有成员
ES6(字符串方法)
1.charAt:返回在指定位置的字符
var str = "HELLO WORLD";
var n = str.charAt(2) //L
2.concat:连接两个或者更多字符串,并返回新的字符串
var str1 = "Hello ";
var str2 = "world!";
var n = str1.concat(str2); // Hello world!
3.endsWith:判断当前字符串是否以指定的字符串结尾(区分大小写)
let str = "Hello world";
str.endsWith("world") // 返回 true
str.endsWith("World") // 返回 false
4.indexOf:返回某个指定的字符串值在字符串中首次出现的位置。
var str="Hello world, welcome to the universe.";
var n=str.indexOf("welcome"); // 13
5.includes:查找字符串中是否包含指定的子字符串
var str = "Hello world, welcome to the Runoob。";
var n = str.includes("Runoob"); //true
6.lastIndexOf:从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置(没有找到返回-1)
var str="I am from runoob,welcome to runoob site.";
var n=str.lastIndexOf("runoob",20);//28 20代表从第20个字符开始找最后出现的位置
7.查找到一个或多个正则表达式匹配。
var str="The rain in SPAIN stays mainly in the plain";
var n=str.match(/ain/g); // [ain,ain,ain]
8.复制字符串指定次数,并将他们连接在一起返回
var str = "Runoob";
str.repeat(2);// RunoobRunoob
9.replace:在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。
var str="Visit Microsoft! Visit Microsoft!";
var n=str.replace("Microsoft","Runoob"); // Visit Runoob!Visit Microsoft!
10.replaceAll:在字符串中查找匹配的子串,并替换与正则表达式匹配的所有子串
var str="Visit Microsoft! Visit Microsoft!";
var n=str.replaceAll("Microsoft","Runoob");// Visit Runoob!Visit Runoob!
11.search:查找与正则表达式相匹配的值
var str="Visit Runoob!";
var n=str.search("Runoob");// 6
12.slice:提取字符串片段,并在新的字符串中返回被提取的部分
var str="Hello world!";
var n=str.slice(1,5);// ello
13.split:把字符串分割为字符数组
var str="How are you doing today?";
var n=str.split(" ");// How,are,you,doing,today?
14.startsWith:查看字串是否以指定的子字符串开头
var str = "Hello world, welcome to the Runoob.";
var n = str.startsWith("Hello");// true
15.substr:从起始索引号提取字符串中指定数据的字符
var str="Hello world!";
var n=str.substr(2,3)// llo
16.提取字符串中两个指定索引号之间的字符
var str="Hello world!";
document.write(str.substring(3)+"<br>");
document.write(str.substring(3,7)); // lo world!
// lo w
17.toLowerCase:把字符串转换为小写
var str="Runoob";
document.write(str.toLowerCase());
18.toUpperCase:把字符串转换为大写
var str="Runoob";
document.write(str.toUpperCase());
19.trim:去除字符串两边的空白
var str = " Runoob ";
alert(str.trim());
20.valueOf:返回某个字符串对象的原始值
var str="Hello world!";
document.write(str.valueOf());// Hello world!
21.toString:返回一个字符串
var str = "Runoob";
var res = str.toString(); // Runoob
const object = {name: '小王', age: 23};
object.valueOf();// {name: '小王', age: 23}
object.toString();// [Object,Object]
AMD和CMD和ES6模块化:
AMD:代表的就是require.js(依赖前置,引入模块就声明了模块,会提前加载模块)
CMD:代表的是module.exports(依赖就近:只有模块用到的时候才加载模块,使用require()引入模块);
ES6:模块化代表的import export(默认暴露,分别暴露,统一暴露)
微任务和宏任务:
宏任务:setTimeout;setInterval;PostMessage;setImmediate;
微任务:Promise.then;Object.obsersve;mutationObserver;process.nextTick();
状态码:(30开头一般式请求重定向,需要重新请求地址,400一般客户端错误,500一般服务器错误);
200: '请求被正确处理并返回了结果',
201: '新增或修改数据成功',
202: '请求已进入任务队列,被异步处理',
203: '令牌或登录状态失效',
204: '删除数据成功',
301: '请求的资源被永久重定向到新的位置,将从新的地址重新请求',
302: '请求的资源被临时重定向到新的位置',
400: '请求参数错误,服务器没有对数据做新建或修改',
401: '无访问权限,用户名、密码、令牌错误',
403: '得到访问授权,但访问是被禁止',
404: '访问的是不存在的资源',
405: '请求方式不正确',
406: '请求的数据格式不是服务接收的类型',
410: '请求的资源被永久删除',
422: '服务器创建对象时发生错误',
500: '服务器不可用,未返回正确的数据',
502: '服务器网关错误',
503: '服务器过载或维护中',
504: '服务器响应超时',
*/
/*
webpack(入口,输出,loader,plugins,mode)
webpack优化:
js压缩:plugin:terser-webpackplugin
css压缩: css-minimizer-webpack-plugin
html压缩 HtmlWebpackPlugin
文件压缩: compression-webpack-plugin
图片压缩: image-webpack-loader
Tree shaking: 树摇
代码分离:
内联chunk:
webpack: (hot)
*/
/*
vue2:
1.数据双向绑定:(视图层,model层,数据模型层)
mvvm:
实现mvvm主要是两方面(目的是:data更新view,view更新data;mvvm中是有一个中间层viewmodel,view不会直接跟data层交互,而是通过viewmodel更新数据和更新view层)
vue数据双向绑定是通过(数据劫持结合发布订阅模式)来实现的。
vue的数据劫持对于普通对象的(深层对象是通过递归调用来实现的,数组是改写了数组的方法:push,pop,shift,unshift,splice,sort,reverse)
1.我们需要一个监听器(Observer)用来监听所有属性,当属性发生变化就需要告诉订阅者watcher看是否需要更新。
2.订阅者有很多个,需要一个消息订阅器dep(来统一收集这些订阅者,然后在observer和watcher之间统一管理)
3.我们需要一个解析器(compile)对每个节点元素进行扫描和解析,初始化视图;将相关指令对应初始化一个订阅者watcher,并且替换模板数据或者绑定相应函数,当订阅者watcher接收到相应属性变化,就会执行对应的更新函数,从而更新视图。
2.v-model:(input value)
input标签是绑定@input事件和value值
当value值发生改变时候,会将值给到input,在input事件中设置$event.target.value = 值;执行后就会更新dom的value值(视图层更新数据层和数据层更新视图层)
3.v-if和v-show
v-if主要是对dom元素进行了移出;v-show是设置了display:none;
频繁操作时候使用v-show;偶尔操作使用v-if
4.生命周期:
vue2声明周期:
1.beforeCreate
2.Created
3.beforeMount
4.mounted
5.beforeUpdate
6.updated
7.beforeDestroyed
8.destroyed
9.activated
10.deactivated
11.errrorcapture
5.路由守卫:(beforeRouteEnter)
1.全局守卫:
beforeEach(to from next)
beforeResolve(to from next)
afterEach(to from)
2.独享守卫:
beforeEnter(to, from, next)
3.路由组件内守卫:
beforeRouteEnter(to, from, next) {
不可以访问this
}
beforeRouteUpdate(to, from, next) {
可以访问this
}
beforeRouteLeave(to, from, next){
可以访问this
};
6.computed和watch和methods
computed:用来计算属性,它会根据你所依赖的数据动态显示新的计算结果,计算结果会被缓存,只有依赖值改变时候,才会重新计算。
watch:是当某个数据变化时候,使用watch来观察变化后进行数据操作,没有缓存。
methods是一个对象属性函数,对发生的在dom中的事件进行反应,可以在computed或者watch中调用他们。
7.mounted和created发送请求的时机
1.created中不可以访问dom元素,mounted中可以访问dom元素
2.created发送ajax请求比mounted中快
3.mounted中访问dom元素可以可使用this.$refs获取dom元素,但是子组件不一定会挂载,可以使用$nextTick()中获取。
8.父子组件内部beforeMount和mounted
父beforeMount
子beforeMount
子mounted
父mounted
9.data中属性为啥是函数不是对象。
data中是函数利用工厂模式,不同的vue组件实例都有一个特定的data函数管理数据不会互相影响,而如果是对象,会导致数据属性发生污染。
10.单页面和多页面区别:
单页面 多页面
1.组成:一个页面和多个页面片段组成 多个完整页面组成
2.资源公用(css.js) 公用,只需要外壳部分加载 不共用,每个页面都需要加载
3.刷新方式:页面局部刷新或更改 整页面刷新
4.url模式 hash模式 history模式
5.页面片段切换快,用户体验好 页面切换加载慢,流畅度不够,用户体验差
6.数据传递容易 依赖url传递参数,cookie,localStorage
7.搜索引擎优化(SEO)不利于seo 容易实现
8.开发成本较高,需要借助专业框架 较低,但是页面重复代码较多
9.维护容易 相对复杂
11.vue通信方式:(props,自定义事件,全局事件总线,ref,$parent和$root和,attrs与listener,provide和inject,vuex)
12.vuex:(state,getter,mutations,actions)
1.actions主要是用于响应组件中的动作,通过commit()来触发mutation中函数调用,间接更新state,不是必须存在的
2.mutation主要用于操作修改数据,是必须存在的
3.actions可以异步操作,可以向后台提交数据或者接受后台数据。
4.mutation是同步操作,不能写异步代码,只能单纯操作state,用于将数据信息写在全局数据状态中缓存,不能异步操作。
13.mixins:(数据状态不清楚)
14.slot(插槽:默认插槽;具名插槽;作用域插槽)
15.keep-alive(activated;deactivated);
16.nextTick(原理;下一次dom更新会执行;重点);
17.路由模式(history和hash)
18.MVVM和MVCM
19.Object.defineProperty
20.vue template 到render过程发生了什么。(vue模板编译)
21.vue初始化页面闪动问题:
22.vue2data属性新增和删除失去响应式,处理办法
23.vue虚拟dom
*/
/*
vue性能优化:
1.v-if和v-show
2.computed和watch使用
3.v-for必须添加key
4.长列表性能优化,只是展示的数据使用Object.freeze()对数据进行冻结失去响应式
5.事件销毁
6.图片懒加载
7.路由懒加载
8.第三方插件按需引入
9.优化列表展示(虚拟列表)
10.服务端渲染(更好的SEO和首屏加载更快)
11.webpack对图片压缩
12.优化sourceMap
13.提取组件css到单独的文件
14.开启压缩
15.浏览器缓存
16.图片的手动压缩
*/
/*
TS:
*/
/*
vue3:
0.setup(在beforeCreate之前执行,接收两个参数(props:组件传入的属性;context:))
const user = reactive({ name: 'sz', age: '123'});
export default defineCompent({
setup(props, context) {
const { name } = props; // 不可以直接使用ES6解构,这样会使得数据失去响应式,可以使用toRefs
console.log(name);
//context中提供了this中最常用的三个属性:
// attrs,slot,emit;分别对应vue2中$attr slot插槽和$emit发射事件
...toRefs(user);
}
});
1.ref(用来基本数据类型的响应式数据设置,数据处理时候.value进行使用) ref(1)
2.reactive(处理引用对象,对象和数组;无需使用.value处理数据) reactive({ name: 'zs', age: 18})
3.toRefs
4.watch(监听特定数据,并在回调函数中执行,默认是惰性的,只有数据变更才执行回调)
watch(source,callback,[option])
source:支持string,object,funtion,array
callBack:执行回调函数
option:支持deep、immediate、和flush选项
// 监听reactive数据,修改age值时会触发 watch的回调
const state = reactive({ name: 'sz', age: '11'});
watch(
() => state.age,
(curAge, preAge) => {
console.log("新值:", curAge, "老值:", preAge);
}
);
// 监听ref数据
const year = ref(0);
watch(year, (newVal, oldVal) => {
console.log("新值:", newVal, "老值:", oldVal);
});
//监听多个数据(合并监听多个数据源)
watch([() => state.age, year], ([curAge, newVal], [preAge, oldVal]) => {
console.log("新值:", curAge, "老值:", preAge); console.log("新值:", newVal,
"老值:", oldVal); });
// 监听复杂对象数据
const state = reactive({
room: {
id: 100,
attrs: {
size: "140平方米",
type: "三室两厅",
},
},
});
watch(
() => state.room,
(newType, oldType) => {
console.log("新值:", newType, "老值:", oldType);
},
{ deep: true }
);
如果不使用第三个参数deep:true, 是无法监听到数据变化的。 前面我们提到,默认情况下,watch 是惰性的, 那什么情况下不是惰性的, 可以立即执行回调函数、 给第三个参数中设置immediate: true即可。
//停止监听:(某个时间停止监听)
const stopWatchRoom = watch(() => state.room, (newType, oldType) => {
console.log("新值:", newType, "老值:", oldType);
}, {deep:true});
setTimeout(()=>{
// 停止监听
stopWatchRoom()
}, 3000)
5.watchEffect(无需传入依赖,自动收集依赖)
watchEffect(() => {
console.log(state);
console.log(year);
}
);
1.watchEffect 不需要手动传入依赖
2.watchEffect 会先执行一次用来自动收集依赖
3.watchEffect 无法获取到变化前的值, 只能获取变化后的值
6.computed
7.生命周期钩子函数
0.setup
1.beforeCreate
2.created
3.onBeforeMount
4.onMounted
5.onBeforeUpdate
6.onUpdated
7.onBeforeUnmount
8.onUnmounted
9.onActivated
10onDeactivated
11.onErrorCaptured
// 用于调试的钩子函数
12.onRenderTriggered
13.onRenderTracked
8.vue3自定义hook(hook就是一个组合式封装的函数,代码复用)
// hook函数文件
import { ref, Ref, computed } from "vue";
type CountResultProps = {
count: Ref<number>;
multiple: Ref<number>;
increase: (delta?: number) => void;
decrease: (delta?: number) => void;
};
export default function useCount(initValue = 1): CountResultProps {
const count = ref(initValue);
const increase = (delta?: number): void => {
if (typeof delta !== "undefined") {
count.value += delta;
} else {
count.value += 1;
}
};
const multiple = computed(() => count.value * 2);
const decrease = (delta?: number): void => {
if (typeof delta !== "undefined") {
count.value -= delta;
} else {
count.value -= 1;
}
};
return {
count,
multiple,
increase,
decrease,
};
}
// hook函数引入组件使用
<template>
<p>count: {{ count }}</p>
<p>倍数: {{ multiple }}</p>
<div>
<button @click="increase()">加1</button>
<button @click="decrease()">减一</button>
</div>
</template>
<script lang="ts">
import useCount from "../hooks/useCount";
setup() {
const { count, multiple, increase, decrease } = useCount(10);
return {
count,
multiple,
increase,
decrease,
};
},
9.vue2和vue3响应式对比:
/*
npm是如何做版本管理的:
遵循semver规范(1.9.1)(主版本号:做了不兼容的api修改;次版本号:向下兼容新增;修订号:向下兼容修正)
*/
/*react:
useMemo和useCallback的区别?(两个最好配套使用)
1.useCMemo缓存的结果是回调函数的返回值
2.useCallback缓存的结果是函数。
*/
/*CSS3(css盒子模型)
*/
/*事件模型(如果在过程中出发一个click事件会怎样)*/
/*map和weakmap和Object
1.map和object区别:
1.map默认没有任何键,object有一个原型上的键名可能和自己设置的冲突
2.map键可以是任意值,包括函数,对象或者任意基本类型,object必须是string或者symbol
3.map的key是有序的,迭代的时候map可以插入顺序返回键值,object键是无顺序的
4.map键值对数量可以轻易通过size获取,object键值手动计算
5.map是有iterate接口的,可以直接被迭代,objet需要获取键值再迭代
6.map删减键值性能好
2.map和weakmap的区别:
1.map集合键值键可以是任意值,包括函数,对象或者任意基本类型,而weakmap键必须是对象(null除外)
2.map有size属性set方法get方法,has方法,weakmap不支持forEach方法和size属性和clear方法
3.weakmap中键值对象是弱引用,垃圾回收机制不会考虑回收,因此不需要手动删除引用
*/
/*CSS不常用属性(css3)
1.transform变形
2.animation(动画)
3.transition(过渡)
*/
/*js组合继承*/
/*new关键字做了什么?(案例查看随笔文件)
1.创建了一个空对象,并且将空对象的__proto__指向构造函数的原型
2.执行构造函数,并将this指向新创建的对象。
3.返回新对象
*/
/*
爬楼梯问题
*/
/*
vue指令相关
*/
/*自定义导航栏(a到b b是新的标签页,b打开了好多页面,如何返回a)
*/
/*
自定义一个联动下拉框
*/
/*
不知道多少个子集,并且异步请求,如何定义props和逻辑*/
/*
axios请求原理,如何封装
*/
/*埋点*/
/*
浏览器循环机制,强制缓存,协商缓存,浏览器缓存。
浏览器缓存机制:
1.浏览器页面加载时候查看是否有缓存,有则不向服务器发送请求,没有则则向服务器发送请求
2.有缓存则会判断缓存标识是否过期,没有过期则使用强制缓存,返回缓存结果
3.如果缓存标识过期,则携带标识码向服务器发送请求,如果资源无更新则返回304,协商缓存生效继续使用缓存结果
4.反之资源更新了则返回200并将结果存入到浏览器中。
*/
/*
vue自己封装axios需要实现哪些功能
*/
/*git的缓存功能*/
/*diff算法*/
/*promise和async和await*/
/*rem和em区别
rem是相对于根元素进行计算,而em是相对于当前元素或父元素的字体大小
*/
/*webpack中loader和plugin的区别
plugin主要用来处理loader不能处理的问题,(loader主要用来打包文件,而plugin可以实现单独抽离css,热更新,可以开启多进程加快代码构建)
*/
/*rem适配,js数据类型,本地数据存储,小程序的一些方法*/
</script>
</body>
</html>