应用层(http),表示层, 会话层,传输层(tcp, udp),网络层,数据链路层, 物理层
Content-Type
来描述请求体使用的格式Content-Type
,响应体就是返回的数据根据REST风格:
语义上或者从restful api角度上看你: get是从服务器获取资源, post是在服务器新建一个资源
实现上,或者浏览器端:
我好,大家好。
你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事
你给我发的是个啥啊,我听都听不懂
你的请求我已收到,但是我就是不给你东西
你的请求我收到了,但我没有你要的东西
你的请求我已收到,但这道题我不会,解不出来,先睡了
因为服务器上的资源不是一直固定不变的,大多数情况下它会更新,这个时候如果我们还访问本地缓存,那么对用户来说,那就相当于资源没有更新,用户看到的还是旧的资源;所以我们希望服务器上的资源更新了浏览器就请求新的资源,没有更新就使用本地的缓存,以最大程度的减少因网络请求而产生的资源浪费。
什么是Bom? Bom是浏览器对象。有哪些常用的Bom属性呢?
(1)location对象
location.href-- 返回或设置当前文档的URL
location.search – 返回URL中的查询字符串部分。例如 http://www.dreamdu.com/dreamdu.php?id=5&name=dreamdu 返回包括(?)后面的内容?id=5&name=dreamdu
location.hash – 返回URL#后面的内容,如果没有#,返回空
location.host – 返回URL中的域名部分,例如www.dreamdu.com
location.hostname – 返回URL中的主域名部分,例如dreamdu.com
location.pathname – 返回URL的域名后的部分。例如 http://www.dreamdu.com/xhtml/ 返回/xhtml/
location.port – 返回URL中的端口部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回8080
location.protocol – 返回URL中的协议部分。例如 http://www.dreamdu.com:8080/xhtml/ 返回(//)前面的内容http:
location.assign – 设置当前文档的URL
location.replace() – 设置当前文档的URL,并且在history对象的地址列表中移除这个URL location.replace(url);
location.reload() – 重载当前页面
(2)history对象
history.go() – 前进或后退指定的页面数 history.go(num);
history.back() – 后退一页
history.forward() – 前进一页
(3)Navigator对象
navigator.userAgent – 返回用户代理头的字符串表示(就是包括浏览器版本信息等的字符串)
navigator.cookieEnabled – 返回浏览器是否支持(启用)cookie
https://github.com/forthealllight/blog/issues/13
<meta id="viewport" name="viewport"
content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;">
是元数据,不会显示在页面上,但对于机器是可读的,告诉浏览器如何解析这个页面,可以添加服务器发送到浏览器的http头部内容
name 和content属性, 描述页面的内容,搜索引擎会利用name和content来找到页面
content属性:必须于name或http-equiv一起出现(key value)
http-equiv: 发送请求时,浏览器中头部包含的内容(5s后重新请求)
name:可以解决一些兼容问题,name=‘render’ content= ‘webkit’
charest: utf-8 编码
HTML5语义化标签是指正确的标签包含了正确的内容,结构良好,便于阅读,比如nav表示导航条,类似的还有article、header、footer等等标签。
(1)请求资源类型不同:
href是超文本引用的简写,用来为当前元素和文档之间建立连接,常用的是link、a标签。
src会将指向的资源下载并引用到当前文档中,常用的标签有script,img,iframe标签。
(2)作用的结果不同:
href是为当前文档和引用资源建立联系;
而src是替换当前的元素。
(3)浏览器的解析方式不同
herf引用的资源,浏览器会将其识别为CSS文档,并行下载资源并且不会停止对当前文档的处理。
当浏览器解析到src时,会暂停其他资源的下载和处理,直接将该资源下载,编译,执行完毕,图片和框架也是如此,类似于将所指资源应用到当前内容。
.triangle{
width: 0px; /*设置宽高为0,所以div的内容为空,从才能形成三角形尖角*/
height: 0px;
border-bottom: 200px solid #00a3af;
border-left: 200px solid transparent; /*transparent 表示透明*/
border-right: 200px solid transparent;
}
https://zhuanlan.zhihu.com/p/110617108
https://zhuanlan.zhihu.com/p/110617108
块元素: 独占一行,可以设置宽高外边距, div h ul li dl form table
行元素: 可以和其他行元素共占一行, span b a i
行内块元素: img input
http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
圣杯布局,content:display flex
有opacity属性的所有后代元素都会继承 opacity 属性,而RGBA后代元素不会继承不透明属性
浏览器窗口大小发生改变,重排一定导致重绘,重绘不一定导致重排,
相对定位relative:
如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
绝对定位absolute:
绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那么它的位置相对于。 absolute 定位使元素的位置与文档流无关,因此不占据空间。 absolute 定位的元素和其他元素重叠
子元素的浮动导致了父元素高度的塌陷。
导致背景不能显示,如果对父级设置了背景属性,导致父级不能撑开,会影响到背景图片不能正常打开。
边框不能撑开,由于子级使用了浮动效果,并且已经产生了浮动,父级不能撑开,所以影响边框不会随着内容的变化而变化。
this是指隐式全局上下文,
this实际上在函数被调用时发生绑定,它指向什么完全取决于函数在那里被调用,
调用函数的时候,会有一个执行上下文,记录函数在那里被调用,调用的方式,传入信息等,this就是这个记录中的属性,在函数执行的时候被用到
https://blog.csdn.net/Hunt_bo/article/details/108073473
typeof NaN = “number”
instanceof是用来判断一个对象在其原型链中是否存在一个构造函数的prototype属性
a instanceof b:判断a是否为b的实例,可以用于继承关系中
https://blog.csdn.net/magic_xiang/article/details/83686224
如果两个操作数都是对象,则比较它们是不是同一个对象。如果指向同一个对象,则相等操作符返回 true
[] == ! [] -> [] == false -> Number([])== Number(false) -> ‘’ == 0 -> 0 == 0 -> true
{} == !{} -> {} == false -> Number({}) == Number(false) -> NaN == 0
相等和不相等——先转换再比较 (==)
全等和不全等——仅比较而不转换 (===)
call(递给函数的参数必须列举出来)和apply(参数数组。)都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加
变量提升优先级:函数声明大于变量声明
let声明的变量不会被提升,而且是块级作用域,存在暂时性死区
https://blog.csdn.net/zebghfv/article/details/118251097
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖靠清除定时器操作,只是在最后一次事件后或第一次才触发一次函数。
https://blog.csdn.net/qq_37918241/article/details/99656110
js是单线程,js执行环境(全局上下文),同步就先执行同步的,遇到定时任务,事件监听,网络线程,要先存到事件队列中,promise产生的回调放入微队列,计时器等放入宏队列,当执行环境中没有任务执行,先去微队列中取出执行,然后执行后队列中的任务,知道全局上下文执行完毕
async await之后的函数相当于promise.then(),是为队列中的,之前的是立即执行函数
new Promise是立即执行函数,promise.then是为队列中的异步
console.log(1)
async function async1() {
await async2()
console.log(2)
}
async function async2() {
console.log(3)
}
async1()
setTimeout(function () {
console.log(4)
}, 0)
new Promise(resolve => {
console.log(5)
resolve()
})
.then(function () {
console.log(6)
})
.then(function () {
console.log(7)
})
console.log(8)
</script>
<!-- 1 3 5 8 2 6 7 4
宏 4
微 2 6 7 -->
https://www.cnblogs.com/soyxiaobi/p/9498357.html
函数外部对内部的引用,
ES6中的迭代器原理就用了闭包
迭代器创建函数返回了next方法,next方法返回了一个对象
外部对next方法的和对象的引用就是一个闭包.
https://www.jianshu.com/p/1c142ec2ca45
每个实例对象(object)都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
console.log( doSomeInstancing );
doSomeInstancing ._proto = doSomething.prototype
function doSomething(){}
doSomething.prototype.foo = "bar";
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value";
console.log("doSomeInstancing.prop: " + doSomeInstancing.prop);
console.log("doSomeInstancing.foo: " + doSomeInstancing.foo);
console.log("doSomething.prop: " + doSomething.prop);
console.log("doSomething.foo: " + doSomething.foo);
console.log("doSomething.prototype.prop: " + doSomething.prototype.prop);
console.log("doSomething.prototype.foo: " + doSomething.prototype.foo);
https://zhuanlan.zhihu.com/p/158640941
function create(Con,...args){
//1、创建一个空的对象
let obj = {}; // let obj = Object.create({});
//2、将空对象的原型prototype指向构造函数的原型
Object.setPrototypeOf(obj,Con.prototype); // obj.__proto__ = Con.prototype
//3、改变构造函数的上下文(this),并将剩余的参数传入
let result = Con.apply(obj,args);
//4、在构造函数有返回值的情况进行判断
return result instanceof Object?result:obj;
}
Set Map Symbol
key唯一,链式调用,用for…of遍历
唯一性, set.size, 只能for of遍历取值, set.add set.has,数组去重
对数组和Set进行结构展开运算符是调用了[Symbol.iterrator]方法
https://es6.ruanyifeng.com/#docs/object-methods
Object.is
同值相等
NaN等于本身, +0 不等于-0
Object.assign
可枚举对象的合并, 浅拷贝
Object.keys values entries
function promiseAll(promises){
return new Promise((resolve, reject) => {
if(!Array.isArray(promises)) {
return reject(new TypeError('argument must be array'))
}
const length = promises.length;
let resolveArr = [];
let num = 0;
for(let i = 0; i < length; i ++) {
(function(i) {
Promise.resolve(promises[i]).then(function(v) {
num ++;
resolveArr[i] = v;
if ( resolveArr[i] === promises ) {
return resolve(resolveArr)
}
}, function(err) {
return reject(err)
})
})(i)
}
})
}
const promises = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]
promiseAll(promises).then(v =>{
console.log('all', v)
})
interface People {
age: number,
height: number
}
interface Man{
sex: string
}
const lilei = (man: People & Man) => {
console.log(man.age)
console.log(man.height)
console.log(man.sex)
}
lilei({age: 18,height: 180,sex: 'male'});
类型断言: as
开发中有一些很长的参数,并且每个参数都是有固定类型或者规定的,就可以用接口单独封装起来.
解决带啊吗重复问题
封装成一个类或接口
共同的方法,consturctoe函数,this指向
https://www.cnblogs.com/smilexuezi/p/13870165.html
$emit
向父组件传数据,父组件通过@事件名
获取到值<router-link>
改变<touter-view>
渲染, route, this.$route.params, hash route 和 history routemutation(){increment(){}}, this.$store.commit('increment')
来改变store.state中数据, 同步函数。Actions
Action 提交的是 mutation,而不是直接变更状态。异步操作。传的参数是上下文...mapState()
Getter, ...mapGetters
在vue
中,渲染视图会调用render
函数,这种渲染不仅发生在组件创建时,同时发生在视图依赖的数据更新时。如果在渲染时,直接使用真实DOM
,由于真实DOM
的创建、更新、插入等操作会带来大量的性能损耗,从而就会极大的降低渲染效率。
在一个组件实例首次被渲染时,它先生成虚拟dom树,然后根据虚拟dom树创建真实dom,并把真实dom挂载到页面中合适的位置,此时,每个虚拟dom便会对应一个真实的dom(elm
)。最小量更新
编译的过程分两步:
AST
AST
转换为render
函数Object.defineProperty
变成带有getter和setter的响应式对象。beforeCreate
之后,created
之前。vue
提供了$set
和$delete
两个实例方法,让开发者通过这两个实例方法对已有响应式对象添加或删除属性。不要随便用set,delet,因为有对象的依赖,新增属性后还会出发渲染reder函数vue
会更改它的隐式原型,之所以这样做,是因为vue需要监听那些可能改变数组内容的方法(pop, push, reverse, sort, splice, unshift, shift
)render
函数的时候, 把函数交给watcher
对象去执行,wathcer会有一个全局变量去执行,被getter中的dep.depend()
记录依赖。setter
中的dep.notify()
派发更新,通知watcher,交给调度器,将watcher添加到nextTick
微队列中。vue对methods的处理比较简单,只需要遍历methods配置中的每个属性,将其对应的函数使用bind绑定当前组件实例后复制其引用到组件实例中即可
而vue对computed的处理会稍微复杂一些。
当组件实例触发生命周期函数
beforeCreate
后,它会做一系列事情,其中就包括对computed的处理它会遍历computed配置中的所有属性,为每一个属性创建一个Watcher对象,并传入一个函数,该函数的本质其实就是computed配置中的getter,这样一来,getter运行过程中就会收集依赖
但是和渲染函数不同,为计算属性创建的Watcher不会立即执行,因为要考虑到该计算属性是否会被渲染函数使用,如果没有使用,就不会得到执行。因此,在创建Watcher的时候,它使用了lazy配置,lazy配置可以让Watcher不会立即执行。
收到
lazy
的影响,Watcher内部会保存两个关键属性来实现缓存,一个是value
,一个是dirty
value
属性用于保存Watcher运行的结果,受lazy
的影响,该值在最开始是undefined
dirty
属性用于指示当前的value
是否已经过时了,即是否为脏值,受lazy
的影响,该值在最开始是true
Watcher创建好后,vue会使用代理模式,将计算属性挂载到组件实例中
当读取计算属性时,vue检查其对应的Watcher是否是脏值,如果是,则运行函数,计算依赖,并得到对应的值,保存在Watcher的value中,然后设置dirty为false,然后返回。
如果dirty为false,则直接返回watcher的value
巧妙的是,在依赖收集时,被依赖的数据不仅会收集到计算属性的Watcher,还会收集到组件的Watcher
当计算属性的依赖变化时,会先触发计算属性的Watcher执行,此时,它只需设置
dirty
为true即可,不做任何处理。由于依赖同时会收集到组件的Watcher,因此组件会重新渲染,而重新渲染时又读取到了计算属性,由于计算属性目前已为dirty,因此会重新运行getter进行运算
而对于计算属性的setter,则极其简单,当设置计算属性时,直接运行setter即可
Object.freeze(obj)
functional: true,
, 没有响应式,没有组件实例(this上下文)include exclude name max
activated deactivated
两个周期函数,有一个keys数组,存放组件的key,一个cache对象,key为keys,value为组件对应的vnode。
```javascript
// keep-alive 内部的声明周期函数
created () {
this.cache = Object.create(null)
this.keys = []
}
```
如果组件中的key在cache中,那么就将组件的实例指向cache中key对应的实例, 从keys中删除key,并将key插入到keys的末尾,保证最近使用的在数组最后
不在缓存对象中,那么就进行缓存,如果keys长度超过max,就删除第一个key对应的缓存
https://www.freesion.com/article/1661486992/
1. 没有Vue构造函数,使用的时createApp创建,返回Vue实例
2. this为proxy,指向的是一个代理,代理组件实例
3. compositionApi
import {ref} from 'vue'
setup(props, ctx){// 所有属性, 上下文
//在所有生命周期钩子函数之前调用
//this -> undefined
let count = ref(0); // 具有响应式
const increase = () => {
count.value ++;
};
const handleCheck = () => {
ctx.emit('update:modelValue', props.checked) //触发事件的事件名
}
return{
count,
increase //放在了组件实例中
}
}
```
template
中可以有多个根节点vue3中使用proxy完成数据相应
proxy效率比Object.defineProperty快,而且可以对属性进行删除和增加,索引访问等
hash: 在输出的时候配置名字带有 总的资源hash,用于解决缓存
mini-css-extract-plugin: 抽离css文件,1个plugin,1个loader
Loader
Plugin
mosule.exports=function(sourcecode)(retiurn '')
module.exports = {
module: {
rules: [ //使用规则
{
test: /\.js$/,//正则表达式,匹配需要loader的模块路径
use: ["./loaders/loader1?changeVar='var'"]//使用哪些loaderloader: , //loader路径(没有写在node_modules中,所以要写全路径)
},
{
test: /\.js$/,//正则表达式,匹配需要loader的模块路径
use: ["./loaders/loader1?changeVar='var','loader2'"]//使用哪些loaderloader: , //loader路径(没有写在node_modules中,所以要写全路径)
}
]
}
}
module.exports = class myPlugin {
apply(compiler){
complier.hooks.事件名称.事件类型(name, (compilation) => {})
}
}
index.js
if(module.hot){
module.hot.accept() //socket
}
watcher: true
中i后,修改打包模块,不会重新执行apply方法,而是注册事件```javascript
module.exports = {
module:{
},
devServer: {
port: 8000,
open: true,
proxy: {
'/api':{
target: 'http://localhost:8080', //请求地址包含/api那么代理请求地址为后面的地址(跨域问题)
changeOrigin: true //请求成功后却报404,是因为有些服务器需要请求头Host信息, 更改请求头中的host和origin
}
}
}
}
```
构建性能(webpack)
module.npParse: /jquery/
传输性能(webpack)
打包的js体积尽可能少,把变动少的代码合并到单独的文件中。
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
module.exports = {
optimization: {
splitChunks: {
chunks: 'all'
},
minimizer: [
// 压缩时使用得到插件
new TerserPlugin();
]
}
}
```javascript
module.exports= {
devServer: {
hot: true // 开启
},
plugin: [
new webpack.HotModuleReplacementPlugin() // 可选,webpack4之后不用写了
]
}
```
宏
https://zhuanlan.zhihu.com/p/113864878?from_voters_page=true