浏览器相关
修改数组下标 不会影响视图
- 数据是修改的,但是视图没有变化的
- 原因:vue2是使用ObjectDefineProperty来实现的,只监听data数据存在的变量,对于循环添加新值的时候,监听不到,因此造成数据发生变化,视图没有发生变化
- vue3 则不会有这样的问题,因为proxy会一直监听整个数据
- 解决方式:使用 this.$set的方法去解决
<!-- -->
<template>
<div>
MenuBar
{{ msg }}
<div v-for="item in arr" :key="item">
{{ item }}
</div>
<button @click="clickBtn">修改最后一项</button>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator'
@Component({
components: {}
})
export default class MenuBar extends Vue {
msg = '我是msg'
arr = [1, 2, 3]
clickBtn = () => {
this.arr[2] = 333 // 直接修改下标 数据修改了 但是视图不修改
console.log('this.arr', this.arr) // 修改数组下标的值 不会影响视图 [1, 2, 333]
// this.$set(this.arr, 0, 111) // 注释掉上方 验证下方 输出 [1,2,333] 视图也发生变化
// console.log('this.arr', this.arr) // 修改数组下标的值 不会影响视图 [1, 2, 333]
}
}
</script>
<style scoped></style>
- 效果
浏览器的同源策略
- 概念:浏览器的同源策略是指 js脚本在未经允许的情况下,不能够访问其他域下的内容。
- 什么是同源
- 协议,域名,端口都相同的则是同源,其中一个不同则都不属于同源。
- 同源策略的限制三个方面
- 1、一个域下的js脚本不能访问另一个域下面的cookie,localStorage和indexDB
- 2、一个域下的js脚本不能够操作另一个域下的DOM.
- 3、ajax不能做跨域请求。
- 为什么script标签,img标签,以及link标签可以链接其他域中的资源?
- 因为这些标签不能通过相应的结果来进行安全问题的操作。
解决跨域与何为协议、域名、端口
- http://www.test.com/index.html
- 协议
- 常见的协议:http、https
- 域名
- 常见域名:.com、.top、.net、.org ( 每一个域名对应一个相应的IP)
- 主域名、子域名之分( 主域名:test,子域名:www )
- 端口
- :80、:8080等
- :80、:8080等
- 解决跨域
- proxy代理
- cors
输入一个url 的一次完整的http服务过程
- 把题目可以解析为:在web浏览器输入:www.baidu.com 回车后会发生什么?
1:首先www.baidu.com 这个网址进行DNS域名解析,得到相应的IP地址
2:根据这个IP找到相应的服务器,发起TCP三次握手
3:建立TCP链接之后,发起HTTP请求
4:服务器相应HTTP请求,服务器把html代码发送给浏览器
5:浏览器解析html代码,并请求html之中的资源(比如:css,img等) 这是先得到html,再请求其他的
6:浏览器对页面进行渲染,呈现给用户
7:服务器关闭TCP连接(http连接)
垃圾回收机制
- 常用的变量标记法
- 当变量进入执行环境,就会被标记为进入环境,离开环境后会被标记为离开环境,在环境中的变量不会被释放,因为随时可能被用到。
- 垃圾收集器在运行时会给内存中所有的变量加上标记,但是会去掉那些环境中的变量,以及被环境中的变量引用的变量,如果后续在被加上标记就会被视为准备删除的变量。
- 最后垃圾收集器销毁这些带标记的变量,回收他们所占的内存。
function aaa() {
var b = 20 // 当前变量b进入环境 标记为变量进入环境
console.log('b', b)
}
aaa() // aaa方法调用 使用到b变量 函数执行完毕 销毁变量 标记b变量被消耗
// console.log('bb', b) // 会查找不到当前变量,因为被消耗了!
http和https区别 https的s是什么?
- http:超文本传输协议
- https:超文本传输安全协议
- https的s是什么?
- s指的是:利用 SSL 来加密数据包
- http 和 https的区别
- HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
- 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。
- HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
- http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源
http状态码
- 成功200
- 重定向方面的问题 300
- 301:永久重定向
- 302: 临时重定向
- 304:缓存造成的问题
- 请求或者权限相关错误 400
- 400:报文存在语法错误
- 401:发送请求需要 通过 http 发起请求
- 403:请求资源被拒绝,没有权限访问
- 404:没有找到该资源
- 服务器相关500
- 500:服务器发生报错
http2
- http2就是对http1进行了升级,优化了http1的一些问题
- 1:头部压缩
- http1对Body进行压缩,但是没有对头部进行压缩
- http2 对头部进行了压缩
- 2:队头阻塞
- http1采用tcp协议,为节省资源,采用长链接,会造成对头阻塞
- http2 引入流和帧,解决http1的对头阻塞
前端做网络接口请求,网络情况不优,前端要怎么处理
- 请求的时候 加loading 并且配置请求响应时间,超时不等待
浏览器线程和进程
浏览器进程
- 浏览器的进程就是浏览器开辟的一个独立执行环境,对静态代码的执行环境,就是浏览器的一个tab页就是一个进程。
浏览器线程
- 浏览器的线程:浏览器线程是建立再浏览器的进程之中,一个进程里面可以包含多个线程,线程之间是可以通信的,只不过代价相对较大
- 线程的分类
- GUI线程:
- 就是针对html,css,dom节点渲染等相关的加载渲染线程
- GUI线程:
- js引擎线程
- 就是浏览器针对js代码执行,实现对应的交互效果(谷歌浏览器的js引擎为V8引擎)
- 注意点:js引擎是单线程的,因此存在消息队列
- 事件线程
- 就是控制事件循环的相关线程是存在事件线程的,而不是js线程,再线程之中符合条件触发之后,把之放在消息队列之中,然后js引擎去执行对应的消息队列
- 定时器线程
- 就是setTimeout、setInterval这两种定时器,是存在定时器线程的,就是等待时间达到满足条件后,把要处理的事情放置再消息队列之中,等待js引擎去执行
- http线程
- 就是针对htpp相关请求的线程
前端缓存
- http缓存
- http缓存是http请求传输时用到的缓存,主要是在服务器代码上设置的(若是请求同一个接口时,返回的数据一致,是直接拿缓存的结果)
- 浏览器缓存
- 浏览器缓存有 localStorage sessionStorage cookie 等
前端如何做信息攻防
- xss攻击
- 原因:就是服务器对客户端的信任
- 解决:需要 对用户输入进行过滤(对应script标签过滤掉)
- csrf -> 请求伪造
- 原因:就是服务器对客户端的信任
- 解决:需要 用户请求时,携带token值
前端跨越处理
- 直接使用 proxy的形式处理即可 (或者后端处理 cors)
js
typeof 与 instanceof的区别
- typeof用于判断简单数据类型,对于对象而已,除了function 其他的都是Object
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
- instanceof 用于判断复杂类型 原理是:根据对象的原型链来找出这个变量属于什么类型
const Person = function() {}
const p1 = new Person()
p1 instanceof Person // true
var str = 'hello world'
str instanceof String // false
//这是因为 str只是存储字符串的一个变量 不是一个对象,因此没有原型 直接为false
var str1 = new String('hello world')
str1 instanceof String // true
let arr = [1, 2, 3]
let obj = {
name: "pink"
}
console.log("arr", arr instanceof Array);
console.log("arr", arr instanceof Object);
console.log("obj", obj instanceof Object);
// 都为true 因此在判断数组的时候 需要先判断!
== 与 ===
原型链
- 概念:原型链就是所有原型所构成的一条链条,这链条称之为原型链
- 对象查找机制的时候,通过 proto 查找对象原型上的属性,若是没有当前属性,则又查找对象原型下的 __proto__去查找,直到Object对象最顶层,若是没有找到,则返回null
- 原型
- 没有函数都有一个 prototype属性 称之为原型( 这个prototype属性指向函数的原型对象 )
- 由于这个属性是一个对象,也称之为原型对象
- 原型作用
- 存储属性和方法 ( 拿数据或者调用方法 obj.xxx 、obj.fun() )
- 也可以用于js的继承
判断数组、对象的几种方式
判断数据的三种方式
- Array.isArray(arr)
- arr instanceof Array
- Object.prototype.toString.call(arr).slice(8, -1)
let arr = [11, 22]
let obj = { age: '20' }
// console.log('res', Array.isArray(arr), 'res2', Array.isArray(obj)) // res true res2 false
// console.log('res', arr instanceof Array) // res true
console.log('res', Object.prototype.toString.call(arr).slice(8, -1)) // res Array
判断对象的
- typeof obj
- obj instanceof obj
- Object.prototype.toString.call(obj).slice(8, -1))
let obj = { age: '20' }
// console.log('res', typeof obj) // res object
// console.log('res', obj instanceof Object) // res true
// console.log('res', Object.prototype.toString.call(obj).slice(8, -1)) // res object
继承
- es6方式
- 使用 extend的 方式 直接去继承
- es5方式
- call + 原型对象的形式 去继承
数组的区别
apply和call的区别 bind
- 都是改变this的指向
- 区别点 (调用时候,传递的参数)
- apply - 传递参数为数组
- apply( this, [] )
- 可以用于求数组最大值什么的
- call - 传递参数为 多个元素
- call( this, X , X )
- 用于继承
- bind - 改变this的指向,但是返回一个新的函数(原始函数不被直接调用)
- bind( this, XX )
- apply - 传递参数为数组
01 + 02 != 0.3
- 因为计算机时用 0 1 去存储数据的,因此对于浮点数,有着止不禁的数值,于是加起来不等于 0.3
- 解决
- 方式1:
- 就是 0.1 与 0.2 皆 * 10 相加后,除于10, 然后0.3 * 10 ,之后除于10,再进行比较
let res = (0.1 * 10 + 0.2 * 10) / 10 === (0.3 * 10) / 10 console.log('res', res) // res true
- 就是 0.1 与 0.2 皆 * 10 相加后,除于10, 然后0.3 * 10 ,之后除于10,再进行比较
- 方式2:直接使用 loadsh 工具库,进行处理
- 方式1:
cookies,sessionStorage和localStorage的区别
- 相同点
- 他们都是以键值对的形式存储
- 区别
- cookies
- 会话级别,浏览器关闭,数据清空
- 存储大概 3k
- 可以使用 express 去设置存储时间
- sessionStorage
- 会话级别,浏览器关闭,数据清空
- 存储5M
- 同一个页面数据可共享
- localStorage
- 永久存在,浏览器关闭,数据还在,除非手动删除
- 存储可 5M
- 同一个浏览器数据可共享
- cookies
async 与 await
- 一个函数若是前面添加了 async 则当前函数返回的则为一个 Promise
- async 和 await是 对于异步操作的解决方案,它是Generator(生成器)函数的语法糖
- async|await是编写异步的新方法,之前ES6中用的是promise。
- async|await是建立在promise基础之上的新写法。
- async|await也是非阻塞的
- async 与 await 的优点
- async|await解决了回调地狱的问题
- async|await支持并发执行
- async|await对异步处理更加简洁
- async|await可以在try…catch中捕获错误
- async 与 await 的缺点
- await将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了await会导致性能上的降低
箭头函数
- 可以改变this的指向
- 箭头函数不具有arguments
- 箭头函数没有原型属性
- 就是当参数为一个的时候,可以省略()
- 当事件处理函数为一条语句的时候,可以省略retrun 和 {}
数组的方法
数组es6
- find 查找数组之中是否符合条件的值,若是符合则返回当前符合条件的数据
- 可以return ( 也就是当前所筛选的条件 )
- findIndex 找出满足条件的第一个元素,返回当前符合条件的下标
- 可return ( 也就是当前所筛选的条件- 下标 )
- Array.from 把可遍历的数组,转换为真实数组
- Array.of 把值转换为数组
- includes 判断数组里面是否包含有符合条件的元素,返回Boolean
- flat 数组的平铺,把二维数组等平铺为一维数组
- replaceAll 字符串的全局匹配与替换
- trim trimStart trimEnd 去掉空格
数组es5
-
forEach遍历循环
- 不能return 值
- 不会影响原始数组,只是单纯的遍历
-
map 遍历数组,对数据进行加工后,返回一个新的数组
- 可以return 值 (所return是所加工后的数据)
- 不会影响原始数组,只是在原始数据提供的数据进行加工,返回新数组
-
filter 过滤掉符合条件的数据,返回一个新的数组
- 可以return 值 ( 所return就是所过滤的符号数据 )
-
some 满足一个条件则返回一个true,否则全不满足,则为flase
-
eveny 满足所有条件则返回一个true,否则有一个不满足,则为flase
-
reduce
reduce((sum,item)=>{…},0)要有两个参数,第一个参数一定要初始化 let arr = [{name:‘张三’,index:0},{name:‘李四’,index:1}]; let result = arr.((array,item)=>{ array.push(item.name) return array;; },[ ]) 结果 result 为[‘张三’,‘李四’]
-
concat( ):数组合并
- concat() 方法不会更改现有数组。它总是返回一个新数组
-
join 数组转换为字符串
-
split 字符串转换为数组
-
push 向数组新增一个元素
-
pop 删除数组最后一个元素
-
unshift 向数组前面新增一个元素
-
shift 删除数组第一个元素
-
reserve 数组的翻转
-
sort 数组的排序
-
slice 数组元素的截取,返回一个新数组,新数组是截取的元素,可以为负值
-
splice 删除元素,并向数组添加新元素
-
substring 裁减数组元素
-
toString( ):数组转字符串;
-
注意点:那些会影响原始数组
- pop,push,unshift,shift,reverse,sort,splice
深拷贝 与 浅拷贝
深拷贝
- 深拷贝不仅仅拷贝外层的数据(栈存放的地址),还有拷贝的是(栈存放的地址 指向堆里面的数据)
- 思路
- 先遍历拷贝的对象,是否为数组,若为数组则递归遍历
- 若是为对象,也递归遍历
- 最后为简单数据的时候,直接把值写入
function deepCopy(obj) {
// 判断传递进来的是 数组还是对象
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj[key] && typeof obj[key] === "object") {
newObj[key] = deepCopy(obj[key]);
} else {
// 没有子元素 简单数据类型
newObj[key] = obj[key];
}
}
// console.log("newObj", newObj);
return newObj;
}
let obj = {
id: 1,
name: "lala",
msg: {
age: 20,
},
color: ["red", "pink", "yellow"],
};
let resObj = deepCopy(obj);
resObj.id = 2
resObj.msg.age = 30
resObj.color[1] = 'pink222'
console.log('obj',obj);
console.log("resObj", resObj);
- 结果
浅拷贝
- 浅拷贝就是拷贝的是外面的一层数据,就是拷贝栈里面存放的地址
let obj = {
id: 1,
name: "pink",
msg: {
age: 18
}
}
let o = {}
for (let k in obj) {
// k为属性名 obj[k]为属性名 直接把属性值拷贝给另一个对象
o[k] = obj[k];
}
console.log(o); //{id: 1, name: "pink", msg: {…}} age=18
obj.msg.age = 30;
console.log(o);
console.log(obj);
事件冒泡和事件捕获
- 事件的阶段:捕获阶段 - 当前目标阶段 - 冒泡阶段
- 事件冒泡
- 事件触发点,逐层向上触发同一类型的事件,直到document才停止
- 事件捕获
- 从document逐层向下捕获事件,直到当前事件触发点( 当前目标阶段 )
- 阻止事件冒泡
- e.stopPropagation()
- cancelBubble = true
- return false
- 阻住默认事件
- event. preventDefault()
- 冒泡事件之事件委托
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
闭包
- 原理
- 在函数外部,调用操作函数,函数内部的数据
- 在函数内部,return了一个函数,内层的函数,使用了外层的变量,使之这个变量由局部变量(局部作用域)变为自由变量(具有全局性)
- 也就是说,延申了变量的作用域
- 优点
- 延申了变量的作用域,使之变量原本处于函数内的作用域变为 一个自由变量( 任意时间内被调用,不会被销毁 )
- 缺点
- 过度的使用闭包可能会导致内存占用过多
数组es5、es6去重
es6去重
- Array.from配合 new Set 去重简单数据的数组
const arr = [1, 2, 3, 3, 4, 4];
const newArr = Array.from(new Set(arr));
console.log("newArr", newArr);
es5去重
- 简单数据类型
const arr = [1, 2, 3, 3, 4, 4];
const newArr = []
arr.forEach((item,idx)=>{
if ( newArr.indexOf(arr[idx]) === -1) {
newArr.push(arr[idx])
}
})
console.log('newArr',newArr); // [1, 2, 3, 4]
数组里面包含对象
let person = [
{ id: 0, name: "小明" },
{ id: 1, name: "小张" },
{ id: 2, name: "小李" },
{ id: 0, name: "小明" },
];
let obj = {};
let newPerson = [];
newPerson = person.reduce((cur, next) => {
obj[next.id] ? "" : (obj[next.id] = true && cur.push(next));
return cur;
}, []);
console.log("newPerson", newPerson);
// newPerson [ { id: 0, name: "小明" },{ id: 1, name: "小张" },{ id: 2, name: "小李" }, ]
冒泡排序
- 原始数组,在开辟一个新的数组,与初始数组相互比较,于是需要双for循环。
- 双重for循环,在内层for循环之后,arr[j] 与 arr[j+1] 进行比较,若是前面一项的值大于后面一项的值,则采用临时变量交换法,把两个值交换过来即可。
<script>
var arr = [5, 76, -8, 23, -15, 88, 47];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(arr);
</script>
适配 rem布局等
rem布局 ( r也就是根标签 - html)
-
原理
- html之中设置font-size为16px,则
- rem的大小是随着根元素html中的font-size的大小变化而变化
-
echarts 怎么适配
- 使用rem的设置盒子的宽高、然后echarts监听resize 方法,去实现echarts的响应式