8.4面经代码

84 阅读12分钟

1.三栏布局

1.浮动加margin
2.absolute
3.grid
display:grid;
gird-template-rows:100px;
grid-template-columns:200px auto 200px;
4.table
display:table;
display:table-cell;
5.flex
display:flex;
flex:1;

2.bfc

1.display是inline-block ,table-cell,table-caption,flex
2.position是absolute和fixed可以,不能是static,relative
3.float不是none
4.overflow不是visible

3.event对象的使用

event.preventDefault()
event.stopPropagation()
event.stopImmediatePropagation()
event.target 事件真正发出者
event.currentTarget 监听事件者
自定义事件
var event=new Event('build')
var event=new CustomEvent('build',{detail:elem.dataset.time})
elem.addEventListener('build',function(e){
console.log('hhh');},false)
elem.dispatchEvent(event)
elem是dom元素呗
手写eventEmitter发布订阅模式
class EventEmitter{
 constructor(){
   this.events={};
 }
 on(type,callBack){
   if(!this.events)this.events=Object.create(null);
   if(!this.events[type]){
     this.events[type]=[callBack];
   }else{
     this.events[type].push(callBack);
   }
 }
 off(type,callBack){
    if(!this.events[type])return;
    this.events[type]=this.events[type].filter(item=>{
    return item!==callBack;
   });
 }
 once(type,callBack){
    function fn(){
      callBack();
      this.off(type,fn);
    }
    this.on(type,fn);
  }
  emit(type,...rest){
     this.events[type]&&this.events[type].forEach(fn=>fn.apply(this,rest));
   }
 }
 const event=new EventEmitter();
 const handle=(...rest)=>{
   console.log(rest);
 }
 event.on('click',handle)
 event.emit('click',1,2,3)
 event.off('click',1,20
 

4.js

let a={name:'aa'}
function Person(name){
  this.name=name
}
let b=new Person('aa')
let c=Object.create({name:'aa'})

instance 
一个构造函数的prototype是否在一个对象的原型链上
一个对象在其原型链上是否存在一个构造函数的prototype属性

new
创建一个空对象
让空对象的_proto_成员指向了构造函数的prototype成员对象
使用apply调用构造器函数,属性和方法被添加到this引用的对象中
如果构造函数中没有返回其他对象,那么返回this,即创建的这个新的对象,否则返回构造函数中返回的对象
function new(func){
 let obj={};
 obj._proto_=func.prototype;
 let result=func.apply(obj)
 if(result&&(typeof result=='object'||typeof(result)=='function')){
   return result
 }
 return obj;

js实现继承的方式
   function Father(name){
     this.name=name||'father';
     this.sayName=function(){
    };
     this.color=['red','orange'];
   }
   Father.prototype.age=18;
   Father.prototype.setAge=function(){
     console.log(this.age);
   }
1.原型链继承
Son.prototype=new Father();
2.构造继承
function Son(name){
 Father.call(this,'aaa')
 this.name=name;
}
let s=new Son('son')
3.组合继承
function Son(name){
 Father.call(this,'a')
 this.name=name
}
Son.prototype=new Father()
4.实例继承
5.拷贝继承
6.寄生组合继承
function Son(name){
 Father.call(this)
 this.name=name
}
Son.prototype=Object.create(Father.prototype);
Son.prototype.constructor=Son;
最完美
7.es6中的class继承:使用extends表明继承自哪个父类,并且在哪个子类构造函数中必须调用super
class Son etends Father{
  constructor(name){
    super(name);
    this.name=name;
  }
}

6.防抖和节流

防抖:动作停止后的事件超过设定事件时执行一次函数
这里的动作停止表示你停止了触发这个函数,从这个时间点开始计算当间隔事件等于你设定时间时才会执行里面的回调函数
function debance(fn,delay){
   let timer=null
   return ()=>{
     if(timer){
       clearTimeout(timer)
     }
     timer=setTimeout(()=>{
       fn();
     },delay);
    };  
}
window.addEventListner(
 "scroll",
 debance(()=>{
  console.log(111)
  },1000)
);
search搜索联想,用户在不断输入值时用防抖来节约请求资源
window触发resize时不断的调整浏览器窗口大小会不断地触发这个事件,用防抖让其只触发一次
节流:一定时间内执行的操作只执行一次,
function throttle(fn,delay){
   let flag=true
   return ()=>{
     if(!flag)return
     flag=false
     timer=setTimeout(()=>{
       fn()
       flag=true
     },delay);
    };
   }
function throttle(fn,delay){
  let startTime=new Date()
  return ()=>{
    let endTime=new Date()
    if(endTime-startTime>=delay){
      fn()
      startTime=endTime
    }else{
      return
    }
  };
鼠标不停点击触发,mousedown单位时间内只触发一次
监听滚动事件,比如是否滑到底部自动加载更多(懒加载),用节流来判断

js运行机制
js设计者将任务分成两种:同步任务和异步任务
同步任务是在主线程上排队执行的任务,只有前一个任务执行完毕才能执行后一个任务
异步任务是不进入主线程,而进入任务队列的任务,值有任务队列通知主线程,某个异步任务可以执行了该任务才会进入主线程执行

宏任务:script setTimeout setInterval setImmediate
微任务:promise process.nexttick
js代码属于异步任务哦

微任务的意义:
减少更新时的渲染次数,因为根据html标准会在宏任务执行结束之后在下一个宏任务开始执行之前,ui都会重新渲染,如果在微任务中就完成数据更新,当宏任务结束后就可以得到最新的ui了。如果新建一个宏任务来做数据更新的话那么渲染会执行两次
?
异步任务分为宏任务和微任务
event loop
任务进入执行栈去区分他是同步任务还是异步任务,同步任务放到主线程任务列表中等待最先执行,异步任务又分为宏任务和微任务分别有对应的事件列表且注册相应回调函数之后会放入事件对列中等待执行,主线程任务执行完毕之后会去先找一个宏任务,然后执行完所有微任务列表,再找宏任务,依次放入主线程执行。而其实此时同步任务应该早都完成了
比如说定时器,当在script中找到定时器的时候则把他放入宏任务table中,开始计时三秒之后放入event queue中 宏任务的执行顺序应该是按着queue队列中顺序
主线程同步任务完成后先清空微任务队列。毕竟微任务的意义是插空更新渲染....,如果微任务队列空那就执行宏任务一个。
then是微任务
new promise是立即执行的
resolve()
}).then(res=>{
   console.log(9)
}).then(res=>{
   console.log(8)
})虽然9的那个promise没有具体说resolve但是8的那个是执行了的也就是9是已经完成了的 虽然具体我不清楚但只要不是跑出异常像这种连贯的都是成功⑧
?

如何取消promise?
1.用promise.race方法
2.新包装一个可操控的promise
??promise还是不太懂? 不会这个

http协议相关:
http超文本传输协议是用于从www服务器传输超文本到本地浏览器的传输协议,http是一个应用层协议,由请求和响应构成。是一个标准的客户端和服务器模型
计网层次:
物理层 数据链路层 网络层 传输层 会话层 表示层 应用层
http特点:
基于请求或响应模型的协议
简单快速
灵活 无连接 无状态
http报文:
请求报文:{
 请求行
 请求头
 请求正文
}
响应报文:{
 状态行
 响应头
 数据主体
}

http方法
get 请求指定的页面信息并返回实体主体
post 向指定资源提交数据进行处理请求,数据被包含在请求体中,会使资源添加或修改
head 类似于get 只用于获取报头 返回的响应无具体内容 
options 允许客户端查看服务器性能
delete 请求服务器删除指定的页面
trace 回显服务器收到的请求,用于测试或诊断
connect http1.1协议中预留给能够将连接改为管道方式的代理服务器
put 客户端到服务器传送的数据取代指定的文档的内容

get post head put delete tarce options connect
8个

get和post区别:
get请求会被浏览器主动缓存,post不行除非手动设置
get把请求的参数放在url上,即http协议头上,而post把参数放在http的包体内
get的方法传输数量非常小大概2kb 但是执行效率却比post好,而post方法传递的数据量相对较大,他是等待服务器来读取数据的不过也有字节限制大概是80kb或者100kb最大,这是为了避免对服务器用大量数据进行恶意攻击
get请求只能进行url编码,而post支持多种编码方式
get产生的url地址可以加入书签但post不行
get请求参数会被完整的保留在浏览器历史记录里,而post中的参数不会被保留
get比post危险,因为参数直接暴露在url里,所以不能用来传输敏感信息

http状态码:
由三位数字组成
1xx表示请求已接收请继续处理
2xx成功表示请求已被成功接收处理
3xx重定向
4xx客户端错误
5xx服务器端错误,服务器未能实现合法的请求
200客户端请求成功
204服务器成功处理但没有返回内容
206服务器已完成了部分get请求(客户端进行了范围请求)
301永久重定向
302临时重定向
303临时重定向,应使用get定向获取请求资源 
304客户端发送附带条件的请求时条件不满足 返回304时不包含任何响应主题虽然304被划分在重定向但是和重定向没有关系
400客户端有语法错误 服务器端没法理解
401请求未经授权
403服务器收到请求但拒绝提供服务
404请求资源不存在
415不支持的媒体类型
500服务器发生不可预期错误
503服务器当前不能处理客户端请求,一段时间后可能恢复正常

8.http持久化连接与管道化

在http1.0中默认是短连接,没有正式规定connection:keep-alive操作
http/1.1所有连接都是keep-alive的也就是默认都是持续连接的,在事务处理结束之后仍然保持在打开状态的tcp连接称为持久连接。
持久连接会在不同事务之间保持打开状态,直到客户端或服务器决定其关闭为止。重用已对目标服务器打开的空闲持久连接,就可以避开缓慢的连接建立阶段。而且,已经打开的连接还可以避免慢启动的拥塞适应阶段,以便更快速地进行数据传输。所以,持久连接降低了时延和连接建立的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量

HTTP/1.1允许在持久连接上可选的使用**请求管道**,是相对于keep-alive连接的又一性能优化。在响应到达之前,可以将多条请求放入队列,当第一条请求通过网络流向服务器时,第二条和第三条请求也可以开始发送了。在高时延网络条件下,这样做可以降低网络的环回时间,提高性能

1)如果HTTP客户端无法确认连接是持久的,就不应该使用管道
2)必须按照与请求相同的顺序回送HTTP响应。
3HTTP客户端必须做好连接会在任意时刻关闭的准备,还要准备好重发所有未完成管道化的请求。
4)出错的时候,管道连接会阻碍客户端了解服务器执行的是一些列管道化请求中的哪一些。由于无法安全地重试POST这样的非幂请求,所以出错时,就存在某些方法永远不会被执行的风险。

9.同源策略

同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这样有利于隔离潜在恶意文件是一种关键安全机制
协议 端口 域名
不是一个源的文档没有资格去访问操作
cookie localstorage indexDB 无法读取
dom无法获得
ajax请求不能发送 如果a发送给b但是ab不是同源的那就没法通信

前后端通信方式:
1.ajax支持同源通信
2.websocket可以跨域
3.jsonp可以接受get请求跨域
4.cors跨域资源共享 同源更可以啊
5.node服务器代理
6.nginx反向代理
都行呗

创建ajax
util.json = function (options) {
     var opt = {
         url: '',
         type: 'get',
         data: {},
         success: function () {},
         error: function () {},
     };
     util.extend(opt, options);
     if (opt.url) {
         var xhr = XMLHttpRequest
            ? new XMLHttpRequest()
            : new ActiveXObject('Microsoft.XMLHTTP');
         var data = opt.data,
             url = opt.url,
             type = opt.type.toUpperCase(),
             dataArr = [];
         for (var k in data) {
             dataArr.push(k + '=' + data[k]);
         }
         if (type === 'GET') {
             url = url + '?' + dataArr.join('&');
             xhr.open(type, url.replace(/\?$/g, ''), true);
             xhr.send();
         }
         if (type === 'POST') {
             xhr.open(type, url, true);
             xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
             xhr.send(dataArr.join('&'));
         }
         xhr.onload = function () {
             if (xhr.status === 200 || xhr.status === 304) {
                 var res;
                 if (opt.success && opt.success instanceof Function) {
                     res = xhr.responseText;
                     if (typeof res === 'string') {
                         res = JSON.parse(res);
                         opt.success.call(xhr, res);
                     }
                 }
             } else {
                 if (opt.error && opt.error instanceof Function) {
                     opt.error.call(xhr, res);
                 }
             }
         };
     }
 };

util.json=function(options){
   var opt={
      url:'',
      type:'get',
      data:{},
      success:function(){},
      
util.json=function(options){
   var opt={
      url:'',
      type:'get',
      data:{},
      success:function(){},
      
这个真猛???不会 有空看看

跨域通信的几种方式:
1.jsonp通过script标签的异步加载来实现,script标签不受同源策略的限制,天然可跨域
2.hash url的#后面的内容就叫hash hash的改变页面不会刷新
3.postMessage
4.websocket 他是h5的一种新的协议,他实现了浏览器与服务器全双工通信,同时允许跨域腾讯。
5.cors 只要服务器实现了cors接口就可以跨域通信,限制最常用的跨域

10.前端安全

xss攻击(跨站脚本攻击)
{
    反射型xss
    发送请求时xss代码出现在请求url中作为参数提交到服务器服务器解析并响应,使最后客户端运行这段有病代码
    存储型xss
    我利用客户端把有病代码存到数据库中这么当用户查询到这段数据库信息并解析出来时我的目的就达成了
    HttpOnly
浏览器禁止页面的Javascript访问带有HttpOnly属性的cookie。(实质解决的是:XSS后的cookie劫持攻击)如今已成为一种“标准”的做法

    输入检查(XSS Filter)
让一些基于特殊字符的攻击失效。(常见的Web漏洞如XSSSQLInjection等,都要求攻击者构造一些特殊字符)

    输出检查
在变量输出到HTML页面时,使用编码或转义的方式来防御XSS攻击
}xss始终是在正常网页中的一些不正常操作

csrf跨站请求伪造
是引导你去不正常网站如何窃取信息
用户登录已信任网站a且留下了cookie
这时候去访问了危险网站b
1.token
2.referer
3.增加验证码

未完 那个面经没整理完?