CSS 常考题
盒模型
标准盒模型:width=content allWidth=content+padding+border+margin
变异盒:width = content+padding+border allWidth=content+padding+border+margin
水平垂直居中
1. display:flex;
justify-content:center;
align-items:center;
2. position:absolute;
top:0;
right:0;
left:0;
bottom:0;
margin:auto;
3. position:absolute;
left:50%; top:50%;
margin-left:-25%;
margin-top"-25%;
4. position:absolute;
top:50%;
left:50%;
tansform:tanslate(-50%,-50%)
ES6
Set WeakSet Map WeakMap
set 它类似于数组,但是成员的值都是唯一的,没有重复的值
const arr=[1,1,2,2,3,4,5,5]
const a=new Set(arr) a //[1,2,3,4,5]
a.add(6) //[1,2,3,4,5,6]
a.delete(5) //[1,2,3,4,6]
a.has(1) //true
a.clear() //[]
new Set的数组是一个类数组,所以没有数组方法,但是可以使用 forEach,for of。
const b=Array.from(a,item=>item+1) //Array.from接收两个参数 第一个参数变成真正的数组 第二个参数 可以进行逻辑操作
output :b //[2,3,4,5,7]
weakSet跟set的区别 WeakSet 没有length 所以不能遍历
add delete has weakSet只能是对象 而不能是其他类型的值 其次,WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象, 那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中 。
Map 它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
const b=[['name':'詹丹'],['age':'18']] const a = new Map(b) b.get('name') b.set(o,'centent')
b.delete()
b.has(name) //true
b.size() //2
b.clear()//清除
Map.prototype.keys():返回键名的遍历器。
Map.prototype.values():返回键值的遍历器。
Map.prototype.entries():返回所有成员的遍历器。
Map.prototype.forEach():遍历 Map 的所有成员。
Map转为数组最快的方式使用扩展运算符
const arr=[1,'one',2,'two']
const map=new Map(arr)
[...map.key()]
[...map.values()]
[...map.entries()]
[...map]
WeakMap与Map的区别有两点。 首先,WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。 其次, WeakMap的键名所指向的对象,不计入垃圾回收机制 没有.length
函数柯里化
利用闭包,形成一个不销毁的私有作用域,把预先处理的内容存在这个作用域里面,并且返回一个函数,以后都要 执行这个函数。
例子:
function add(x){
return function(y){
return x+y }
}
const yaa=add(1) //在这时执行了 add 此时的x 为1 所以执行yaa就是执行里面的函数 形参为2 console.log(yaa(2)===3) //true
Event Loop的正确执行顺序
1.执行同步代码,这属于宏任务。
2.执行栈为空,查询是否有微任务要执行。
3.执行所有微任务。
4.必要的话渲染UI
5.然后开始下一轮的EventLoop 执行宏任务的异步代码
宏任务 setTimeout setInterval requestAnimationFrame
微任务 .then nextTick .then
axios怎么请求?
axios就是在ajax的基础上加上了promise
例子:
const axios={
get(){
return new Promise((resolve,reject)=>{
const xhr=new XhrHttpRequest()
xhr.open('GET',url,true)
xhr.onreadystateChange=function(){
if(xhr.readyState==4 && xhr.state==200){
resolve(xhr.responseText) }
}
xhr.send()
})
}
}
axios的请求拦截和响应拦截
请求拦截
axios.interceptors.request.use(function (config){
//在发送请求之前可以
//在请求时要添加hander的数据(token,后端加密的数据等 ,具体的看业务 ),会统一赋值给一个
变量比如(config) 在执行这个里面,在同一传给ajax,请求拦截器就是在执行ajax之前先执行请求
拦截器里面的内容。
return config
},function(error){
//对请求错误做些什么
//例:接口地址不对啦,可以进行message报错
return Promise.reject(error)
})
响应拦截
axios.interceptors.response.use(function(response){
//对响应拦截做出什么
//根据后端返回的状态码,进行判定是不是有token失效了,需要重新登录,或者根据后端返回的状态码进行其他的报错处理
return response
},function (error){
//响应拦截处理 //状态码为 404 || 500的时候做对应的message提示处理
return Promise.reject(error)
})
npm i 和npm install的区别
区别
1. npm i 安装的模块及依赖,使用npm uninstall是没有办法删除的,必须使用npm uninstall i才可以删除
2.npm i 会帮助检测与当前node最匹配的npm的版本号,并匹配出相互依赖的npm包应该升级的版本号
3.npm i 安装的一些包,在当前的node版本下是没有办法使用的,必须使用建议版本
4.npm i安装出现问题是不会出现npm-debug.log文件的,但npm install 安装出现问题是有这个文件的
前端安全(XSS,CSRF,SQL注入)
XSS攻击: 指的是攻击者向Web页面插入恶意HTML标签或者JS代码,比如,攻击者在论坛上放一个看似安全的链接,骗取用户单击,并窃取cookie中的用户隐私信息,或者攻击者在论坛上加一个表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是 用户本身信任的站点。
要防范XSS攻击 首先,在代码里对用户的输入,和变量都需要仔细检查长度和对“<>”";"',' 等这些字符做过滤,其次,在把任何内容写在页面之前都必须进行编码,避免泄露。 xss几种形式,防范手段,过滤哪些字符? 验证文本框输入特殊字符,一般 "alert","eval","<script>"、<iframe>",,"<img>",<style>、"onload","onfocus","onerror","onclick","
XSS的分类形式
反射型:发出请求是,XSS代码在url中,发送给服务端,服务端响应后,会随着相应内容发送给浏览器,最后浏览器解析XSS代码,这一过程叫做反射。
存储型:提交的代码会存储到服务器的数据库中,用户的浏览器接收到响应后解析执行。混在其中的代码也被执行。
DOM型:取出恶意的浏览器代码由浏览器端完成,这输入前端JS的漏洞,前两个都是服务端的
CSRF攻击: 是一种劫持受信任用户向服务器发送非预期请求的攻击方式。
原理及流程;
1.受害者登录A网站,并留下登录凭证。
2.攻击者引诱受害者登录B网站。 B向A发送请求。
3、A收到请求后,对请求进行验证,并确认受害者的凭证,误以为是受害者自己发送的请求。
4、A以受害者的名义执行了。 攻击完成,
攻击者以受害者的名义,完成了对A的操作
CSRF的分类形式
GET:
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
POST:
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form> <script> document.forms[0].submit();
链接类型的:
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank"> 重磅消息!! <a/>
XSS和CSRF的区别
1.XSS不需要登录。 CSRF需要用户先登录A,获取Cookie
2.XSS是向网站中注入JS代码,篡改原本网站A的内容。 CSRF利用网站A本身的漏洞,去请求A的api。
CSRF如何防御
1.Token验证:(用的最多) 服务端发送给客户端一个token 表单提交携带这个token 服务端验证token,如果token不合法,那么拒绝这个请求。
2.隐藏token,就是把token放在请求头中。跟方法一是一样的
3.Referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截 设置Referrer Policy的方法有三种:
1、在CSP设置 (content-security-policy) 内容安全策略
2、页面头部增加meta标签
<meta http-equiv="content-security-policy" content='font-action 'self';'>
3、a标签增加referrerpolicy属性
SQL注入: 就是通过把SQL命令插入到web表单的提交或者输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。 1.不信任用户的输入,可以通过正则或限制长度,对单引号或者下划线进行转换等。 2.始终不要使用动态拼装SQL 3.始终不要使用管理员权限的数据库的链接 4.不要把机密的信息用明文存放,应通过加密处理密码和敏感的信息。
浏览器中输入URL都发生了什么
一、解析URL
二、DNS解析(域名解析成对应的IP)
三、浏览器与网站建立TCP连接(三次握手)
第一次握手:客户端向服务器端发送请求(SYN=1) 等待服务器确认;
第二次握手:服务器收到请求并确认,回复一个指令(SYN=1,ACK=1);
第三次握手:客户端收到服务器的回复指令并返回确认(ACK=1)
四、请求和传输数据
五、浏览器渲染页面
MVVM MVC的区别(简单理解)
MVVM:model view viewModel
model和view本身并没有很大的联系是通过viewmodel建里联系的,model变化时 viewmodel会同步到view层,view发生变化时也会同步到model。
mvvm双向数据流 ,解决了mvc中大量的DOM操作,使页面的渲染能力降低,
MVC : model view control 单向数据流
js实现深拷贝的方式有哪些?
(110条消息) JSON.stringify和JSON.parse 优缺点 实现深拷贝的优缺点_Jack おう的博客-CSDN博客_json深拷贝的优缺点
JSON.parse(JSON.styingify()))
缺点:
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引用的对象
const obj={
例如: name:function(){}
test:\abc\ example:undefined
}
打印出来深拷贝都是空对象,会丢失 console.log(JSON.parse(JSON.stringify(obj))) // {}
lodash库 npm i --save lodash
<script> import _ from "lodash"
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); //false </script>
闭包
就是将函数内部和外部建立起来一座桥梁,可以把函数和变量脱离常规的作用去,进行套来套去使用。
优点:极大的拓宽了作用域,创建私有作用域,使里面的变量不会被回收掉。
缺点:浪费性能
节流防抖
节流:在一定时间内,在动作被连续触发的情况下,每隔一段时间只会执行一次
js:
function fn(){
console.log('你好世界')
}
function jieliu(fn,delay){
let status=true
return function(){
if(status){
status=false fn()
setTimeout(()=>{
status=true
},delay)
}else{
console.log('节流你好')
}
}
}
const hh=jieliu(fn,1000)
hh() //你好世界
hh() //节流你好
hh() //节流你好
hh() //节流你好
hh() //节流你好
防抖:在一定时间内,在动作被连续触发的情况下,只执行最后一次 \
js:
function fn(){
console.log('防抖函数')
}
function fangdou(fn,delay){
let status=true
return function (){
if(status){
status=false
setTimeout(()=>{
fn()
status=true
},delay)
}
}
}
const hh=fangdou(fn,1000)
hh() undefined
hh()
hh() //防抖函数
垃圾回收机制
定义:js中的垃圾正是,不再被需要的变量----就是垃圾
全局变量:全局变量存在被使用的可能性,所以不能当做垃圾
局部变量:函数执行完了变量当做垃圾清除 单引用,双引用,环引用,这三种情况下,只有将所有指向该变量的对象清除才能够将该变量作为垃圾处理
标记扫除算法: 就是从global或者window按照每一个的箭头开始寻找,如果变量被引用就√,没有就是x,最后清除x。 缺点:效率慢,每次都需要遍历,会拖慢js的的运行速度。
优化点:
分代垃圾回收:意思就是说,对于一些老的变量,可能之前引用过,后来清除或者怎么样的,每隔一段时间去遍历,但是对于一些新的变量,就会时刻标记清除。
增量执行:一次性不能全部遍历完,一次遍历个十分之一就可。 空余时间执行:在js代码执行完成之后,在进行标记清除。
引用计数: 使用计数器,在每个对象进行删除,引用,新建时更新计数,如果数为0,就直接回收。 优点: 及时回收垃圾, 最大暂停时间短, 不用去一步一步遍历 缺点: 循环引用无法回收 耗费性能,计数器需要站位,实现起来繁琐
new操作符做了什么
1.新建一个对象
2.使这个对象的__proto__指向该对象的prototype
3.改变this
4.return这个对象
assets文件和static文件的区别
共同点,他们都是存放静态文件的地方 但是,项目在打包的时候会把assets文件进行压缩,最后放到static里面,最后部署到服务器上,但是static文件在打包的时候就不会进行压缩,可能就会导致体积过大。
解决办法:assets文件可以放插件的css,js文件没有压缩过的,static文件里面可以压缩过的,这样打包的时候就可以叫减少体积。
单页面和多页面的区别
单页面: 像现在的框架都是单页面应用,初次进入页面时会请求一个html文件,切换到其他组件的时候,只是路径发生了变化,并没有其他的请求。
原理:js动态感知url的变化,会动态的删除或者新增页面,这时的路由都是前端来做的,不是后端了。
优点:页面切换快。
缺点:不利于seo引擎的抓取(因为html都是js动态生成的,seo只抓取html的文件) 首屏加载速度慢(需要发送两次请求,html文件请求,js请求)
多页面: 每次加载页面都是请求后端的html文件
优点:首屏加载快(只需要经历一次的http请求) 有利于seo引擎的抓取
缺点:切换页面慢(每次跳转都需要请求)
vue响应式的原理
当一个vue的实例创建的时候,vue会遍历data中所有的选项,并用object.definepropery把他们转为getter和setter并在内部追踪相关依赖,在属性被访问和修改时通知变化,每个组价实例都有watcher属性,当seter调用时,watcher会重新计算,通知组件得以更新
js 构造函数和普通函数的区别
this指向:
构造函数指向new出来的对象
普通函数:指向window
作用: 构造函数用来新建实例对象
调用方式不一样:
普通函数直接调用 构造函数需要new操作符,在进行调用
Promise(定义,.all, .race)
定义:promise是一个异步的解决方案,是用来解决回调地狱的问题,导致代码的可读性非常差,维护起来非常的困难,.then用来接收回调成功的数据,里面有两个参数,resolve和reject,resolve是接收成功的回调,reject是接收失败的回调,async await 是一种语法糖, .then多了之后,也会造成回调地狱的问题,async await 使语法更加的扁平化,更美观。
promise.all:
是可以将多个promise实例包裹成一个数组,成功则是返回一个数组,失败是,返回最先失败的值
const p1=new Promise((resolve,reject)=>{
resolve('你好p1')
})
const p2=new Promise((resolve,reject)=>{
resolve('你好p2')
})
const p3=new Promise((resolve,reject)=>{
reject('我失败了')
})
Promise.all([p1,p2]).then(res=>{
console.log(res) //['你好p1', '你好p2']
})
Promise.all([p1,p2,p3]).then(res=>{
console.log(res)
}).catch(err=>{
console.log('失败了',err) //失败了 我失败了
})
promise.race 谁先返回的快,就返回快的值
const p1=new Promise((resolve,reject)=>{
resolve('你好p1')
})
const p2=new Promise((resolve,reject)=>{
resolve('你好p2')
})
Promise.race([p1,p2]).then(res=>{
console.log(res) //你好p1
})
js 数组方法
toString() 将数组通过','转为字符串
join() 将数组通过指定分隔符转为字符串
pop() 删除数组首位
返回值:删掉的数据
shift() 删除数组末位
返回值:删掉的数据
unshift() 数组首位开始添加
返回值:新数组的长度
push() 数组末位开始添加
返回值:新数组的长度
splice() 删除并替换
参数1:开始删除或替换的索引
参数2:删除的个数
参数3,需要添加的数据
返回值:删除的数组
concat() 合并数组
返回值:合并之后的新数组
slice() 截取
参数1:开始截取的数组的索引
参数2:截取结束的数组索引(不包括最后一个)
返回值:截取之后的新数组
sort() 排序
.sort((a,b)=> a-b) 升序
.sort((a,b)=> b-a) 降序
reverse() 翻转数组
当a等于? 可以打印a
a==1 && a==2 && a==3 的三种解法 - 掘金
let a={
n:1,
valueOf:function(){
return this.n++
}
}
if(a==1&&a==2&&a==3){
console.log(a) //
}
let obj={
valueOf:function(){
return 1;
}
}
console.log(obj==1)
因为两端的类型不一样,会先转成原始类型,就会把{}转为1,(转换规则,先调用对象的valueOf的方法,
如果转不成在调用tostring()的方法)//string就是原始类型
原生js-new Array
new Array 方法
const arr=new Array(2) //一个参数:创建一个数组 内容为空值 [, ,]
new Array(2,3) //两个参数:相当于字面量创建 [2,3]
遇到的笔试题:
const arr=new Array(2)
arr[6] = 2
console.log(arr.length) // 7
arr.shift()
console.log(arr) // [ , , , , , 2]
arr.splice(5,1,3)
console.log(arr) // [ , , , , , 3]
原生js-变量提升
用var声明的变量(包括函数表达式),只提升声明,不提升赋值操作
alert(a) //undefined
var a = 1
提升之后的代码
var a //声明一个变量,但是没有初始化
alert(a) //undefined
a=1
--------
fn() //在c语言,要先声明函数,在调用
function fn(){
console.log('你好世界')
}
提升后
function fn(){
console.log('你好世界')
}
fn()
----------
多个函数同名提升规则: 都提升,但是后面的函数会覆盖掉前面函数
func1(); //输出 我是后声明的函数
function func1(){
console.log('我是先声明的函数');
}
function func1(){
console.log('我是后声明的函数');
}
-----------
模拟提升后的代码
function func1(){
console.log('我是先声明的函数');
}
function func1(){
console.log('我是后声明的函数');
}
func1();
函数名也是变量,后面的会覆盖前面。
--------------------
变量名和函数名相同提升规则:如果有变量和函数同名,会忽略掉变量,只提升函数
alert(fn)
function fn(){
}
var fn=12
alert(fn)
----------
模拟提升后的代码
function fn(){
}
alert(fn) //fn 函数
var fn=12
alert(fn) //12
-------------------
变量提升分作用域
var num=10
function test(){
console.log(num)
var num=1
}
test()
模拟代码
var num
num = 1
function test(){
var num
console.log(num) //函数内部声明了num,但是没赋值。因为在函数内部声明了num,所以函数会使用它内部声明的num,而不会去全局中找
var num=1
}
test() //undefined
---------
函数表达式不会提升
fn() //fn is not a function
var fn=function (){
console.log('你好世界')
}
模拟提升之后
var fn
fn()
fn=fucntion(){
console.log('你好世界')
}
原生js-对象的引用
总结:只操作(修改,删除,添加)对象的属性,不会与之前的对象断开链接
直接操作对象本身,就是 { }的外层,会和之前的对象断开链接
const a='哈哈'
const b='哈哈'
console.log(a===b)// true
const a={}
const b={}
console.log(a===b) //false
let a={z:5,y:9}
let b =a
b.z=6
delete b.y
b.x=8
console.log(a) // {a:6,x:8}
console.log(a===b) //true
let a={z:5,y:{x:8},w:{r:10}}
let b={...a}
b.z=6
b.y.x=9
b.w={r:11}
console.log(a) //{z:6,y:{x:9},w:{r:10}}
console.log(a.y===b.y)//true
console.log(a.w===b.w)//false
console.log(a===b) //false
js的作用域?
词法作用域 :词法作用域就是定义在词法阶段的作用域,简单说就是函数的作用域在函数定义的时候就决定了,而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的
函数作用域:都是对外封闭的,对外的作用域无法访问里面的作用域
全局作用域:最外层的全局作用域,任何地方都可以访问得到。在最外层作用域下使用 var 关键字会定义全局变量,也就是说会挂载在 window 对象上,或者不使用关键字 var、let、const 直接对变量名字进行赋值,JS也会自动为其创建为全局变量。
块级作用域:{ } 内定义的变量不会影响之外的变量,使用let 或者const可以定义
null和undefined的区别?
null转Number是0
undefined转Number是NaN