zoukankan      html  css  js  c++  java
  • 前端面试题

    说一下浏览器缓存:

    缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。

    强缓存相关字段有expires,cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。

    协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match

    fetch发送2次请求的原因:

    fetch发送post请求的时候,总是发送2次,第一次状态码是204,第二次才成功?
    原因很简单,因为你用fetch的post请求的时候,导致fetch 第一次发送了一个Options请求,询问服务器是否支持修改的请求头,如果服务器支持,则在第二次中发送真正的请求。

    第一次是探域,至于跨域的情况下才会发送两次

    在地址栏里输入一个URL,到这个页面呈现出来,中间会发生什么?

    这是一个必考的面试问题,
    输入url后,首先需要找到这个url域名的服务器ip,为了寻找这个ip,浏览器首先会寻找缓存,查看缓存中是否有记录,缓存的查找记录为:浏览器缓存-》系统缓存-》路由器缓存,缓存中没有则查找系统的hosts文件中是否有记录,如果没有则查询DNS服务器,得到服务器的ip地址后,浏览器根据这个ip以及相应的端口号,构造一个http请求,这个请求报文会包括这次请求的信息,主要是请求方法,请求说明和请求附带的数据,并将这个http请求封装在一个tcp包中,这个tcp包会依次经过传输层,网络层,数据链路层,物理层到达服务器,服务器解析这个请求来作出响应,返回相应的html给浏览器,因为html是一个树形结构,浏览器根据这个html来构建DOM树,在dom树的构建过程中如果遇到JS脚本和外部JS连接,则会停止构建DOM树来执行和下载相应的代码,这会造成阻塞,这就是为什么推荐JS代码应该放在html代码的后面,之后根据外部央视,内部央视,内联样式构建一个CSS对象模型树CSSOM树,构建完成后和DOM树合并为渲染树,这里主要做的是排除非视觉节点,比如script,meta标签和排除display为none的节点,之后进行布局,布局主要是确定各个元素的位置和尺寸,之后是渲染页面,因为html文件中会含有图片,视频,音频等资源,在解析DOM的过程中,遇到这些都会进行并行下载,浏览器对每个域的并行下载数量有一定的限制,一般是4-6个,当然在这些所有的请求中我们还需要关注的就是缓存,缓存一般通过Cache-Control、Last-Modify、Expires等首部字段控制。 Cache-Control和Expires的区别在于Cache-Control使用相对时间,Expires使用的是基于服务器 端的绝对时间,因为存在时差问题,一般采用Cache-Control,在请求这些有设置了缓存的数据时,会先 查看是否过期,如果没有过期则直接使用本地缓存,过期则请求并在服务器校验文件是否修改,如果上一次 响应设置了ETag值会在这次请求的时候作为If-None-Match的值交给服务器校验,如果一致,继续校验 Last-Modified,没有设置ETag则直接验证Last-Modified,再决定是否返回304
     
    简单点说:
     
    DNS解析

    TCP连接

    发送HTTP请求

    服务器处理请求并返回HTTP报文

    浏览器解析渲染页面

    连接结束

     
    浏览器在生成页面的时候,会生成那两颗树?
     
    构造两棵树,DOM树和CSSOM规则树

    当浏览器接收到服务器相应来的HTML文档后,会遍历文档节点,生成DOM树,

    CSSOM规则树由浏览器解析CSS文件生成,

    csrf和xss的网络攻击及防范

    CSRF:跨站请求伪造,可以理解为攻击者盗用了用户的身份,以用户的名义发送了恶意请求,比如用户登录了一个网站后,立刻在另一个tab页面访问量攻击者用来制造攻击的网站,这个网站要求访问刚刚登陆的网站,并发送了一个恶意请求,这时候CSRF就产生了,比如这个制造攻击的网站使用一张图片,但是这种图片的链接却是可以修改数据库的,这时候攻击者就可以以用户的名义操作这个数据库,防御方式的话:使用验证码,检查https头部的refer,使用token

    XSS:跨站脚本攻击,是说攻击者通过注入恶意的脚本,在用户浏览网页的时候进行攻击,比如获取cookie,或者其他用户身份信息,可以分为存储型和反射型,存储型是攻击者输入一些数据并且存储到了数据库中,其他浏览者看到的时候进行攻击,反射型的话不存储在数据库中,往往表现为将攻击代码放在url地址的请求参数中,防御的话为cookie设置httpOnly属性,对用户的输入进行检查,进行特殊字符过滤

    描述一下XSS和CRSF攻击?防御方法?

    XSS, 即为(Cross Site Scripting), 中文名为跨站脚本, 是发生在目标用户的浏览器层面上的,当渲染DOM树的过程成发生了不在预期内执行的JS代码时,就发生了XSS攻击。大多数XSS攻击的主要方式是嵌入一段远程或者第三方域上的JS代码。实际上是在目标网站的作用域下执行了这段js代码。

    CSRF(Cross Site Request Forgery,跨站请求伪造),字面理解意思就是在别的站点伪造了一个请求。专业术语来说就是在受害者访问一个网站时,其 Cookie 还没有过期的情况下,攻击者伪造一个链接地址发送受害者并欺骗让其点击,从而形成 CSRF 攻击。

    XSS防御的总体思路是:对输入(和URL参数)进行过滤,对输出进行编码。也就是对提交的所有内容进行过滤,对url中的参数进行过滤,过滤掉会导致脚本执行的相关内容;然后对动态输出到页面的内容进行html编码,使脚本无法在浏览器中执行。虽然对输入过滤可以被绕过,但是也还是会拦截很大一部分的XSS攻击。

    防御CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

    说一下对Cookie和Session的认知,Cookie有哪些限制?

    1.    cookie数据存放在客户的浏览器上,session数据放在服务器上。

    2.    cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
    考虑到安全应当使用session。

    3.    session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
    考虑到减轻服务器性能方面,应当使用COOKIE。

    4.    单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

    什么是BFC?什么是IFC?

    不要试图去讲解 BFC 的定义!!
    如何说明 BFC ,举例子!!不要试图去讲定义!!

    格式化上下文(block formatting context) 

    当一个HTML元素满足下面条件的任何一点,都可以产生Block Formatting Context:
    a、float的值不为none
    b、overflow的值不为visible
    c、display的值为table-cell, table-caption, inline-block中的任何一个
    d、position的值不为relative和static

     IFC(Inline Formatting Context)即行内格式化上下文。常规流(也称标准流、普通流)是一个文档在被显示时最常见的布局形态。

    (块级格式化上下文,用于清楚浮动,防止margin重叠等)

    直译成:块级格式化上下文,是一个独立的渲染区域,并且有一定的布局规则。

    BFC区域不会与float box重叠

    BFC是页面上的一个独立容器,子元素不会影响到外面

    计算BFC的高度时,浮动元素也会参与计算

    那些元素会生成BFC:

    根元素

    float不为none的元素

    position为fixed和absolute的元素

    display为inline-block、table-cell、table-caption,flex,inline-flex的元素

    overflow不为visible的元素

    BFC 特性(功能)

    1. 使 BFC 内部浮动元素不会到处乱跑;
    2. 和浮动元素产生边界。

    画一条0.5px的线

    采用meta viewport的方式

    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

    采用border-image的方式

    采用transform: scale()的方式

    .hairline-bottom {
      position: relative;
      border: none;
    }
    .hairline-bottom::after {
      content: "";
      position: absolute;
      left: 0;
      bottom: 0;
      border-bottom: 1px solid #dddee3;
       100%;
      -webkit-transform: scale(1, 0.5);
      transform: scale(1, 0.5);
      -webkit-transform-origin: center bottom;
      transform-origin: center bottom;
      z-index: 1;
    }

    介绍一下盒模型

    CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。

    标准盒模型:一个块的总宽度=width+margin(左右)+padding(左右)+border(左右)

    怪异盒模型:一个块的总宽度=width+margin(左右)(既width已经包含了padding和border值)

    设置盒模型:box-sizing:border-box

    对象深度克隆的简单实现

    function deepClone(obj){
    var newObj= obj instanceof Array ? []:{};
    for(var item in obj){
    var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];
    newObj[item] = temple;
    }
    return newObj;
    }
    ES5的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以我们一开始判断了一些类型,决定newObj是对象还是数组~

     null == undefined为什么

    要比较相等性之前,不能将null 和 undefined 转换成其他任何值,但 null == undefined 会返回 true 。ECMAScript规范中是这样定义的。

    简单介绍一下symbol

    Symbol是ES6 的新增属性,代表用给定名称作为唯一标识,这种类型的值可以这样创建,let id=symbol(“id”)

    Symbl确保唯一,即使采用相同的名称,也会产生不同的值,我们创建一个字段,仅为知道对应symbol的人能访问,使用symbol很有用,symbol并不是100%隐藏,有内置方法Object.getOwnPropertySymbols(obj)可以获得所有的symbol。 
    也有一个方法Reflect.ownKeys(obj)返回对象所有的键,包括symbol。

    所以并不是真正隐藏。但大多数库内置方法和语法结构遵循通用约定他们是隐藏的

    NaN

    NaN是JS中的特殊值,表示非数字,NaN不是数字,但是他的数据类型是数字,它不等于任何值,包括自身,在布尔运算时被当做false,NaN与任何数运算得到的结果都是NaN,

    redux里常用方法

    提供 getState() 方法获取 state;

    提供 dispatch(action) 方法更新 state;

    通过 subscribe(listener) 注册监听器;

    react的生命周期函数

    初始化
    1、getDefaultProps()
    
    设置默认的props,也可以用dufaultProps设置组件的默认属性.
    
    2、getInitialState()
    
    在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state。此时可以访问this.props
    
    3、componentWillMount()
    
    组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。
    
    4、 render()
    
    react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。
    
    5、componentDidMount()
    
    组件渲染之后调用,只调用一次。
    
    更新
    
    6、componentWillReceiveProps(nextProps)
    
    组件初始化时不调用,组件接受新的props时调用。
    
    7、shouldComponentUpdate(nextProps, nextState)
    
    react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候
    
    8、componentWillUpdata(nextProps, nextState)
    
    组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state
    
    9、render()
    
    组件渲染
    
    10、componentDidUpdate()
    
    组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。
    
    卸载
    
    11、componentWillUnmount()
    
    组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
    View Code

    setState之后的流程

    在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。 经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。 在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。 在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

    tcp三次握手过程

    第一次握手:起初两端都处于CLOSED关闭状态,Client将标志位SYN置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN-SENT状态,等待Server确认;

    第二次握手:Server收到数据包后由标志位SYN=1得知Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN-RCVD状态,此时操作系统为该TCP连接分配TCP缓存和变量;

    第三次握手:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并且此时操作系统为该TCP连接分配TCP缓存和变量,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client和Server就可以开始传输数据。

    TCP和UDP的区别,为什么三次握手四次挥手

    TCP和UDP之间的区别 OSI 和TCP/IP 模型在传输层定义两种传输协议:TCP(或传输控制协议)和UDP(或用户数据报协议)。 UDP 与TCP 的主要区别在于UDP 不一定提供可靠的数据传输。 事实上,该协议不能保证数据准确无误地到达目的地。
    
    为什么TCP要进行四次挥手呢?
    
    因为是双方彼此都建立了连接,因此双方都要释放自己的连接,A向B发出一个释放连接请求,他要释放链接表明不再向B发送数据了,此时B收到了A发送的释放链接请求之后,给A发送一个确认,A不能再向B发送数据了,它处于FIN-WAIT-2的状态,但是此时B还可以向A进行数据的传送。此时B向A 发送一个断开连接的请求,A收到之后给B发送一个确认。此时B关闭连接。A也关闭连接。
    
    
    为什么要有TIME-WAIT这个状态呢,这是因为有可能最后一次确认丢失,如果B此时继续向A发送一个我要断开连接的请求等待A发送确认,但此时A已经关闭连接了,那么B永远也关不掉了,所以我们要有TIME-WAIT这个状态。
    
    当然TCP也并不是100%可靠的。
    View Code

    Redis和 mysql

    (1)类型上
    从类型上来说,mysql是关系型数据库,redis是缓存数据库
    
    (2)作用上
    
    mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢
    
    redis用于存储使用较为频繁的数据到缓存中,读取速度快
    
    (3)需求上
    
    mysql和redis因为需求的不同,一般都是配合使用。
    View Code

    git 怎么删除一个远程/本地分支

    删除远程分支

    git push origin --delete dev

    删除本地分支

    git branch -d dev

    查看分支情况

    git branch -a

    两个数组比较,判断是否有相同元素

    要判断JS中的两个数组是否相同,需要先将数组转换为字符串,再作比较。以下两行代码将返回true

    <script type="text/javascript">
            alert([].toString()== [].toString());
            alert([].toString()===[].toString());
    </script>

    数组去重一般用什么方法,数据量大又用什么方法

    /*
    * 速度最快, 占空间最多(空间换时间)
    *
    * 该方法执行的速度比其他任何方法都快, 就是占用的内存大一些。
    * 现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,
    * 不是的话给对象新增该键并放入新数组。
    * 注意点:判断是否为js对象键时,会自动对传入的键执行“toString()”,
    * 不同的键可能会被误认为一样,例如n[val]-- n[1]、n["1"];
    * 解决上述问题还是得调用“indexOf”。*/
    function uniq(array){
        var temp = {}, r = [], len = array.length, val, type;
        for (var i = 0; i < len; i++) {
            val = array[i];
            type = typeof val;
            if (!temp[val]) {
                temp[val] = [type];
                r.push(val);
            } else if (temp[val].indexOf(type) < 0) {
                temp[val].push(type);
                r.push(val);
            }
        }
        return r;
    }
    
    var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
    console.log(uniq(aa));
    View Code
    const removeDuplicateItems = arr => [...new Set(arr)]; console.log(removeDuplicateItems([42, 'foo', 42, 'foo', true, true])); // => [42, "foo", true]
    View Code

    set和obj

    数据量大就用排序方法去重呗 

    为什么JS中0.1+0.2 != 0.3


    由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。

    WebView和原生是如何通信

    == 和 ===的区别,什么情况下用相等==

    两个对象如何比较

    https://www.jianshu.com/p/90ed8b728975

    prototype和——proto——区别

    JS为什么要区分微任务和宏任务

    发布-订阅和观察者模式的区别

    for..in 和 object.keys的区别

    获取对象的属性的方法

    关于标题中方法和语句的基本用法可以参阅如下两篇文章:

    (1).JavaScript Object.keys()一章节。

    (2).JavaScript for in 语句一章节。

    Object.keys方法对数组进行遍历操作,可以看到获取的是数组的索引。

    数组的索引都是数字,但是通过此方法获取的都会被转换为字符串。

    for in语句:

    此语句可以遍历普通对象,也可以遍历数组,但是不建议使用它遍历数组。

    三.异同总结如下:

    (1).都可以遍历对象与数组。

    (2).获取的都是对象或者数组的键(数组的键就是元素索引),获取的值都会被转换为字符串。

    (3).获取键的顺序两者是完全相同的。

    (4).浏览器支持有所差异,Object.keys方法低版本IE浏览器不支持。

    (5).Object.keys方法不会获取原型链上的键,但是for in是可以的。

    文章

    react的理念是什么(拿函数式编程来做页面渲染)
    JS是什么范式语言(面向对象还是函数式编程)

    输出下面的执行顺序

    setTimeout(function(){
            console.log('1')
    });
     
    new Promise(function(resolve){
        console.log('2');
            resolve();
    }).then(function(){
        console.log('3')
    });
            console.log('4');

    看一下宏任务和微任务

    同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)。

    宏任务和微任务

    而宏任务一般是:包括整体代码script,setTimeout,setInterval。

    微任务:Promise,process.nextTick。

    记住就行了。

    所以正确的执行结果当然是:

    2,4,3,1。
    View Code

    因为settimeout是宏任务,虽然先执行的他,但是他被放到了宏任务的eventqueue里面,然后代码继续往下检查看有没有微任务,检测到Promise的then函数把他放入了微任务序列。等到主线进程的所有代码执行结束后。先从微任务queue里拿回掉函数,然后微任务queue空了后再从宏任务的queue拿函数。

  • 相关阅读:
    颜色空间之CIE2000色差公式
    爱做梦的人-人的特性之一
    Lua文件操作和串行化
    Lua文件操作和串行化
    Lua调用C++带参数的方法
    Lua调用C++带参数的方法
    C++对Lua中table进行读取、修改和创建
    C++对Lua中table进行读取、修改和创建
    C++获取Lua全局变量和执行Lua多参数多返回值函数
    C++获取Lua全局变量和执行Lua多参数多返回值函数
  • 原文地址:https://www.cnblogs.com/yangsg/p/11137546.html
Copyright © 2011-2022 走看看