前端面试题

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值