HTTP协议各版本差异以及图示_http协议版本_阿汤哥的程序之路的博客-CSDN博客
Vue3 性能比Vue2好的原因(diff算法优化、静态提升、事件侦听器缓存)
在Vue2.0当中,当数据发生变化,它就会新生成一个DOM树,并和之前的DOM树进行比较,找到不同的节点然后更新。但这比较的过程是全量的比较,也就是每个节点都会彼此比较。但其中很显然的是,有些节点中的内容是不会发生改变的,那我们对其进行比较就肯定消耗了时间。所以在Vue3.0当中,就对这部分内容进行了优化:在创建虚拟DOM树的时候,会根据DOM中的内容会不会发生变化,添加一个静态标记。那么之后在与上次虚拟节点进行对比的时候,就只会对比这些带有静态标记的节点。
静态提升 hoistStatic
Vue3中使用了静态提升后,对于不参与更新的元素,只会被创建一次,在渲染时直接复用即可:
事件侦听器缓存 cacheHandlers
默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化,但是因为是同一个函数,所以没必要去追踪它的变化,想办法将它直接缓存起来复用就会提升性能。
继承的多方式:
原型链继承:
prototype
问题:引用类型的属性被所有实例共享
构造函数:
function Parent (name) {
this.name = name;
}
function Child (name) {
Parent.call(this, name);
}
var child1 = new Child('kevin');
优点:
1.避免了引用类型的属性被所有实例共享
2.可以在 Child 中向 Parent 传参
缺点:
方法都在构造函数中定义,每次创建实例都会创建一遍方法
组合继承:
原型链继承和构造函数继承结合
原型式继承
function createObj(o) {
function F(){}
F.prototype = o;
return new F();
}
缺点:
包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。
寄生式继承
function createObj (o) {
var clone = Object.create(o);
clone.sayName = function () {
console.log('hi');
}
return clone;
}
寄生组合式继承
虚拟dom中key的作用:
key是dom的标识,当状态中的数据发生变化,react会根据[新数据生成新的虚拟DOM] 随后React进行[新虚拟DOM]与[旧虚拟DOM]的diff比较,比较规则如下:
旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变。直接使用之前的真实DOM
(2).若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到到页面
用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序刷除等破坏顺序操作:会产生没有必要的真实DOM更新==>界面效果没问题,但效率低。
2. 如果结构中还包含输入类..... 会产生错误DOM更新==>界面有问题。
3.最好使用每条数据的唯一. 标识作为key。
本地存储(存储token):
http是无状态的,那么就没办法记录用户的状态,比如是否登录。
token:对用户名密码加密得到的
本地存储不能跨域传递
本地存储任一页面都能取值
本地存储不能存对象(转字符串)
sessionStorage(5M):
- sessionStorage.setItem("token","123456") 存值
- console.log(sessionStorage.getItem("token"))取值
- localStorage.removeItem("token") 删除
- localStorage.clear()
- 浏览器关闭,取消
localStorage(5M):
- localStorage.setItem("token","123456")
- console.log(sessionStorage.getItem("token"))
- sessionStorage.removeItem("token")
- sessionStorage.clear()
- 永久有效,除非自己主动清除localStorage信息。
cookie(4K):
- 规定时间内有效,
- 每次把请求的数据发送到服务器
- 有个数限制(各浏览器不同),一般不能超过20个
- https://www.runoob.com/js/js-cookies.html
session
- session是保存在服务端的
- session的运行依赖sessionId,而sessionId又保存在cookie中,所以如果禁用的cookie,session也是不能用的,不过硬要用也可以,可以把sessionId保存在URL中
- session一般用来跟踪用户的状态
- session 的安全性更高,保存在服务端,不过一般为使服务端性能更加,会考虑部分信息保存在cookie中
Vue的性能优化有哪些
- 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用
- 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- key保证唯一
- 使用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 图片懒加载<img v-lazy="/static/img/1.png">
- 变量本地化const base = this.base // 不要频繁引用this.base
BFC 原理
具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素
触发 BFC
- body 根元素
- 浮动元素:float 除 none 以外的值
- 绝对定位元素:position (absolute、fixed)
- display 为 inline-block、table-cells、flex
- overflow 除了 visible 以外的值 (hidden、auto、scroll)
同一个 BFC 下外边距会发生折叠
BFC 可以包含浮动的元素(清除浮动)
BFC 可以阻止元素被浮动元素覆盖
[] == ! [] 的结果为什么会是true
js数组的reduce
计算数组中每个元素出现的次数
let arr = ['name', 'age', 'long', 'short', 'long', 'name', 'name']
let arrResult = arr.reduce((pre, cur) => {
console.log(pre, cur)
if (cur in pre) {
pre[cur]++
} else {
pre[cur] = 1
}
return pre
}, {})
console.log(arrResult)
去除数组中重复的元素
let arrResult = arr.reduce((pre, cur) => {
if (!pre.includes(cur)) {
pre.push(cur)
}
return pre;
}, [])
console.log(arrResult)
盒模型
如何实现元素居中
//第一种
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
//第二种
display: flex;
align-items: center;
flex-direction: column
//第三种
//给父元素添加 position: relative;相对定位。
//给自身元素添加position: absolute;绝对定位。
//top: 50%;使自身元素距离上方“父元素的50%高度”的高度。
//left: 50%;使自身元素距离上方“父元素的50%宽度”的宽度。
//transform: translate(-50%,-50%);使自身元素再往左,往上平移自身元素的50%宽度和高度。
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
垂直居中
水平居中:
text-align: center;
margin: 0 auto;
left:50%;margin-left: -元素宽度的一半px; 或者设置transform: translateX(-50%);
display: flex; justify-content: center;
三种减低⻚⾯加载时间的⽅法
for in 循环和for of循环的区别
for-in是ES5标准,遍历的是key(可遍历对象、数组或字符串的key);
for-of是ES6标准,遍历的是value(可遍历对象、数组或字符串的value)
事件委托/事件代理
利用事件的冒泡传播机制(触发当前元素的某一个行为,它父级所有元素的相关行为都会被触发),如果一个容器中有很多元素都要绑定点击事件,我们没有必要一个个的绑定了,只需要给最外层容器绑定一个点击事件即可
线程和进程
线程是最小的执行单元,进程是最小的资源管理单元
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(一般情况)
一个进程对应多个线程最为常见,Linux、Windows等是这么实现的.其实理论上这种关系并不是一定的,可以存在多个进程对应一个线程,例如一些分布式操作系统的研究使用过这种方式,让线程能从一个地址空间转移到另一个地址空间,甚至跨机器调用不同的进程入口
如何实现数组扁平化
什么是数组扁平化?
[‘a’,‘b’,‘c’] //这是一个拥有3个元素的数组,是一个一维数组(不存在数组嵌套)。[[‘a’,‘b’],[‘c’,‘d’],[‘e’,‘f’]] 从整体上看是一个数组,但是其中的元素又是数组,即数组中嵌套数组,这就是二维数组
以此类推·····
[‘a’,[‘b’,[‘c’]]]//3维数组 [‘a’,[‘b’,[‘c’,[…]]]]//n维数组 数组扁平化就是把多维数组转化成一维数组。
通过es5递归实现
let result = [];
function fn(ary) {
for(let i = 0; i < ary.length; i++) }{
let item = ary[i];
if (Array.isArray(ary[i])){
fn(item);
} else {
result.push(item);
}
}
}
es6 +reduce+递归实现
let arr=[[1,2,3],4,5,[6,7,[8,9]]];
function bianping(arr){
return arr.reduce((res,item) =>{
return res.concat(Array.isArray(item)?bianping(item):item)
},[])
}
console.log(bianping(arr));
js中的深拷贝和浅拷贝
深拷贝递归地复制新对象中的所有值或属性,而浅拷贝只复制引用关系。
在深拷贝中,新对象中的更改不会影响原始对象,而在浅拷贝中,新对象中的更改,原始对象中也会跟着改。
在深拷贝中,原始对象不与新对象共享相同的属性,而在浅拷贝中,它们具有相同的属性。
slice方法和concat方法可以实现普通数组的深赋值,但是如果是二维数组就无法深复制object.assigin() //该方法在只有一层时,进行的是深拷贝
下面这个例子证明slice无法真正实现深复制
var arr1=[1,2,3,['1','2','3']];
var arr2=arr1.slice(0);
arr1[3][0]=0;
console.log(arr1);//[1,2,3,['0','2','3']]
console.log(arr2);//[1,2,3,['0','2','3']]
如何实现深拷贝:
1.JSON.stringfy JSON.parse
var arr1 = ['red','green'];
var arr2 = JSON.parse(JSON.stringify(arr1));//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]
2.递归
function deepClone(obj){
//判断参数是不是一个对象
let objClone = obj instanceof Object?{}:[];
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
var a ={
x:1,
y:2
};
b=deepClone(a);
a.x=3
console.log(a);
console.log(b);
3.ES6扩展运算符
4.jqery里面的extend方法:
var b = $.extend(true, {}, a);
// 第一个参数true为深拷贝,第二个参数为目标对象,第三个参数为源对象
JS是单线程的,那么JS是如何实现并发请求的?
因为有消息队列和事件循环的存在。
消息队列指的是一个先进先出的队列,在这个队列中可以存在各种消息。
事件循环指的是主线程重复从消息队列中获取消息、执行的过程。
js中的event loop(事件循环)
js作为单线程语言。所有的任务可以分为两种,一种是同步任务,另外一种是异步任务。
同步任务指的是,在主线程上,排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程,而进入“任务队列”(task queue)的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
异步任务分类为宏任务(macro-task)和微任务(micro-task)。
宏任务:整体的Script setTimeout setInterval
微任务:Promise.then process.nextTick
注意:Promise是同步任务
有微则微,无微则宏
setTimeout(function(){
console.log('1')
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3')
});
console.log('4');
new Promise(function(resolve){
console.log('5');
resolve();
}).then(function(){
console.log('6')
});
setTimeout(function(){
console.log('7')
});
function bar(){
console.log('8')
foo()
}
function foo(){
console.log('9')
}
console.log('10')
bar()
setTimeout(() => {
console.log('1');
new Promise(function (resolve, reject) {
console.log('2');
setTimeout(() => {
console.log('3');
}, 0);
resolve();
}).then(function () {
console.log('4')
})
}, 0);
console.log('5'); //5 7 10 8 1 2 4 6 3
setTimeout(() => {
console.log('6');
}, 0);
new Promise(function (resolve, reject) {
console.log('7');
// reject();
resolve();
}).then(function () {
console.log('8')
}).catch(function () {
console.log('9')
})
console.log('10');
console.log("AAAA");
setTimeout(() => console.log("BBBB"), 1000);
const start = new Date();
while (new Date() - start < 3000) {}
console.log("CCCC");
setTimeout(() => console.log("DDDD"), 0);
new Promise((resolve, reject) => {
console.log("EEEE");
foo.bar(100);
})
.then(() => console.log("FFFF"))
.then(() => console.log("GGGG"))
.catch(() => console.log("HHHH"));
console.log("IIII");
//输出结果:
AAAA
CCCC
EEEE
IIII
HHHH
BBBB
DDDD
原型链污染
在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。这种攻击方式就是原型链污染。
> var a = {admin:1}
undefined
> a.admin
1
> a.__proto__.admin = 2
2
> var b = {}
undefined
> b.admin
2
计算结果:
let a={n:1}
let b=a;
a.x=a={a:2}
console.log(a.x)
console.log(b.x)
点的优先级大于=,new的优先级
{n:1,x:undefined}.x={n:2}
var a=10;
var foo={
a:20,
bar:function(){
var a=30;
return this.a
}
}
console.log(foo.bar())
console.log((foo.bar)())
console.log((foo.bar=foo.bar)())
console.log((foo.bar,foo.bar)())
括号改变运算顺序
经过赋值运算后都为函数,并非对象的引用
var tmp = 2;
var obj = {
tmp: 3,
fn() {
this.tmp *= 2
tmp *= 2;
console.log(1, tmp)
console.log(2, this.tmp)
}
}
var func = obj.fn
func()
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end")
}
async function async2() {
console.log("async2")
}
console.log("script start")
setTimeout(function () {
console.log("setTimeout")
}, 0);
async1();
new Promise(function (resolve) {
console.log("promise 1");
resolve();
}).then(function () {
console.log("promise 2")
})
console.log("script end")
function Foo(){
getName=function(){alert(1)}
return this
}
Foo.getName =function(){alert(2)}
Foo.prototype.getName=function(){alert(3)}
var getName=function(){
alert(4)
}
function getName(){
alert(5)
}
Foo.getName()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
数组去重
//数组去重
function repetition1(arr){
for(var j=0;j<arr.length-1;j++){
for(var i=j+1;i<arr.length;i++){
if(arr[j]==arr[i]){
arr.splice(i,1)
i--
}
}
}
console.log(arr)
}
function repetition2(arr){
var arr1=[];
arr.map(function(item1,index){
if(arr1.indexOf(arr[index])==-1){
arr1.push(arr[index])
}
})
console.log(arr1)
}
function repetition3(arr){
for(var i=0;i<arr.length-1;i++){
for(var j=arr.length;j>i;j--){
if(arr[i]==arr[j]){
arr.splice(j,1)
}
}
}
console.log(arr)
}
function repetition5(arr){
var arr1=arr.filter(function(item,index){return arr.indexOf(item)===index})
console.log(arr1)
}
var arr=[45,23,666,45,88,00,66,23,66,66,666,"你","天使","你","e","w"];
console.log([...new Set(arr)])
1、for+splice
2、set
3、indexof
4、filter+indexof
类数组-->数组
1、Array.from
2、Array.prototype.slice.call()
3、[...x]
4、Array.prototype.concate.apply([],arraylike)
防抖和节流(响应跟不上触发频率)
防抖:
防抖动是将多次执行变为最后一次执行
- 搜索框搜索输入。只需要用户最后一次输入完再发送请求
- 手机号、邮箱格式的输入验证检测
- 窗口大小的 resize 。只需窗口调整完成后,计算窗口的大小,防止重复渲染。
<script>
function debounce(callback,delay){
var t=null
return function(){
clearTimeout(t)
t=setTimeout(callback,500)
}
}
window.onscroll=debounce(function(){
console.log(1)
},500)
</script>
节流:
节流是将多次执行变成每隔一段时间执行。
- 滚动加载,加载更多或滚动到底部监听
- 谷歌搜索框,搜索联想功能
- 高频点击提交,表单重复提交
- 省市信息对应字母快速选择
<script>
function debounce(callback,delay){
var t=new Date().getTime()
return function(){
var n=new Date().getTime()
if(n-t>delay){
callback();
t=n;
}
}
}
window.onscroll=debounce(function(){
console.log(1)
},500)
</script>
function throttle(fn) {
let canRun = true;
return function () {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn()
canRun = true;
}, 500);
};
}
window.addEventListener('resize', throttle(function(){
console.log('节流');
}));
原型与继承、原型链
只有函数才有原型,原型是用来存放共有属性的,原型是一个属性,它的值是个对象
每一个对象都有一个__proto__(隐式原型)的属性,这个属性指向创建该对象的构造函数的prototype(如果不能确定他是谁的实例,都是Object的实例)
原型链:对象实例的隐式原型指向创建改对象的构造函数的原型对象,这样一层一层的指向关系形成的链叫原型链。
垃圾回收机制:
垃圾回收:JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。
标记清除 标记整理清除 引用清除 复制整理
减少垃圾回收
- 对数组进行优化:在清空一个数组时,最简单的方法就是给其赋值为[ ],但是与此同时会创建一个新的空对象,可以将数组的长度设置为0,以此来达到清空数组的目的。
- 对
object
进行优化:对象尽量复用,对于不再使用的对象,就将其设置为null,尽快被回收。 - 清除定时器
- dom引用
- 闭包。
Javascript中 callee和 caller 的作用?
callee是函数arguments对象内的指针,它指向当前的函数,使得在函数内部递归调用当前函数时,不需要调用函数名称,减少函数内部对于函数名的依赖
caller是函数的一个属性,它指向调用当前函数的函数,如果当前函数在其他函数内被调用,则返回调用它的那个函数,如果是在全局环境下被调用,则返回 null
我们可以利用caller的特性跟踪函数的调用链
http常见的状态码有那些?分别代表是什么意思?
http由请求头和请求体组成
1xx : Hold on (等着)
2xx : Here you go (执行完了,没毛病,拿着结果回去吧)
3xx : Go away (你要的不在我这儿,去别处找)
4xx : You fucked up (你丫出问题了)
5xx : I fucked up (我特么出问题了)
200 OK 服务器成功处理了请求(这个是我们见到最多的)
304 Not Modified:服务端的资源与客户端上一次请求的一致,不需要重新传输,客户端使用本地缓存的即可
400 Bad Request:用于告诉客户端它发送了一个错误的请求
404 Not Found (页面丢失) 未找到资源
500 Internal Server Error:服务器内部出现了错误
501 Internal Server Error 服务器遇到一个错误,使其无法对请求提供服务
写 Vue 项目时为什么要在列表组件中写 key,其作用是什么?
- 第一种情况是 v-if 中使用 key。使用 key 的元素不会被复用。
- 第二种情况是 v-for 中使用 key。高效的实现复用。diff 操作可以更准确、更快速
不能用index和random
diff算法通过tag和key判断是否是sameNode
减少渲染次数,提高渲染性能
var,let和const之间的区别
块级作用域:块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES5中的两个问题:
内层变量可能覆盖外层变量
用来计数的循环变量泄露为全局变量
变量提升:var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否则会报错。
重复声明:var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的变量。const和let不允许重复声明变量。
暂时性死区:在代码块内,使用let命令声明变量之前,该变量不可用。这在语法上,称为暂时性死区。
初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
指针指向:let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。
const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。
对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。
但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的。
箭头函数和普通函数的区别:
a. 箭头函数和普通函数的样式不同,箭头函数语法更加简洁、清晰,箭头函数是=>定义函数,普通函数是function定义函数。
b. 箭头函数定义的时候this值就确定了,永久不变。
c. 箭头函数不能作为构造函数使用,也不能使用new关键字
d. 箭头函数没有自己的arguments。
e. call、apply、bind 并不会影响其 this 的指向。
f. 箭头函数没有原型prototype。
g.箭头函数不会函数提升
面向对象和面向过程的区别
面向对象=》 组件(方法1,方法2,方法3)
面向过程=》 顺序
this指向
ES5: 谁调用指向谁,方式不同指向不同
ES6:无this向
function Person(name){
this.name=name //Person
console.log(this)
}
let p=new Person();
let obj={
print:Person
}
Person() //window
obj.print() //object
setInterval(Person,5000) //window
Person.call(document) //document
new:
var obj={}
//_this=obj
this.name=name
return obj
箭头函数:当箭头函数不存在,找this
eval("var a=1;alert(a)")动态运行代码
少用,安全问题
eval 全局作用域
"use strict" eval产生自己的作用域
依次输出123456
for (let i = 0; i < 6; i++){
setTimeout(function(){
console.log(i)
},1000)
}
for (var i = 0; i < 6; i++) {
(function(i) {
setTimeout(function () {
console.log(i)
}, 1000)
})(i)
}
安全:
1、过滤特殊字符串
2、禁止拼接sql
3、innerText而非innerHtml
4、token验证
dom树:
vnode={
tag:
prop:{}
children:{}
}
get和post的区别
a. GET 是将参数写在 URL 中 ? 的后面,并用 & 分隔不同参数;Get是通过地址栏来传值,而Post是通过提交表单来传值。
b. GET请求提交的数据有长度限制,POST请求没有内容长度限制。
c. GET请求返回的内容会被浏览器缓存起来。而每次提交POST请求,浏览器不会缓存POST请求返回的内容。
d. GET对数据进行查询,POST主要对数据进行增删改!
e. 关于安全性,GET 请求方式从浏览器的 URL 地址就可以看到参数;所以post更安全,其实无论是 GET 还是 POST 其实都是不安全的,因为 HTTP 协议是明文传输,只要拦截封包便能轻易获取重要资讯。想要安全传输资料,必须使用 SSL/TLS来加密封包,也就是 HTTPS。
f. 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务端响应200,请求成功。
对于POST方式的请求,浏览器会先发送http header给服务端,告诉服务端等一下会有数据过来,服务端响应100 continue,告诉浏览器我已经准备接收数据,浏览器再post发送一个data给服务端,服务端响应200,请求成功。
g:get效率高!
1物理像素的实现
1、像素比=物理像素/css像素(px)
2.在移动中,不同设备其dpr即像素比不一样
通过操作meta标签上的缩放比
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
width: 100rem;/*用上相对单位 100rem相当于100px*/
border-bottom: 1px solid #666;
<script>
window.onload = function () {
//获取像素比
var dpr = window.devicePixelRatio;
//缩放比例
var scale = 1 / dpr;
//获取meta标签,设置缩放比
var metaNode = document.querySelector('meta[name="viewport"]');
metaNode.setAttribute('content', 'width=device-width, initial-scale=' + scale + ',user-scalable=no')
//将页面中元素的宽度,高度,反向乘回来
var htmlNode = document.querySelector('html');
htmlNode.style.fontSize = dpr + 'px';/*通过设置根元素字体大小*/
}
</script>
2,媒体查询
@media screen and (-webkit-min-device-pixel-ratio:2){
trandform:scalseY(0.5)
}
JavaScript代码的整个执行过程,分为两个阶段
代码编译阶段由编译器完成(词法分析,语法分析,可执行代码生成,作用域规则确定)
执行阶段由引擎完成(执行上下文创建,代码执行,垃圾回收)
执行上下文(execute context)EC
每当函数被调用,就会进入一个执行上下文。
- 全局环境:JavaScript代码运行起来会首先进入该环境
- 函数环境:当函数被调用执行时,会进入当前函数中执行代码
- eval
JavaScript引擎会以函数调用栈(call stack)的方式来处理它们,栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。处于栈顶的上下文执行完毕之后,就会自动出栈
执行上下文的生命周期可以分为两个阶段:
- 创建阶段
创建变量对象(Variable Object) 声明提升,为变量分配栈空间
建立arguments对象。。
函数声明,如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
变量声明,如果该变量名的属性已经存在,则会直接跳过,原属性值不会被修改。
建立作用域链
作用域链,是由当前环境与上层环境的一系列变量对象组成(单向通道),它保证了当前执行环境对符合访问权限的变量和函数的有序访问。
确定this的指向
未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。
- 代码执行阶段
变量赋值,
函数引用,
执行其他代码。
执行完毕后出栈,等待被回收
内存空间管理
JavaScript的内存生命周期
1. 分配你所需要的内存
2. 使用分配到的内存(读、写)
3. 不需要时将其释放、归还(null)
函数声明会覆盖变量声明;
立即调用的函数表达式有一个独立的作用域,函数名称与内部变量名冲突,永远指向函数本身;
网络OSI七层模型都有哪些?
- 应用层
- 表示层
- 会话层
- 传输层(TCP)
- 网络层
- 数据链路层
- 物理层
http1.0和http1.1,还有http2有什么区别
- http0.9只能进行get请求
- http1.0添加了POST,HEAD,OPTION,PUT,DELETE等
- http1.1增加了长连接keep-alive,增加了host域,而且节约带宽
- http2 多路复用,头部压缩,服务器推送
http和https的区别
超文本传输协议,由请求头和请求体组成
http:明文 快 tcp三次连接(3个包)
https:ssl(数字证书)+http(3+9)个包
http无状态无连接,而且是明文传输,不安全
https传输内容加密,身份验证,保证数据完整性
https实现原理⭐⭐⭐⭐⭐
首先客户端向服务端发起一个随机值,以及一个加密算法
服务端收到后返回一个协商好的加密算法,以及另一个随机值
服务端在发送一个公钥CA
客户端收到以后先验证CA是否有效,如果无效则报错弹窗,有过有效则进行下一步操作
客户端使用之前的两个随机值和一个预主密钥组成一个会话密钥,在通过服务端传来的公钥加密把会话密钥发送给服务端
服务端收到后使用私钥解密,得到两个随机值和预主密钥,然后组装成会话密钥
客户端在向服务端发起一条信息,这条信息使用会话秘钥加密,用来验证服务端时候能收到加密的信息
服务端收到信息后返回一个会话秘钥加密的信息
都收到以后SSL层连接建立成功
tcp 和udp有什么区别⭐⭐⭐⭐⭐
连接方面
tcp面向连接,udp不需要连接
tcp需要三次握手四次挥手请求连接
可靠性
tcp是可靠传输;一旦传输过程中丢包的话会进行重传
udp是不可靠传输,但会最大努力交付
工作效率
UDP实时性高,比TCP工作效率高
因为不需要建立连接,更不需要复杂的握手挥手以及复杂的算法,也没有重传机制
是否支持多对多
TCP是点对点的
UDP支持一对一,一对多,多对多
首部大小
tcp首部占20字节
udp首部占8字节
什么是xss?什么是csrf?⭐⭐⭐⭐⭐
xss脚本注入
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、hmtl代码块等)。
防御
编码:对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
过滤:移除用户输入的和事件相关的属性。
csrf跨域请求伪造
在未退出A网站的前提下访问B,B使用A的cookie去访问服务器
防御:token,每次用户提交表单时需要带上token(伪造者访问不到),如果token不合法,则服务器拒绝请求
['1', '2', '3'].map(parseInt):
其中第一个参数代表当前被处理的元素,而第二个参数代表该元素的索引。
-
而parseInt则是用来解析字符串的,使字符串成为指定基数的整数。
parseInt(string, radix)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
- parseInt('1', 0) //radix为0时,且string参数不以“0x”和“0”开头时,按照10为基数处理。这个时候返回1
- parseInt('2', 1) //基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN
- parseInt('3', 2) //基数为2(2进制)表示的数中,最大值小于3,所以无法解析,返回NaN
-
map函数返回的是一个数组,所以最后结果为[1, NaN, NaN]
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];编写一个程序将数组扁平化去并除其中重复部分数据,最终得到一个升序且不重复的数组
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})
arr.toString().split(",").sort((a,b)=>{ return a-b}).map(Number)
var flatArr = arr.toString().split(",");//扁平化