在 HTTP/1 中,每次请求都会建立一次HTTP连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive ,解决了多次连接的问题,但是依然有两个效率上的问题:
HTTP/2的多路复用就是为了解决上述的两个性能问题。
在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。
帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。
多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
let s2 = Symbol(‘another symbol‘)
Symbol()
函数时传入一个可选的字符串参数,相当于给你创建的Symbol实例一个描述信息Symbol
是一种基础数据类型,所以当我们使用typeof
去检查它的类型的时候,它会返回一个属于自己的类型symbol
,而不是什么string
、object
之类的①.使用Symbol来作为对象属性名
const PROP_NAME = Symbol() const PROP_AGE = Symbol() let obj = { [PROP_NAME]: "一斤代码" } obj[PROP_AGE] = 18 obj[PROP_NAME] // ‘一斤代码‘ obj[PROP_AGE] // 18
Object.keys()
或者for...in
来枚举对象的属性名,那在这方面,Symbol类型的key表现的会有什么不同之处呢?let obj = { [Symbol(‘name‘)]: ‘一斤代码‘, age: 18, title: ‘Engineer‘ } Object.keys(obj) // [‘age‘, ‘title‘] for (let p in obj) { console.log(p) // 分别会输出:‘age‘ 和 ‘title‘ } Object.getOwnPropertyNames(obj) // [‘age‘, ‘title‘]
Object.keys()
或者for...in
来枚举的,它未被包含在对象自身的属性名集合(property names)之中。所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。JSON.stringify()
将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外:
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
然而,这样的话,我们就没办法获取以Symbol方式定义的对象属性了么?非也。还是会有一些专门针对Symbol的API,比如:
// 使用Object的API Object.getOwnPropertySymbols(obj) // [Symbol(name)] // 使用新增的反射API Reflect.ownKeys(obj) // [Symbol(name), ‘age‘, ‘title‘]
②.使用Symbol代替常量:
const TYPE_AUDIO = ‘AUDIO‘ const TYPE_VIDEO = ‘VIDEO‘ const TYPE_IMAGE = ‘IMAGE‘ function handleFileResource(resource) { switch(resource.type) { case TYPE_AUDIO: playAudio(resource) break case TYPE_VIDEO: playVideo(resource) break case TYPE_IMAGE: previewImage(resource) break default: throw new Error(‘Unknown type of resource‘) } }
③.使用Symbol定义类的私有属性
//在a.js中
const PASSWORD = Symbol() class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd } } export default Login
//在b.js中 import Login from ‘./a‘ const login = new Login(‘admin‘, ‘123456‘) login.checkPassword(‘123456‘) // true login.PASSWORD // oh!no! login[PASSWORD] // oh!no! login["PASSWORD"] // oh!no!
PASSWORD
被定义在a.js所在的模块中,外面的模块获取不到这个Symbol,也不可能再创建一个一模一样的Symbol出来(因为Symbol是唯一的),因此这个PASSWORD
的Symbol只能被限制在a.js内部使用,所以使用它来定义的类属性是没有办法被模块外访问到的,达到了一个私有化的效果。<div id="root"> <ul> <li> <a> <img src="" > </a> </li> <li> <span></span> </li> <li></li> </ul> </div>
①.深度优先的遍历:
/*深度优先遍历三种方式*/
let deepTraversal1 = (node, nodeList = []) => {
if (node !== null) {
nodeList.push(node)
let children = node.children
for (let i = 0; i < children.length; i++) {
deepTraversal1(children[i], nodeList)
}
}
return nodeList
}
let deepTraversal2 = (node) => {
let nodes = []
if (node !== null) {
nodes.push(node)
let children = node.children
for (let i = 0; i < children.length; i++) {
nodes = nodes.concat(deepTraversal2(children[i]))
}
}
return nodes
}
// 非递归
let deepTraversal3 = (node) => {
let stack = []
let nodes = []
if (node) {
// 推入当前处理的node
stack.push(node)
while (stack.length) {
let item = stack.pop()
let children = item.children
nodes.push(item)
// node = [] stack = [parent]
// node = [parent] stack = [child3,child2,child1]
// node = [parent, child1] stack = [child3,child2,child1-2,child1-1]
// node = [parent, child1-1] stack = [child3,child2,child1-2]
for (let i = children.length - 1; i >= 0; i--) {
stack.push(children[i])
}
}
}
return nodes
}
②.广度优先遍历:
let widthTraversal2 = (node) => {
let nodes = []
let stack = []
if (node) {
stack.push(node)
while (stack.length) {
let item = stack.shift()
let children = item.children
nodes.push(item)
// 队列,先进先出
// nodes = [] stack = [parent]
// nodes = [parent] stack = [child1,child2,child3]
// nodes = [parent, child1] stack = [child2,child3,child1-1,child1-2]
// nodes = [parent,child1,child2]
for (let i = 0; i < children.length; i++) {
stack.push(children[i])
}
}
}
return nodes
}
节流和防抖?有什么区别?怎么实现?
防抖(debounce)
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
https://www.jianshu.com/p/c8b86b09daf0
父子组件之间的传值
<!DOCTYPE html> <html lang="en"> <head> <title></title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="app"> <h2>{{msg}}</h2> <!-- 使用子组件(以子组件的名字当做标签即可使用子组件),并向子组件传递了一个msg值 --> <son :info="msg"></son> </div> <script src="./lib/vue-2.4.0.js"></script> <script> var vm = new Vue({ el: ‘#app‘, data: { // 父组件中的msg值,要传递给子组件 msg: "我是父组件" }, // 定义一个私有的子组件 components: { // 子组件的名字为son son: { // 子组件显示的内容 template: "<h2>我是子组件+++{{info}}</h2>", // 接收父组件传递过来的值info,里面保存的是父组件的msg props: ["info"] } } }) </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>子传父</title> </head> <body> <div id="app"> <!-- 在父组件中使用子组件,并用v-on接收子组件传递过来的方法 --> <son @chuandi="fangfa"></son> </div> <script src="./lib/vue-2.4.0.js"></script> <script> let vm = new Vue({ el: ‘#app‘, data: { msg: ‘我是父组件的数据‘ }, methods: { // 在父组件中定义方法,接收子组件传递过来的值 fangfa(res){ console.log(res); } }, // 定义一个私有的子组件 components: { // 子组件的名字为son son: { // 子组件的内容 template: "<button>子组件标签</button>" // 子组件中的数据 data(){ return { message: "我是子组件的数据" } }, // 在created钩子函数中用$emit注册一个方法,第一个参数就是父组件用v-on绑定的属性,第二个参数是子组件要传递给父组件的值 created(){ this.$emit("chuandi",this.message); } } } }); </script> </body> </html>
Vue的生命周期
创建期间的生命周期函数:
beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
运行期间的生命周期函数:
beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
销毁期间的生命周期函数:
beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
原文:https://www.cnblogs.com/zhuzhu520/p/13284305.html