从输入url到页面加载完成中间发生了什么
1.浏览器的地址栏输入URL并按下回车。
2 .在我们的电脑上先把通过DNS服务器域名解析成IP地址
3我们的电脑要和服务器建立一个TCP的网络连接
-
1、第一次握手:客户端给服务器发送一个 SYN 报文。
-
2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。
-
3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。
-
服务器收到 ACK 报文之后,三次握手建立完成,作用是为了确认双方的接收与发送能力是否正常。
4 我们的浏览器往ip地址为解析后的服务器上发送http请求
4服务器收到http请求,服务器处理http请求
5服务器处理http请求后,开始回复我们的浏览器
6 我们的电脑和服务器之间断开TCP链接(四次挥手)
-
客户端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中的FIN字段置为1,表示需要断开TCP连接。(FIN=1,seq=x,x由客户端随机生成);(客户端发送断开TCP请求的包)
-
服务端会回复客户端发送的TCP断开请求报文,其包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP断开请求已经得到验证。(FIN=1,ACK=x+1,seq=y,y由服务端随机生成);(服务端收到断开请求的包后,表示同意断开)
-
服务端在回复完客户端的TCP断开请求后,不会马上进行TCP连接的断开,服务端会先确保断开前,所有传输到A的数据是否已经传输完毕,一旦确认传输数据完毕,就会将回复报文的FIN字段置1,并且产生随机seq序列号。(FIN=1,ACK=x+1,seq=z,z由服务端随机生成);(服务器发送断开TCP连接的请求,准备断开)
-
客户端收到服务端的TCP断开请求后,会回复服务端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在服务端的TCP断开请求的seq基础上加1,从而完成服务端请求的验证回复。(FIN=1,ACK=z+1,seq=h,h为客户端随机生成)(浏览器收到断开的请求断开了)
6 浏览器收到http回复后,开始解析html+css在浏览器上绘制形成我们看到的网页了
-
浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
-
将CSS解析成 CSS Rule Tree 。
-
根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
-
有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系。下一步操作称之为layout,顾名思义就是计算出每个节点在屏幕中的位置。
-
再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。
http协议
超文本传输协议
协议:双方或者多方共同遵守的约定
http协议:浏览器和web服务器之间建立的约定
http请求:请求头,请求行,请求体
请求资源:url
请求方式:get,post ,put ,delete,options
请求携带的数据:
header,url地址后面,请求体
get和post请求的区别
get请求数据放到url地址后面(不安全,携带的数据量小),post请求放在请求体,安全(携带的数据量大)
http回复 响应的状态码+响应的文本(回复的内容)
http响应状态码,标识http有没有成功
100:请求未完成
200:请求成功
302:重定向(服务端解析请求后跳转到别的资源)
304:浏览中有缓存了(有利于提高网站的速度)
403:没有权限访问的资源
404:未找到服务器的资源
500:服务器出错了
特点:无状态,不会保持长连接,浏览器主动请求,服务才能回复
计算机的网络的架构
应用层(应用)
传输层(端口)
网络层 (ip地址)
数据链路层 (mac地址)
物理层
ES6入门文档-ES6官方文档,ES6新特性,ES6标准入门文档,ES6教程
ES6的简介
简介
ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了
为什么要学习ES6
ES6版本变动内容最多,具有里程碑的意义
ES6加入了许多语法的特性,变成更加简单
ES6前端发展趋势,就业必备技能
ES6的兼容性的问题
ECMAScript 6 compatibility table
可以使用babel将ES6的语法编译成ES5让低版本的浏览器也能使用我们写的代码
let和const的命令
作用域
变量的作用范围,
全局作用域
函数作用域
块级作用域
作用域链
变量使用时,首先到变量所在的作用域中找变量,如果找不到往上一级上找,依次往上找如果全局作用域没有该变量报错
let命令
功能:声明变量用的
let a; let a,b,c let e=1 console.log(a,b,c,e)
说明:
-
在同一个作用域下声明变量不能重复
-
块级作用域,(ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域)
-
作用域死区,不存在有变量提升
-
不影响作用域链
const命令
功能:声明常量用的,常量一旦定义后就不能修改
const name="zhangsan"
说明:
-
声明时一定要赋初始值
-
对于常量中放置基本数据类型声明常量后不能修改常量,对于数组和对象,不能修改常量地址,可以修改常量某个属性或数组的某个值
-
块级作用域
结构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
数组的结构赋值
按照对应位置,对变量赋值
let person=["张三",18,"男"] let [name,age,sex]=person console.log(name,age,sex)
let person=["张三",18,"男",[180,150]] let [name,age,sex,[height,weight]]=person console.log(name,age,sex)
let person=["张三",18,"男",[180]] let [name,,sex,[,weight=170]]=person console.log(name,age,sex)
说明:
-
可以浅层次的结构,也按照结构深层进行结构
-
如果一个值不想结构可以不写
-
如果解构不成功,如果有默认值,就等于默认值,如果没有默认值变量的值就等于
undefined
。
对象中的结构
按照对象中属性,对变量赋值
let person={ name:"zhangsan", age:18, info:{ weight:180, height:240 } say:function(){ } } let {name:xingming,info:{weight},say,sex:s="男"}=person //name解析后成xingming变量了 //info 打印不出来,info作为模式了,如果同时想要info的话 let {name:xingming,info:{weight},say}=person //weight能打印出来 //say能结构出来, //s能结构出来
-
可以浅层次的结构,也按照结构深层进行结构
-
如果一个值不想结构可以不写
-
如果解构不成功,如果有默认值,就等于默认值,如果没有默认值变量的值就等于
undefined
。
字符串的扩展
模板字符串
let name="zhangsan" let person=`我的名字 是${name}`
-
使用模板字符串可以直接换行
-
可以直接变量拼接
扩展的字符的方法
实例方法:includes(), startsWith(), endsWith() 实例方法:repeat() 实例方法:padStart(),padEnd() 实例方法:trimStart(),trimEnd()
对象的简化写法
let name="zhangsan" let age=1 let person={ name:name, age:age, say:function(){ } } //下面的和上面的等效 let person={ name, age, say(){ } }
-
简化定义属性
-
简化定义方法
剩余函数rest
有点像扩展运算符的逆运算,一般在结构赋值中使用
let [a,...b]=[1,2,3,4,5] console.log(a) //1 console.log(b) //[2,3,4,5]
let {name,...person}={ name:"zhangsan", age:18, sex:1 } console.log(name) //zhangsan console.log(person) //{age:18,sex:1}
function say(...arr){ console.log(arr) } say(1,2,3,4)
ES6的扩展运算符
数组的扩展运算符
扩展运算符(spread)是三个点(...
),将一个数组转为用逗号分隔的参数序列(不是字符串)。那个地方使用到了这种序列,我们就使用就行
let arr=[1,2,3] console.log(...arr) //本来console.log函数中的参数应该是console.log(1,2,3) 而数组的扩展运算符刚好展开后和console.log中的格式一样,我们就可以使用扩展运算符了
let arr=[3,4,5] let arr1=[1,2,3,4,5]//我们可以定义一个新的数组我们还可以这样定义 let arr1=[1,2,...arr]
function say(a,b){ return a+b } let arr=[1,2] say(...arr)
我的理解就是...把数组的[]剥掉了,剥掉后是什么类型(不重要,不是js中的任何一种类型,或者就理解成一种格式就好),那个地方需要用到这种格式,我们就在那个地方用就行
对象的扩展运算符
let user={ name:"zhangsan" } let userinfo={ age:18 } let person={ name:"zhangsan", age:18 } 或者 let person={...user,...userinfo}
数组的扩展
Array.from() Array.of() 实例方法:copyWithin() 实例方法:find(),findIndex(),findLast(),findLastIndex() 实例方法:fill() 实例方法:entries(),keys() 和 values() 实例方法:includes() 实例方法:flat(),flatMap() 实例方法:at() 实例方法:toReversed(),toSorted(),toSpliced(),with() 实例方法:group(),groupToMap() 数组的空位 Array.prototype.sort() 的排序稳定性
对象的扩展
let propKey = 'foo'; let obj = { [propKey]: true, ['a' + 'bc']: 123 };
const cart = { _wheels: 4, get wheels () { return this._wheels; }, set wheels (value) { if (value < this._wheels) { throw new Error('数值太小了!'); } this._wheels = value; } }
函数的扩展
函数作用:解决代码重用的问题
箭头函数
格式
//定义箭头函数 const eating=(形参,...)=>{ //函数体 } //调用箭头函数 eating(实参)
let fn=function(a,b){ return a+b }
let fn=(a,b)=>{ return a+b }
-
this的指向不同,箭头函数的this指向函数定义的位置
-
不能成为构造方法(报错)
-
不能使用call,bind和apply修改this的指向。不会有任何的修改
-
函数中不能使用一个arguments变量
-
当形参只有一个时可以省略形参的小括号,当函数体只有一条语句可以省略{},同时省略掉return,函数执行结果就是语句执行的结果。
总结:看函数的执行,普通函数中的this指向是他的调用者,箭头函数中的this指向的是定义的箭头函数的上下文的环境。
函数参数默认值的设置
function add(a,b,c=3){ return a+b+c } add(1,2) add(1,2,4)
-
一般函数参数的默认值放在后面
function add({name,age=18}){ console.log(name,age) } add({ name:"aa", age:18 }) add({ name:"aa", age:16 })
-
可以和结构赋值一起使用
function say([a,b]){ return a+b } say([3,4])
运算符的扩展
?.的使用
let obj={ } console.log(obj.a?.b?.c)
||的使用
const headerText = response.settings.headerText || 'Hello, world!';
Symbol的使用
ES6引入了一种新的原始的数据类型,表示独一无二的值,他是一种新的数据类型,是一种类似字符串的数据类型。
特点:
-
symbol的值是唯一的,用来解决命名冲突的问题的
-
symbol的值不能与其他数据进行运算
-
使用symbol定义的对象属性不能使用for...in 循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有的键名
let s=Symbol() console.log(s,typeof s)
let s=Symbol("hello") let s1=Symbol("hello") console.log(s,s1)
let game={ up:"go up" } let up=Symbol() game[up]="go up" let down=Symbol() game[down]="go down"
Set的使用
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
const set = new Set([1, 2, 3, 4, 4]);
-
Set.prototype.constructor
:构造函数,默认就是Set
函数。 -
Set.prototype.size
:返回Set
实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
-
Set.prototype.add(value)
:添加某个值,返回 Set 结构本身。 -
Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。 -
Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员。 -
Set.prototype.clear()
:清除所有成员,没有返回值。
Map的使用
const map = new Map(); map .set(1, 'aaa') .set(1, 'bbb'); map.get(1)
Object.defineProperty
//之前添加属性的方式 let Vue={ name:"zhangsan" } Vue.age=100
可以使用Object.defineProperty给一个对象添加属性
let Vue={ name:"zhangsan" } Vue.defineProperty(Vue,"age",{ get(){ return 值 //获取name属性执行的方法 }, set(value){ console.log(vaue) //给name属性赋值时的调用 } })
区别:第一种给属性赋值也就赋值了,不能做额外的操作,第二种不止可以赋值,还可以添加别的操作。
Vue2的底层使用defineProperty
let Vue={ data(){ return { name:"张三", age:18, height:180 } } } let data=Vue._data=Vue.data() for(let key in data){ Object.defineProperty(Vue,key,{ get(){ return Vue._data[key] }, set(value){ Vue._data[key]=value console.log("数据变了,页面要重新渲染了") } }) } //所以在Vue2中只要修改data返回的值,页面就要重新渲染 Vue.name="lisi" Vue.age=19 Vue.height=190 Vue.sex="男" //页面是不会进行重新渲染的
使用Object.defineProperty()添加的属性会走get和set的,直接添加的属性不会走get和set的,所以在Vue中想让新加的属性具有相应式Vue提供了$set,如果使用delete删除一个属性也不会走set的,所以Vue给我们提供了一个$delete.
Proxy
是一个构造方法
let obj={} let obj1=new Proxy(obj,{ get(target,propName){ //target就是代理对象,obj //propName://获取某个属性的属性名字 //console.log(target,propName) return target[propName] }, set(target,propName,value){ //target就是代理对象,obj //propName://获取某个属性的属性名字 //value:赋的新的值 target[propName]=value console.log("页面重新渲染") }, deleteProperty(target,propName){ delete target[propName] console.log("页面重新渲染") return true } })
Reflect
let person={ name:"zhangsan" } person.age=18 //这样添加我们也不知到添加成功了还是失败了,因为没有返回值 let res=Reflect.set(person,"age",18) //使用这种方式添加一个属性值的话就有返回值 if(res){ console.log('添加成功了') }else{ console.log("添加失败了") }
class的类的使用
ES5面向对象的写法
类的概念
是对象的一个模板,我们可以使用new 类名 产生无数个对象
格式
class 类名 { //构造方法必须要有,不需要人为的调用,在new 一个对象就会自动调用 constructor(name,age=0){ this.name=name this.age=age } 属性 //可以不写 方法 }
类的定义
class Person { //构造方法 constructor(name,age=0){ this.name=name this.age=age } crying(){ console.log(this.name+"哭了") } } const p1=new Person("zhangsan",18) console.log(p1) const p2=new Person("lisi",20) console.log(p2)
类中的静态属性和静态方法
类的继承
ES5实现类的继承
ES6实现类的继承
Promise
模块化