beforeCreate:methods声明,生命周期钩子函数声明
created:data数据注入,data数据劫持
beforeMount :此时模板已经编译完成,但还没有被渲染至页面中
mounted :渲染真实DOM
beforeUpdate : 当被劫持的data数据发生变化时,这将经入更新阶段,数据已经发生变化但是视图还未变化
updated :更新真实DOM,视图发生改变
beforeDestroy :销毁前执行,清除计时器、清除非指令绑定的事件等等
destroyed:卸载watcher,事件监听,子组件
beforeCreate created beforeMount mounted
可以在 created /beforeMount/mounted /beforeUpdate /updated /beforeUnmount 访问
对一个响应式变量赋值,最好不要在钩子函数updated中,不然会造成死循环
组件理解:用来实现页面局部功能效果的代码集合
ref和reactive以及toRef、toRefs
都是用来定义响应式变量,使用前import。reactive()用来定义对象,但在对象定义复杂的时候 会出现不能响应的情况。
ref:创建单个响应式变量,修改响应式数据不影响以前的数据;数据改变,界面自动更新
reactive:用于创建一个响应式对象,reactive不能直接赋值,可以Object.assign进行赋值
toRef:引用,修改响应式数据会影响以前的数据;数据改变,界面不自动更新
toRefs:接收一个对象作为参数,它会遍历对象身上所有属性,然后调用单个toRef,将对象的多个属性变成响应式数据,并且要求响应式数据和原始数据关联,且更新响应式数据的时候不会更新界面,用于批量设置多个数据为响应式
响应式变量驱动视图是 异步线程
nextTick()和onUpdate()的相同和区别
相同:只和视图变化有关
区别:nextTick() 依附逻辑执行 例子体现:VTT-NextTick()
computed 在数据没有变化的情况下,会拿缓存数据,节约资源,利用性高;而调用函数会进行重新计算一次
1). query传值 2). params传值 // 语法相同
10.当在一个button 中的click事件的函数逻辑中通过addRoute新增一个路由配置,然后通过编程式路由跳转到该路由配置的path,成功跳转后刷新页面不能正常显示该组件
将变量定义为window对象的属性 window.变量=xx;
将变量定义为当前vue实例的属性 在main.js定义
Vue3:当前vue实例.config.globalProperties.$变量=xx;
Vue2:当前vue实例 .prototype.global = global
vue实现数据双向绑定主要是采用数据劫持和发布订阅的模式,通过objiect.defineProperty()的get和set,在数据变动的时候发布消息给订阅者,触发消息。
因此接下去我们执行以下3个步骤,实现数据的双向绑定:
实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher) 。
v-model是什么?如何实现双向绑定的
本质是一个语法糖,可以看成input+value的语法糖。可以通过model的prop属性和event事件来进行自定义。用来监听输入的事件以及更新数据。
vue2里面用Object.defineProperty监听每个属性;
vue3里面用new Proxy 监听整个对象。
watch : 监听属性
不支持缓存,数据变化直接触发响应操作
支持异步
可以监听简单类型也可以监听复杂类型
immediate:组件加载立即触发回调函数执行;
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用。
当需要在数据变化时执行异步或开销较大的操作时,使用watch
watchEffect:依赖数据更新时重新执行自身
立即执行,没有惰性,页面的首次加载就会执行
无法获取到原值,只能得到变化后的值
不用指明监视哪个属性,监视的回调中用到哪个属性就监视哪个属性
computed:计算属性
页面初始化数据的时候就执行了
不支持异步,当computed内有异步操作时无效,无法监听数据的变化
computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
计算属性可以是属性值也可以是函数
Diff算法的作用是用来计算出 虚拟 DOM 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面
在v-for循环中,key的作用通过判断新节点和旧节点的Key是否相等,从而复用与新节点对应的老节点,节约性能的开销。
使用唯一id作为Key值,不建议用index作为key,因为无法被有效复用,新节点需要重新创建
首屏需要加载很大的js文件,当网速差的时候会出现一定程度上白屏
解决办法:
优化 webpack 减少模块打包体积,code-split 按需加载
服务端渲染,在服务端事先拼装好首页所需的 html
首页加 loading 或 骨架屏 (仅仅是优化体验)
服务端开启gzip压缩
打包文件分包,提取公共文件包
祖传孙:
- $props 链 :传递次序:GrandFather → Father → GrandSon;
- $attrs :直接使用 v-bind=“attrs” 绑定到子组件上;
- 祖组件中 写入 provide(‘传递的变量名’,自定义变量名),孙组件中写入inject(‘接收的传递的变量名’)这种方式传递过来的数据是没有响应性的,如果传入了一个可监听的对象,那么其对象的 property 还是可响应的。
孙传组:
- $listeners // $emit
Vue.nextTick():在Vue生命周期的created()函数中进行DOM操作是要放在Vue.nextTick()回调函数中。原因就是created()在执行的时候DOM只是创建出来并没有渲染在页面上,因此页面上没有这个元素也就无法对其进行操作。
mounted():函数执行时所有的DOM的创建,布局和渲染都已完成。
nextTick()直接放在mounted函数之中是没有作用的,要写在异步函数完成之后。
由于Pinia是轻量级的,体积很小,它适合于中小型应用。它也适用于低复杂度的Vue.js项目,但一些调试功能,如时间旅行和编辑仍然不被支持。
将 Vuex 用于中小型 Vue.js 项目对性能降低有很大影响,更 适用于大规模、高复杂度的 Vue.js 项目。
- pinia的属性:state,getters,action
- vuex的属性:
state(负责状态管理,类似于vue中的data,初始化数据),
getters(计算属性,相当于vue中的computed),
mutation(专用于修改state中的数据) ,
action( 可以处理异步) ,
module(模块化管理)
- 响应式原理的不同:vue2 的双向数据绑定是利用Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的;vue3 中使用了 ProxyAPI 对数据代理。
vue3使用proxy的优势:
defineProperty只能监听某个属性,不能对全对象监听
可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化- Vue2使用选项类型API(Options API)对比 Vue3合成型API(Composition API),vue3更加简便和整洁
- 生命周期钩子
- 建立数据 data:
Vue2 - 这里把数据放入data属性中;在Vue3 - 在setup()方法中(此方法在组件初始化构造的时候触发)。使用reactive//ref 方法来声名我们的数据为响应性数据。
- 防抖(多次触发 只执行最后一次)
作用: 高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间内再次触发,则重新计算时间
防抖类似于英雄联盟回城6秒,如果回城中被打断,再次回城需要再等6秒
使用场景:1) .search搜索时,用户在不断输入值时,用防抖来节约请求资源。- 节流 (规定时间内 只触发一次)
作用: 高频率触发的事件,在指定的单位时间内,只响应第一次
节流类似于英雄联盟里的英雄平A 一定是内点击多次只进行攻击一次
使用场景:1).鼠标不断点击触发,mousedown单位时间内只触发一次
2).监听滚动事件,比如是否滑到底部自动加载更多-------触底加载的优化
- Promise 是异步编程的一种解决方案
- Promise的实例有三个状态:Pending(进行中)、Resolved(已完成)、Rejected(已拒绝)
- then函数中的两个参数:resolved成功回调和rejected失败回调
- Promise的catch、then、finally :promise可以链式调用,因为每次调用 .then 或者 .catch 都会返回一个新的 promise
.finally()方法不管Promise对象最后的状态如何都会执行,他回调函数不接受任何的参数,也就是说你在.finally()函数中是无法知道Promise最终的状态是resolved还是rejected的- Promise的all和race:
.all()的作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调
.race()的作用是接收一组异步任务,然后并行执行异步任务,只保留取第一个执行完成的异步操作的结果,其他的方法仍在执行,不过执行结果会被抛弃
也是异步编程的一种解决方案,但它是同步语法来写异步的代码
await只能在async函数中使用,不然会报错
async函数返回的是一个状态为fuifilled(状态为成功)的Promise对象
const datas = async ()=> {
await request.selectPies(Route.path.split('/')[3]).then(res=>{
states.ids = res.obj
})
await request.selectUsers(states.ids).then(res=>{
console.log(res.obj)
})
}
datas()
事件委托原理:事件冒泡机制,把子元素的事件行为 委托给 父级元素执行
优点:节省内存占用,减少事件注册;新增子对象无需进行事件绑定
缺点:把所有的事件都进行代理,可能会出现事件误判
事件冒泡:事件逐级向上传播
事件捕捉:事件逐级向下传播,一直到具体
Dom事件流:事件捕捉 目标阶段 事件冒泡
- typeof 变量
- 变量.constructor===String
- Object.prototype.toString.call(变量)//推荐使用
判断变量是数组的方法
- Array.isArray(变量)
- 变量 instanceof Array
- object.prototype.toString.call(变量) === ‘[object Array]’
- Array.prototype.isPrototypeOf(变量)
- 变量.constructor === Array
几种变量类型判断方法的优缺点
1). typeof
console.log(typeof null) // object
console.log(typeof {}) // object
优点:该方法简单、快速,适用于大多数情况下。
缺点:其中数组、对象、null 都会被判断为 object,无法判断复杂的数据类型如数组和正则表达式,其他判断都正确。
2). instanceof:可以用于判断对象是否为某个构造函数的实例。
console.log(2 intanceof Number) // false
console.log( [] intanceof Array ) // true
优点:可以区分复杂的数据类型如数组和正则表达式。
缺点:无法判断基本数据类型,也无法判断 null 和 undefined 类型。
3). constructor :
function Fn(){}
Fn.prototype = new Array();
var f = new Fn();
console.log( f.constructor === Fn ) // false
console.log( f.constructor === Array ) //true
优点:语法简单,只需访问变量的 constructor 属性即可判断。
缺点:当变量被重新赋值时,可能会出现问题,无法判断 null 和 undefined 类型。
4). Array.isArray()
缺点:只能判断数组类型,无法判断其他数据类型。
5). Object.prototype.toString.call():使用 Object 对象的原型方法toString 来判断数据类型
var a = Object.prototype.toString;
console.log(a.call(2))
优点:可以判断复杂的数据类型,包括数组、正则表达式等。
缺点:需要调用 Object.prototype.toString.call() 方法,语法较复杂
substr(n,m):截取的是字符串中索引为n开始的,并且截取m位
substring(n,m):截取的是字符串中索引为n开始,为m结束,但不包括m这一项
slice(n,m):用法与substring相同,但可以支持负数索引
splice(n,m,item1,item2…):从第n个位置删除m个元素,包括第n个。添加item1,item2…新元素。会改变原数组,返回被删除的数组
//slice(n,m)
var arr1 = [1,23,44,55,66,77,888,"fff"];
var arr2 = arr1.slice(2,4) //从index为2截取到index为4之前不包括4
console.log(arr2); //[44,55]
console.log(arr1); // [1,23,44,55,66,77,888,"fff"]原始数组没有被改变
//splice(start,deleteCount,item1,item2)
var arr3 = [1,2,3,4,5,6,7,"f1","f2"];
var arr4 = arr3.splice(2,3) //删除第三个元素以后的三个数组元素(包含第三个元素)
console.log(arr4); //[3,4,5];
console.log(arr3); //[1,2,6,7,"f1","f2"]; 原始数组被改变
var arr5 = arr3.splice(2,0,"wu","leon");
//从第2位开始删除0个元素,插入"wu","leon"
console.log(arr5); //[] 返回空数组
console.log(arr3); // [1, 2, "wu", "leon", 6, 7, "f1", "f2"]; 原始数组被改变
var arr6 = arr3.splice(2,3,"xiao","long");
//从第2位开始删除3个元素,插入"xiao","long"
console.log(arr6); //["wu", "leon", 6]
console.log(arr3); //[1, 2, "xiao", "long", 7, "f1", "f2"]
var arr7 = arr3.splice(2);//从第三个元素开始删除所有的元素
console.log(arr7);//["xiao", "long", 7, "f1", "f2"]
console.log(arr3); //[1, 2]
- 全局作用域中的函数:非严格模式下其内部this指向window;
- 对象内部的函数:其内部this指向对象本身;
- 构造函数:其内部this指向生成的实例;
- 由apply、call、bind改造的函数:其this指向第一个参数;
- 箭头函数:箭头函数没有自己的this,看其外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。(函数定义时的this,而不是调用时this)
- 宏任务和微任务是什么?
由于js是一种单线程语言,在任务多的情况下就有了同步和异步任务。在es5之后,javascript自身能引起异步请求的能力,这时就产生了宏任务和微任务。- 宏任务和微任务分别有哪些?
宏任务(由宿主发起):setTimeout/setInterval;script外层同步代码…
微任务(由js引擎发起):promise;proxy;…- 宏任务和微任务执行顺序?
先执行同步任务 —>在执行异步任务 ( 先执行异步微任务—> 再执行异步宏任务 )
一、html5 web本地存储:sessionStorage和localStorage。
以键值对的形式存储,通常以字符串存储,存储复杂类型时,需要进行数据格式转换。
不参与服务器的通信,仅存在客户端。
- localStorage:生命周期为永久,除非手动清除localStorage,否则信息一直都在。
- sessionStorage:生命周期为当前会话,关闭浏览器或关闭页面后被清除。
二、cookie:简言之,cookie是服务器端发给客户端的文本文件;目的是用于辨别用户身份。
如果不在浏览器中设置过期时间,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称会话cookie。
如果在浏览器中设置了cookie的过期时间,cookie被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,直到过期时间结束才消失。
- Array.sort()函数
var ary = [311,43,54,4,40,26,31,33]
var arySortA = ary.sort();
console.log(arySortA);//26, 31, 311, 33, 4, 40, 43, 54
//降序排列
var arySortB = ary.sort(function(a,b){
return b-a;
})
console.log(arySortB);//311, 54, 43, 40, 33, 31, 26, 4
- 冒泡排序
原理:a.比较相邻的元素,如果第一个比第二个大,就交换他们;
b.对每一对相邻元素做同样的工作,最后的元素应该会是最大的数;
//判断是否是数组,数组是否为空
function arrisArray ( arr ) {
return Object.prototype.toString.call(arr) === '[object Array]' && arr.length > 0
// 如果是数组并且数组长度大于零,则返回true。
}
//封装冒泡排序函数
function bubble(arr){
if(arrisArray(arr)){
//外层循环,控制趟数,每一次找到一个最大值
for (var i = 0; i < arr.length - 1; i++) {
// 内层循环,控制比较的次数,并且判断两个数的大小
for (var j = 0; j < arr.length - 1 - i; j++) {
// 白话解释:如果前面的数大,放到后面(当然是从小到大的冒泡排序)
if (arr[j] > arr[j + 1]) {
//var temp = arr[j];
//arr[j] = arr[j + 1];
//arr[j + 1] = temp;
[arr[i], arr[i+1]] = [arr[i+1], arr[i]]//使用结构赋值简洁代码
}
}
}
return arr
}
}
var arr = [29,45,51,68,72,97];
console.log(bubble(arr));//[2, 4, 5, 12, 31, 32, 45, 52, 78, 89]
简单数组去重:
- Set()+Array.from()
const result = Array.from(new Set(arr))
- 利用两层循环+数组的splice方法
- 利用数组的indexOf / includes方法
- 利用数组的filter()+indexOf()
…
数组对象去重:
1、对象访问属性的方法
//
let newArr = [];
let obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i].key]) {
newArr.push(arr[i])
obj[arr[i].key] = true
}
}
console.log(newArr);
2、Map()方法
//set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。
//values方法可以返回Map对象值的遍历器对象
let map = new Map();
for (let item of this.arr) {
map.set(item.id, item);
}
this.arr = [...map.values()];
console.log(this.arr)
3、reduce() 方法
//reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值
const obj = {}
arr = arr.reduce((total, next) => {
obj[next.key] ? '' : obj[next.key] = true && total.push(next)
return total
}, [])
console.log(arr)
- 什么是闭包?
闭包可以当作一个密闭的容器,用来存储数据,它是一个对象,存放数据的格式:key:value。- 闭包形成的条件?
函数嵌套 并且 内部函数引用外部函数- 闭包的应用场景?
它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。- 闭包的优缺点?
优点:延长外部函数局部变量的生命周期
缺点:本应被销毁的变量,因为闭包的原因没有被销毁,长期存在的话,容易造成内存泄漏
- 新增let const关键字
- 新增解构赋值和箭头函数
- 新增模块化,通过import导入 然后通过export导出
- 新增promise,es6处理异步的一种方。本质是一个对象,promise的参数是一个回调,回调有连个参数 resolve 成功回调 reject 失败回调。
…
- get因为参数会放在url中,所以隐私性,安全性较差,请求的数据长度是有限制的,不同的浏览器和服务器不同,一般限制在 2~8K 之间,更加常见的是 1k 以内。get请求一般是去取获取数据。
- post请求是没有的长度限制,请求数据是放在body中。post请求一般是去提交数据。
- get请求可以被缓存,post请求不会被缓存。get请求会被保存在浏览器历史记录当中,post不会。get请求可以被收藏为书签,因为参数就在url中,但post不能,它的参数不在url中。
- 通过http GET/POST/PUT/DELETE 获取/新建/更新/删除 资源
- 一般使用JSON格式返回数据
- 创建空对象
- 新对象执行prototype连接原型
- 绑定this到新对象上
- 执行构造函数
- 返回新对象
Class是面向对象的语法的一个实现。Class本质上类似一个模板,通过模板去构建一些东西。可以通过constructor去构建一些东西,构建的时候可以复制一些属性,一些方法。
//类 开头大写
class Student {
//构造器构造属性
constructor(name,number) {
//this代表当前你正在构造的实例
this.name = name;
this.number = number;
}
//方法
sayHi() {
console.log(`姓名 ${this.name}, 学号 ${this.number}`)
// console.log('姓名 ' + this.name + ' , 学号' + this.number)
}
}
//通过类 new 对象/实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name);//夏洛
console.log(xialuo.number);//100
xialuo.sayHi();//姓名 夏洛, 学号 100
class的继承:有很多个class,这些class有一些共用的属性的时候,就可以抽离出来。
- 通过extends去做的
- 里面通过super来执行父类的构造函数,也就是父类的构建过程。
- 扩展或重写的方法
//父类
class People {
constructor(name) {
this.name = name
}
eat() {
console.log(`${this.name} eat something`)
}
}
//子类 继承父类 里面的方法可以直接调用,属性需要调用super去执行
class Student extends People {
constructor(name,number) {
//调用super,People会自动帮我们处理name
super(name)
//自己处理,学生才有自己的学号
this.number = number
}
sayHi() {
console.log(`姓名 ${this.name} 学号 ${this.number}`)
}
}
//子类
class Teacher extends People {
constructor(name,major) {
super(name)
this.major = major
}
teach() {
console.log(`${this.name} 教授 ${this.major}`)
}
}
//实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name);//夏洛
console.log(xialuo.number);//100
xialuo.sayHi();//姓名 夏洛 学号 100
xialuo.eat();//夏洛 eat something
//实例
const wanglaoshi = new Teacher('王老师','语文')
console.log(wanglaoshi.name);//王老师
console.log(wanglaoshi.major);//语文
wanglaoshi.teach();//王老师 教授 语文
wanglaoshi.eat();//王老师 eat something
div{ /*宽高为0*/
width: 0;
height: 0;
/*在三角形一边设置一个边界颜色*/
border-top: 20px solid red;
/*其它3边设置相同颜色,*/
border-bottom: 20px solid white;
border-left: 20px solid white;
border-right: 20px solid white;
1、绝对定位居中
2、负margin居中
3、margin固定宽高居中
4、flex居中
5、transform居中
6、不确定宽高居中(绝对定位百分数:只需要保证left和right的百分数一样就可以实现水平居中,保证top和bottom的百分数一样就可以实现垂直居中。)
- css盒子模型 ,包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素。
- box-sizing中比较常用的两个属性值为
1). content-box :标准盒子,默认模式
盒子的宽度=margin(左右外边距)+padding(左右内边距)+border(左右边框)+内容的(width).
2). border-box:怪异盒子
盒子的宽度=内容的(width)+margin(左右)(这里的内容width包含了padding(左右内边距)+border(左右边框))
- 额外标签法: 给谁清除浮动,就在其后额外添加一个空白标签。
优点: 通俗易懂,书写方便。(不推荐使用)
缺点: 添加许多无意义的标签,结构化比较差。
- 父级添加overflow方法: 可以通过触发BFC的方式,实现清楚浮动效果。必须定义width或zoom:1。同时,不能定义height,因为使用overflow:hidden时,浏览器会自动检查浮动区域的高度。
优点: 简单、代码少、浏览器支持好。
缺点: 内容增多时候容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素。不能和position配合使用,因为超出的尺寸的会被隐藏。
- 使用after伪元素清除浮动
优点: 符合闭合浮动思想,结构语义化正确,不容易出现怪问题(目前:大型网站都有使用,如:腾迅,网易,新浪等等)
- 使用before和after双伪元素清除浮动
注意:设为Flex布局后,子元素的float、clear和vertical-align属性将失效。
子元素设置的属性
flex属性是flex-grow(放大比例), flex-shrink(缩小比例) 和 flex-basis的合写,默认值为0 1 auto;
align-self属性(单独给自己设置对齐方式)
- BFC:块级格式化上下文,BFC是一块块独立的渲染区域,可以将BFC看成是元素的一种属性,拥有了这种属性的元素就会使他的子元素与世隔绝,不会影响到外部其他元素。
- 触发BFC:
·设置浮动,不包括none
·设置定位,absoulte或者fixed
·行内块显示模式,inline-block
·设置overflow,即hidden,auto,scroll
·表格单元格,table-cell
·弹性布局,flex- 解决问题:
1)解决外边距的塌陷问题(垂直塌陷)
2)顶部包含塌陷
3)清除浮动 overflow:hidden
常见行内元素:span、a、i、br
常见块级元素:div、p、ul、li、form、table、h1~h6
常见行内块元素:img、input
!important =》无穷
行类样式 =》 1000
ID选择器 =》0100
类选择器,伪类选择器=》0010
元素选择器 =》0001
css继承 =》0000
详细参考: http://t.csdn.cn/Mpw7B
- 用git工具检查当前状态
- 查看当前分支命令
- 代码误删,怎么恢复?
本地项目还在的情况下,在有.git的那个目录下载,打开bash窗口,输入命令git reflog。窗口里面会展示从建立以来所有的变动log日志,找到想要的版本。
使用q键退出检视,接着输入git checkout -b 新分支名字 HEAD@{编号} 命令。- …
TCP协议是对数据传输提供的一个管控机制
详细面试题参考: http://t.csdn.cn/YQbOY
- 什么是WebSocket?
WebSocket是HTML5下一种新的协议,是一个持久化的协议(本质上是一个基于tcp的协议)。
它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的。- Websocket解决的问题?
解决了Http长连接传统的客户端对服务器发起请求的模式,实现客户端与服务器端完全平等,解决了http不能实时更新的弊端。
//匿名函数的this指向window。
//在使用时:可以当做变量的值、当做参数值、可以自调用
function show4(){
let m = function(){
console.log('key');//key
}
m();
}
show4();
//箭头函数的this指向要调用函数的对象
//在使用时:可以当做变量的值、当做参数值、可以自调用
function show4() {
let test = (name, age) => {
console.log(name, age);//wang 20
};
test('wang', 20);
}
show4();