跨域问题及解决
跨域是指浏览器的不执行其他网站脚本的,由于浏览器的同源策略造成,是对JavaScript的一种安全限制, 当你通过浏览器向其他服务器发送请求时,不是服务器不响应,而是服务器返回的结果被浏览器限制了。同源策略是必须的,否则cookie可以共享。
解决办法
- jsonp: JSONP是服务器无客户端跨源通信的常用方法。基本思想是网页通过添加一个
- 代理服务器: 使用代理方式跨域更加直接,因为同源限制是浏览器实现的。如果请求不是从浏览器发起的,就不存在跨域问题了
- cors: 跨域资源共享(corss-origin resource sharing):CORS需要浏览器和服务器同时支持。目前所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
js中解构
- 默认赋值 给解构的变量赋予默认值, 就是说当age, 没有值
const User = {
name: '111',
}
const { name, age=18 } = User; //name=111 ; age=18
- ...展开式 这里的...会将后面的变量rest 变为一个对象, 用对象来接收余下的所有变量 ; c : d 是将变量c 更改名字为d
const obj = { a: 1, b: 2, c: 3, d: 4 };
const {
a, // a = 1
c: d, // d = 3
...rest // rest = { b: 2, d: 4 }
} = obj;
const nested = { a: { b: 1, c: 2 }, d: [1, 2]};
const {
a: {
b: f, // f = 1
...g // g = { c: 2 }
},
...h // h = { d: [1, 2]}
} = nested;
- 通过解构对象中的数字代表数组中下标对应的值; length 能拿到数组的长度并改名为count; 增添一个新的变量name; 用restData 接收所有未直接解构的变量
const arr = [ 5, 'b', 4, 'd', 'e', 'f', 2 ];
const {
6: x, // x = 2
0: y, // y = 5
2: z, // z = 4
length: count, // count = 7
name = 'array', // name = 'array' (not present in arr)
...restData // restData = { '1': 'b', '3': 'd', '4': 'e', '5': 'f' }
} = arr;
- 数组解构中的...赋值 这里展开后的rest为一个数组 (也就是说...如果用在对象中, 后面的变量就为一个对象, 如果用在数组中, 后面的变量就为一个数组)
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest); //[30, 40, 50]
- 交换两个变量的值
let a = 1;
let b = 3;
//交换a和b的值
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
- 改名并赋予默认值
let { a: aa = 10, b: bb = 5 } = { a: 3 };
console.log(aa); // 3
console.log(bb); // 5
动态路由传参
通过params 或 query 传参, 其中name 配合params 能在<router-link中使用> ; params传参不能用path,只能用name, 并且通过params 传值在浏览器地址栏中不显示参数, 更加安全
CSDN: blog.csdn.net/Lemontree_f…
观察者模式和订阅者模式
观察者模式
定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新
订阅者模式
发布-订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在
区别
- 在观察者模式中,观察者是知道Subject的,Subject一直保持对观察者进行记录。然而,在发布订阅模式中,发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。
- 在发布订阅模式中,组件是松散耦合的,正好和观察者模式相反。
- 观察者模式大多数时候是同步的,比如当事件触发,Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)
数据处理
数组的拷贝
这些方式能够拷贝新数组并且不拷贝原数组的地址
// `arr` is an array
const clone = arr => arr.slice(0);
// Or
const clone = arr => [...arr];
// Or
const clone = arr => Array.from(arr);
// Or
const clone = arr => arr.map(x => x);
// Or
const clone = arr => JSON.parse(JSON.stringify(arr));
// Or
const clone = arr => arr.concat([]);
对象的合并 (Object.assign)
注意这个方法会将两个对象中相同键的部分进行覆盖处理, 以方法中最后一个为准
let aaa = {
text: 2,
value: 11,
}
let bbb = {
text: 3
}
let ccc = Object.assign(aaa,bbb) // aaa目标对象, bbb源对象
console.log(ccc) // { text:2, value:11 }
call、apply、bind的用法和区别
这里案例中的this 都指向obj, 但如果我要显示的是db 中的数据的话, 就需要将this 指向db, 同时还要注意bind 指向之后需要手动调用, 而call 和bind 能够自动执行
obj.myFun.call(db); // 德玛年龄 99
obj.myFun.apply(db); // 德玛年龄 99
obj.myFun.bind(db)(); // 德玛年龄 99
注意
- 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
- bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行
- apply 可以接收伪数组, 也就是说这种情况也可以
func.apply(obj, {
0: 1,
1: 2,
2: 3,
length: 3
})
// func 接收到的参数实际上是 1,2,3
平铺结构数据转树形结构
用数组方法实现
export function tranListToTreeData(list) {
// 1. 定义两个变量
const treeList = []; const map = {}
// 2. 建立一个映射关系,并给每个元素补充children属性.
// 映射关系: 目的是让我们能通过id快速找到对应的元素
// 补充children:让后边的计算更方便
list.forEach(item => {
if (!item.children) {
item.children = []
}
map[item.id] = item
})
// 循环
list.forEach(item => {
// 对于每一个元素来说,先找它的上级
// 如果能找到,说明它有上级,则要把它添加到上级的children中去
// 如果找不到,说明它没有上级,直接添加到 treeList
const parent = map[item.pid]
// 如果存在上级则表示item不是最顶层的数据
if (parent) {
parent.children.push(item)
} else {
// 如果不存在上级 则是顶层数据,直接添加
treeList.push(item)
}
})
// 返回
return treeList
}
用递归实现
这里的递归退出条件为, 数组为空的时候, 就不会继续进入到函数调用的递归代码
promise 面试题
红色框为同步代码, 绿色框为异步代码
注意
- await axios() 返回值 和 后面的代码为异步代码, 而调用函数为同步代码
- 实际上是宏任务和宏任务的队列, 其中每个宏任务后面都排有微任务 (单个宏任务完成之后, 再进行内部的微任务, 再进行下一个宏任务)
浏览器代码审查
- 不进入调用函数中的代码, 直接拿到函数调用的结果
- 进入函数中的代码, 而不是直接拿到函数调用的结果
- 监视器, 可以将需要监视的变量放到监视器中, 实时显示变化的值
- 不同作用域中的变量
- 函数回调栈, 其中script 标签为一级匿名函数
- 栈队列为先进后出, 所以需要一级一级完成才能结束代码
tcp 与 udp 传输协议
- 当数据不太重要, 数据暂时丢失不太重要的场合, 就可以用udp, 比如视频直播的时候, 卡顿时的数据丢失也没关系, 但像王者中卡顿之后, 数据还是会全部加载, 用的就是tcp 连接
数据类型检测
| 适用于 | 返回 | |
|---|---|---|
| typeof | 基本数据类型 | string |
| instanceof | 任意对象 | true/false |
| Object.prototype.toString | 基本数据类型、内置对象以及包含 Symbol.toStringTag 属性的对象 | string |
闭包注意点
- 使用闭包的注意点: 由于闭包会使得函数中的变量都保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄漏。解决方法是,在退出函数之前,将不使用的局部变量全部删除(引用设置为
null,这样就解除了对这个变量的引用,其引用计数也会减少,从而确保其内存可以在适当的时机回收) - 内存泄漏: 程序的运行需要内存。对于持续运行的服务进程,必须及时释放不再用到的内存,否则占用越来越高,轻则影响系统性能,重则导致进程崩溃。不再用到的内存,没有及时释放,就叫做内存泄漏
- this指向: 闭包的this指向的是window
call 的应用
- 这里的 this 指向的是 obj, 同时向函数 foo 中传递两个参数, a和b 能拿到这两个参数
var obj = {name: "李四", age: 20};
function foo(a, b){
document.writeln(this.name);
document.writeln(a);
document.writeln(b);
}
// 改变this引用为obj,同时传递两个参数
foo.call(obj, 12, true); // 李四 12 true
Array.prototype.slice.call(arguments,0)这句里,就是把 arguments 当做当前对象,
也就是说 要调用的是 arguments 的 slice 方法,后面的 参数 0 也就成了 slice 的第一个参数,slice(0)就是获取所有。
[].slice.call(arguments)能将具有length属性的对象转成数组
Array.prototype.slice.call(伪数组)也能将伪数组转成真数组
nextTick 原理 (待补充)
@hook 钩子函数
能够在父组件中使用, 能够在子组件通过 @hook 绑定生命周期函数, 根据子组件的生命周期不同时机执行不同函数(也就是说这里的 @hook:mounted 会在子组件的 dom 加载完成后执行函数)
<v-chart
@hook:mounted="loading = false"
@hook:beforeUpdated="loading = true"
@hook:updated="loading = false"
:data="data"
/>
实例属性 / 原型属性 / 静态属性 的区别
这个案例解释了 vue 的 data 为什么要是一个函数的问题
为了形成局部作用域, 使不同组件的相同名字的变量不会相互影响, 因为 data 返回的对象会开辟一个新的内存空间
小的注意点
- 注意数据的原型的数据类型不只有对象一种
补充点
- 通过给元素标签设置 id, 能够通过 js 代码直接通过 id 拿到元素 (不过版本浏览器不兼容)