【前端面试题】前端基础 | 八股文 | HTTP网络 | Vue | React

⭐️ 本文首发自 前端修罗场(点击加入),是一个由 资深开发者 独立运行 的专业技术社区,我专注 Web 技术、Web3、区块链、答疑解惑、面试辅导以及职业发展博主创作的 《前端面试复习笔记》(点击订阅),广受好评,已帮助多人提升实力、拿到 offer。现在订阅,私聊我即可获取一次免费的模拟面试机会,帮你评估知识点的掌握程度,获得更全面的学习指导意见!

盒模型

  • https://www.cnblogs.com/chengzp/p/cssbox.html

盒模型的组成大家肯定都懂,由里向外content,padding,border,margin.

盒模型是有两种标准的,一个是标准模型,一个是IE模型。

img

img

  • 在标准模型中,盒模型的宽高 = 内容(content)的宽高,

  • IE模型中盒模型的宽高 = 内容(content)+填充(padding)+边框(border)的总宽高

  • css如何设置两种模型:

    /* 标准模型 */
    box-sizing:content-box;
    /*IE模型*/
    box-sizing:border-box;
    
  • js获取宽高

    dom.offsetWidth/offsetHeight //最常用的,也是兼容最好的
    
  • 边距重叠

边距重叠解决方案BFC(块级格式化上下文)

//原理

  1. 内部的box会在垂直方向,一个接一个的放置
  2. 每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)
  3. box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠
  4. bfc的区域不会与浮动区域的box重叠
  5. bfc是一个页面上的独立的容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的
  6. 计算bfc高度的时候,浮动元素也会参与计算
  • 创建BFC
  1. float属性不为none(脱离文档流)
  2. position为absolute或fixed
  3. display为inline-block,table-cell,table-caption,flex,inine-flex
  4. overflow不为visible
  5. 根元素
  • 应用场景
    1. 自适应两栏布局
    2. 清除内部浮动
    3. 防止垂直margin重叠

清除浮动

  • 父级div定义伪类:after和zoom

    .clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0}
    .clearfloat{zoom:1}//zoom(IE转有属性)可解决ie6,ie7浮动问题
    
  • 在结尾处添加空div标签clear:both

    .clearfloat{clear:both}//添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
    
  • 父级div定义height

    父级div手动定义height,就解决了父级div无法自动获取到高度的问题
    
  • 父级div定义overflow:hidden

    必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
    
  • 父级div定义overflow:auto

    必须定义width或zoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度
    
  • 父级div也一起浮动

    所有代码一起浮动,就变成了一个整体,会产生新的浮动问题。
    
  • 父级div定义display:table: 将div属性变成表格

  • 结尾处加br标签clear:both:父级div定义zoom:1来解决IE浮动问题,结尾处加br标签clear:both

Position

https://segmentfault.com/a/1190000013683068

inline-block中间会有空隙

内联块元素具有了内联元素以及块级元素的特性:(1)元素之间可以水平排列 (2)可以当做一个块级元素来设置各种的属性,例如:width、height、padding等

间隙是由换行或者回车导致的。只要把标签写成一行或者标签直接没有空格,就不会出现间隙。但是这种方式是不太可靠。在父容器上使用font-size:0;可以消除间隙(把空格隐藏/去除),对于Chrome, 其默认有最小字体大小限制,考虑到兼容性,需要取消字体大小限制。

.demo {font-size: 0;-webkit-text-size-adjust:none;}

层叠优先级

浏览器默认的样式 < 网页制作者样式 < 用户自己设置的样式<!important

按照权重取最大(取权重最大值显示)去确定最后样式:

!importrant >内联>ID派生选择器(#id h1)> id(100)> class(10)>标签(1)>继承(0.5)

怎样覆盖 !important

很简单,只需再添加一条 带 !important 的CSS规则,再给这个给选择器更高的优先级(添加一个标签,ID或类);或是添加一样选择器,把它的位置放在原有声明的后面,总之,最后定义一条规则比胜)。

或者使用相同的选择器,但是置于已有的样式之后;

或干脆改写原来的规则,以避免使用 !important

HTTP:地址栏输入url到显示页面的步骤

基本流程:

a. 域名解析

b. 发起TCP的3次握手(TCP连接理论上不会自动断开)

c. 建立TCP连接发起http请求

d. 服务器端响应http请求,浏览器得到html代码

e. 浏览器解析html代码,并请求html代码中的资源

f. 浏览器对页面进行渲染呈现给用户

  1. 在浏览器地址栏输入URL
  2. 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
    • 如果资源未缓存,发起新请求
    • 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
    • 检验新鲜通常有两个HTTP头进行控制Expires和Cache-Control:
      • HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
      • HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
  3. 浏览器解析URL获取协议,主机,端口,path
  4. 浏览器组装一个HTTP(GET)请求报文
  5. 浏览器获取主机ip地址,过程如下:
    • 浏览器缓存
    • 本机缓存
    • hosts文件
    • 路由器缓存
    • ISP DNS缓存
    • DNS递归查询(可能存在负载均衡导致每次IP不一样)
  6. 端口建立TCP链接,三次握手
  7. TCP链接建立后发送HTTP请求
  8. 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
  9. 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
  10. 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
  11. 服务器将响应报文通过TCP连接发送回浏览器
  12. 浏览器接收HTTP响应,然后根据情况选择**关闭TCP连接或者保留重用,关闭TCP连接的四次握手
  13. 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同
  14. 如果资源可缓存,进行缓存
  15. 对响应进行解码(例如gzip压缩)
  16. 根据资源类型决定如何处理(假设资源为HTML文档)
  17. 解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
  18. 构建DOM树
  19. 解析过程中遇到图片、样式表、js文件,启动下载
  20. 构建CSSOM树
  21. 根据DOM树和CSSOM树构建渲染树
  22. js解析
  23. 显示页面

数据类型

  • 基本类型:数字(number)、字符串(string)、布尔值(boolean)、null、undefined、Symbol

  • 引用(对象)类型:function、array、object 对象是可变的,即值是可以修改的;对象的比较并非值得比较

  • undefined表示系统级的、出乎意料的或类似错误的值的空缺;表示缺少值,此处应该有值,但没有定义

  • null表示程序级的、正常的或在意料之中的值的空缺; 一般多使用null。

    null表示没有对象,即该处不应该有值

    1) 作为函数的参数,表示该函数的参数不是对象

    2) 作为对象原型链的终点

    undefined表示缺少值,即此处应该有值,但没有定义

    1)定义了形参,没有传实参,显示undefined

    2)对象属性名不存在时,显示undefined

    3)函数没有写返回值,即没有写return,拿到的是undefined

    4)写了return,但没有赋值,拿到的是undefined

    null和undefined转换成number数据类型

    null 默认转成 0

    undefined 默认转成 NaN

    typeof null         // object (因为一些以前的原因而不是'null')
    typeof undefined    // undefined
    null === undefined  // false
    null  == undefined  // true
    null === null  // true
    null == null  // true
    !null //true
    isNaN(1 + null)  // false
    isNaN(1 + undefined)  // true
    
  • Symbol:它的功能类似于一种标识唯一性的ID。通常情况下,我们可以通过调用Symbol()函数来创建一个Symbol实例:

    let s1 = Symbol()
    

    每个Symbol实例都是唯一的。因此,当你比较两个Symbol实例的时候,将总会返回false.

    应用场景:

    1. 使用Symbol来作为对象属性名(key)

      注意:Symbol类型的key是不能通过Object.keys()或者for...in来枚举的,它未被包含在对象自身的属性名集合(property names)之中,所以,利用该特性,我们可以**把一些不需要对外操作和访问的属性使用Symbol来定义。**当使用JSON.stringify()将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外

    2. 使用Symbol来替代常量
      const TYPE_AUDIO = Symbol()
      const TYPE_VIDEO = Symbol()
      const TYPE_IMAGE = Symbol()
      
    3. 使用Symbol定义类的私有属性/方法:私有化内部属性/方法
    4. 注册和获取全局Symbol

      通常情况下,我们在一个浏览器窗口中(window),使用Symbol()函数来定义和Symbol实例就足够了。但是,如果你的应用涉及到多个window(最典型的就是页面中使用了<iframe>),并需要这些window中使用的某些Symbol是同一个,那就不能使用Symbol()函数了,因为用它在不同window中创建的Symbol实例总是唯一的,而我们需要的是在所有这些window环境下保持一个共享的Symbol。这种情况下,我们就需要使用另一个API来创建或获取Symbol,那就是Symbol.for(),它可以注册或获取一个window间全局的Symbol实例:

      let gs1 = Symbol.for('global_symbol_1')  //注册一个全局Symbol
      let gs2 = Symbol.for('global_symbol_1')  //获取全局Symbol
      gs1 === gs2  // true
      

实现深复制的三种方法

  • 使用递归实现

    //使用递归的方式实现数组、对象的深拷贝
    function deepClone1(obj) {
      //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
      var objClone = Array.isArray(obj) ? [] : {};
      //进行深拷贝的不能为空,并且是对象或者是
      if (obj && typeof obj === "object") {
        for (key in obj) {
          if (obj.hasOwnProperty(key)) {
            if (obj[key] && typeof obj[key] === "object") {
              objClone[key] = deepClone1(obj[key]);
            } else {
              objClone[key] = obj[key];
            }
          }
        }
      }
      return objClone;
    }
    
  • 通过 JSON 对象实现深拷贝

    //通过js的内置对象JSON来进行数组对象的深拷贝
    function deepClone2(obj) {
      var _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
      return objClone;
    }
    
  • 通过jQuery的extend方法实现深拷贝

    var array = [1,2,3,4];
    var newArray = $.extend(true,[],array);
    
  • lodash函数库实现深拷贝

    lodash.cloneDeep()实现深拷贝
    
  • Object.assign()拷贝

    当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
    

JQuery 获取ID元素与JS获取的区别

  • KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲id")获取的对象其实是一个数…(“#id”)[0],这样两个就相等了。

vue中组件通信方式

  • 父组件向子组件传值:

    父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed

  • 子组件向父组件传值: 通过事件形式$emit: 子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件

  • 通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级

  • Vuex: Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。

    vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。

总结

  • 父子通信:

    父向子传递数据是通过 props,子向父是通过 events**($emit)**;通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners

  • 兄弟通信:Bus;Vuex

  • 跨级通信:Bus;Vuex;provide / inject API、$attrs/$listeners

同源策略

如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的。我们也可以把它称为“协议/主机/端口

跨域的解决方法

https://www.cnblogs.com/laixiangran/p/9064769.html

  • CORS(跨域资源共享): 是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。

    整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。

    浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

    • 简单请求:浏览器直接发出CORS请求,在头信息中添加一个Origin字段,用来说明请求来自哪个源,服务器根据这个值,决定是否同意这次请求。

    如果服务器不许可,则返回的信息中不会包含Access-Control-Allow-Origin字段,这个错误需要onerror捕获,返回的状态码可能为200;

    如果服务器许可,则服务器返回的响应中会多出Access-Control-字段;

    CORS默认不发送cookie,需要发送cookies,则需要服务器指定Access-Control-Allow-Credentials字段,需要在ajax请求中打开withCredentials属性;

    • 非简单请求/复杂请求:请求方法是PUT或DELETE,Content-Type字段类型是application/json。

    **会在正式通信前,增加一次OPTIONS查询请求,预检请求(目的就是为了判断实际发送的请求是否是安全的)****。**询问服务器,网页所在域名是否在服务器的许可名单中,以及可以使用那些HTTP动词和头信息字段,只有得到肯定答复,浏览器才会发出正式XMLHTTPRequest请求,否则会报错

    服务器通过预检请求,以后每次浏览器正常CORS请求,都会和简单请求一样,会有一个Origin字段,服务器的回应也会有yieldAccess-Control-Allow-Origin头信息字段

  • JSONP 跨域: 借助script标签能跨域的原理。流量器告诉服务端一个回调函数的名称,服务端在返回的script里面调用这个回调函数,同时传进客户端需要的数据,这个返回的代码就能在浏览器上执行了。

    JSONP和CORS比较,缺点是支持是get类型。优点是兼容老版本浏览器。

  • 图像 Ping 跨域

  • 服务器代理

  • document.domain =“父域”:子域跨父域

  • window.name 跨域

  • location.hash 跨域

  • postMessage 跨域:父窗口向子iframe传消息

进程线程

  • 进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
  • 线程:单个进程中执行中每个任务就是一个线程。
  • 一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务
  • 线程没有地址空间,线程包含在进程的地址空间中
  • 父和子进程使用进程间通信机制
  • 进程内的任何线程都被看做是同位体,且处于相同的级别。不管是哪个线程创建了哪一个线程,进程内的任何线程都可以销毁、挂起、恢复和更改其它线程的优先权。
  • 子进程不对任何其他子进程施加控制,进程的线程可以对同一进程的其它线程施加控制。

状态码

HTTP状态码共分为5种类型:

1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

常见的HTTP状态码:

  • 200 - 请求成功
  • 301 - 资源(网页等)被永久转移到其它URL
  • 302- 资源只是临时被移动。客户端应继续使用原有URI
  • 304- 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。
  • 404 - 请求的资源(网页等)不存在
  • 500 - 内部服务器错误
  • 502- 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应

前端缓存

cookie是浏览器提供的一种机制,它将document 对象的cookie属性提供给JavaScript。可以由JavaScript对其进行控制,而并不是JavaScript本身的性质。cookie是存于用户硬盘的一个文件,这个文件通常对应于一个域名,当浏览器再次访问这个域名时,便使这个cookie可用。

cookie的缺点主要集中于安全性和隐私保护。

localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同

localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽

localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡

localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空

sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。

白屏之前的步骤优化

发生的原因基本可以归结为网速&静态资源

1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。

2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。

3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。

根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时:

1减少文件加载体积,如html压缩,js压缩

2加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西

3提供一些友好的交互,比如提供一些假的滚动条

4使用本地存储处理静态文件。

vue首屏性能优化,解决页面加载时间过长(白屏)方法

  • 路由懒加载

    在 router.js文件中,原来的静态引用方式,如:

    import ShowBlogs from '@/components/ShowBlogs'
    routes:[ path: 'Blogs', name: 'ShowBlogs', component: ShowBlogs ]
    

    改为:

     routes:[ 
     		path: 'Blogs',
     		name: 'ShowBlogs',
     		component: () => import('./components/ShowBlogs.vue')
     	]
    

    如果是在 vuecli 3中,我们还需要多做一步工作
    因为 vuecli 3默认开启 prefetch(预先加载模块),提前获取用户未来可能会访问的内容
    在首屏会把这十几个路由文件,都一口气下载了
    所以我们要关闭这个功能,在 vue.config.js中设置:

    img

  • ui框架按需加载

    在 .babelrc / babel.config.js文件中添加( vue-cli 3要先安装 babel-plugin-component):

    plugins: [
        [
          "component",
          {
            "libraryName": "element-ui",
            "styleLibraryName": "theme-chalk"
          }
        ]
      ]
    
    
  • gzip压缩

    安装 compression-webpack-plugin

cnpm i compression-webpack-plugin -D

在 vue.congig.js中引入并修改 webpack配置:

const CompressionPlugin = require('compression-webpack-plugin')

configureWebpack: (config) => {
        if (process.env.NODE_ENV === 'production') {
            // 为生产环境修改配置...
            config.mode = 'production'
            return {
                plugins: [new CompressionPlugin({
                    test: /\.js$|\.html$|\.css/, //匹配文件名
                    threshold: 10240, //对超过10k的数据进行压缩
                    deleteOriginalAssets: false //是否删除原文件
                })]
            }
        }

在服务器我们也要做相应的配置
如果发送请求的浏览器支持 gzip,就发送给它 gzip格式的文件。

https://segmentfault.com/a/1190000020383064
https://segmentfault.com/a/1190000019499007

Vue 响应式原理

数据劫持

数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者触发相应的监听回调。Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

vue中通过observe方法实现所有的数据属性的劫持.

  • vue在实例化的时候会将data数据中的属性都做数据劫持
  • 如果是对象,也会迭代本身属性将全部属性都实现数据劫持
  • 当赋值的时候,如果是newVal是对象,也会去迭代newVal的属性实现全部属性的数据劫持

Array对象是没有办法通过上述方法实现数据劫持的:

vue中实现的方法实际是对数组的属性重写,重写过后的方法不仅能实现原有的功能,还能发布消息给订阅者。

如果要更新 Array 某个索引对应的值得时候,要用Vue.set方式实现

Vue.set是对数据进行拦截,实际就是数据劫持处理,并发布一次消息

手写bind

//context为需要被绑定上的对象,arguments是参数
Function.prototype.bind = function(context){
  var self = this; //this => Function
  return function(){
      return self.apply(context,arguments)
  }
}

http与https区别

  • https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

HTTPS 连接过程

服务器发送它的证书给浏览器,浏览器确认证书正确,并检查证书中对应的主机名是否正确,如果正确则双方加密数据后发给对方,对方再进行加密,保证数据是不透明的。

非对称加密算法:加密用密钥,解密用公钥,公钥是公开的,密钥是不会传播的。常见的算法如:RSA。

SSL原理

img

es6之扩展/剩余运算符 三个点(…)

  • 对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中

前端跨脚本攻击攻击xss

XSS也称为跨脚本攻击,是一种恶意脚本,可以获取用户得cookie、token、session.

分为存储性(持久型)、反射型(非持久型)、基于DOM

  • 尽量少使用appenChidinnerHTMLouterHTML等标签,而使用innerTexttextContentsetAttribute
  • 前端过滤:url: 可以使用encodeURIComponent 进行转义
  • 通过 Content-Security-PolicyHTTP头来开启CSP:
  • 通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。如果 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记

CSRF跨站请求伪造

CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器.

由于同源策略,跨域的Ajax请求不会带上Cookie,然而script/iframe/img等标签却是支持跨域的。所以在请求的时候是会带上cookie的。

  • Get 请求不对数据进行修改/写

  • 不让第三方网站访问到用户Cookie

  • 阻止第三方网站请求接口

  • 请求时附带验证信息,如验证码或Token,可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token。

  • XSS是利用用户对指定网站的信任

  • CSRF是利用网站对用户的信任

call apply bind区别

  • call、apply、bind的作用是改变函数运行时this的指向
  • call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。
  • apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。
  • bind和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。bind返回对应函数, 便于稍后调用; apply, call则是立即调用。
  • 箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象

++1 和i++哪个效率高

++i的效率高些,++i在运算过程中不产生临时对象,返回的就是i,是个左值,类似++i=1这样的表达式是合法的,而i++在运算的过程中会产生临时对象,返回的是零时对象的值,是个右值,像i++=1这样的表达式是非法的.

对于内置类型,单独的i++和++i语句,现在的编译器基本上都会优化成++i,所以就没什么区别了

webpack热更新 HMR

为 Webpack 开发环境开启热更新,要做两件事:

  • 使用 HotModuleReplacementPlugin 插件
  • 打开 webpack-dev-server 的热更新开关

每次 compiler 的 ‘done’ 钩子函数被调用的时候就会要求客户端去检查模块更新,如果客户端不支持 HMR,那么就会全局加载。通过 webpack-dev-server 提供的 websocket 服务端代码通知 websocket 客户端发送的 ok 和 warning 信息的时候会要求更新。如果支持 HMR 的情况下就会要求检查更新,同时发送过来的还有服务器端本次编译的 compilation 的 hash 值。如果不支持 HMR,那么要求刷新页面。如果 ok 则调用reloadApp方法,而 reloadApp 方法 判断如果开启了 HMR 模式, 通过hotEmitter 执行webpackHotUpdate方法,如果不是 Hotupdate 那么直接 reload刷新网页。所以"webpack/hot/only-dev-server"的文件内容就是检查哪些模块更新了(通过 webpackHotUpdate 事件完成,而该事件依赖于compilation的 hash 值),其中哪些模块更新成功,而哪些模块由于某种原因没有更新成功。

sass less

事件流,冒泡捕获

从页面中接收事件的顺序称为事件流.

IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

Netscape Communicator团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预期目标之前捕获它。

“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。

首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。

先捕获,后冒泡

事件流比较典型应用是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理一类型的所有事件。

强缓存,协商缓存

  • 强缓存:强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。

    Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。

  • 协商缓存:协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。

    这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即第一次请求的响应头带上某个字段**(Last-Modified或者Etag)**,则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。Etag/If-None-Match返回的是一个校验码。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。

装饰者模式

装饰模式指的是在不必改变原类文件和使用继承的情况下,**动态地扩展一个对象的功能。**它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

适用场景:当遇到新的功能或需求需要对原来的操作做出更改时,若原来的操作比较复杂,可以把原来的操作原封不动地放在装饰者中,然后再添加新功能。

function Person() {
}
Person.prototype.sayHello = function() {
  console.log('Hello, Alice!');
};
function Decorator(param) {
  this.person = param;
}
Decorator.prototype.sayHello = function() {
  this.person.sayHello();
  console.log('Hello, Bruce!');
};
new Decorator(new Person()).sayHello();

WebView调用Android本地组件

webview有两个方法:setWebChromeClient 和 setWebClient

setWebClient:主要处理解析,渲染网页等浏览器做的事情

setWebChromeClient:辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等

WebViewClient就是帮助WebView处理各种通知、请求事件的。

响应式布局

普通函数和箭头函数区别

  • 箭头函数相当于匿名函数,并且简化了函数定义。箭头函数是匿名函数,不能作为构造函数,不能使用new

  • 箭头函数不绑定arguments,取而代之用rest参数…解决

  • 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

  • 箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。

  • 箭头函数没有原型属性

  • 箭头函数不能当做Generator函数,不能使用yield关键字

    箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()

    普通函数的this指向调用它的那个对象

原型与原型链

原型prototype

每个函数都有一个 prototype 属性,每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型每一个对象都会从原型"继承"属性。

  • proto:每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型。

  • constructor:每个原型都有一个 constructor 属性指向关联的构造函数,实例原型指向构造函数

使用原型的好处就是,可以让所有对象实例共享它包含的属性和方法。即不用在构造函数中定义对象实例的属性和方法,而是直接把这些信息添加到原型对象上面。

使用hasOwnProperty()方法可以检查一个属性是存在于实例中,还是存在原型中?只在给定属性存在于对象实例中时,才会返回true。

原型链

JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。

MVVM

Model–View–ViewModel(MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发。MVVM 源自于经典的 Model–View–Controller(MVC)模式,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。

img

iframe优缺点

  • 优点

    1.iframe能够原封不动的把嵌入的网页展现出来。

    2.如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决

  • 缺点

    很多的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。

    iframe框架页面会增加服务器的http请求,对于大型网站是不可取的

JS数组slice()和splice()的区别

  • **slice()定义:从已有的数组中返回你选择的某段数组元素;:**start可以为负数,此时它规定从数组尾部开始算起的位置。也就是-1 ,指最后一个元素,
  • slice()方法不会修改数组本身,而是返回所选取范围的数组元素
  • 如果想删除数组中的某一个元素,需要使用splice()。splice()定义:从数组中添加或删除元素,然后返回被删除的数组元素。splice()方法会改变原始数组
  • splice()语法:arrayObject.splice(index,howmany,item1,…,itemX).howmany表示删除的元素数量,如果为0,则表示不删除数组元素

defineproperty 与 proxy的区别

  • Object.defineProperty() 无法监控到数组下标的变化
  • proxy可以劫持整个对象,并返回一个新对象,有13种劫持操作,Proxy是es6提供的,兼容性不好,无法用polyfill磨平
  • proxy在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,我们可以这样认为,Proxy是Object.defineProperty的全方位加强版.

懒加载和预加载

  • 懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式

  • 懒加载原理:首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在data-original属性中,
    当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。

  • 预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源

    两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力

解决setTimeout中的this指向问题

在setInterval和setTimeout中传入函数时,函数中的this会指向window对象。

解决办法:

推荐用下面两种写法:

  • 将bind换成call,apply也会导致立即执行,延迟效果会失效

    window.setTimeout(this.declare.bind(this), 2000);
    
  • 使用es6中的箭头函数,因为在箭头函数中this是固定的.箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域

对象字面量vs构造函数创建对象对比

  • 字面量的优势
    1. 它的代码量更少,更易读;
    2. 它可以强调对象就是一个简单的可变的散列表,而不必一定派生自某个类
    3. 对象字面量运行速度更快,因为它们可以在解析的时候被优化,它们不需要"作用域解析(scope resolution)";因为存在我们创建了一个同名的构造函数Object()的可能,当我们调用Object()的时候,解析器需要顺着作用域链从当前作用域开始查找,如果在当前作用域找到了名为Object()的函数就执行,如果没找到,就继续顺着作用域链往上照,直到找到全局Object()构造函数为止
    4. Object()构造函数可以接收参数,通过这个参数可以把对象实例的创建过程委托给另一个内置构造函数,并返回另外一个对象实例,而这往往不是你想要的。Object()构造函数的这种特性会导致一些意想不到的结果,特别是当参数不确定的时候

Content-Type

互联网媒体类型,在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。

  • application/x-www-form-urlencoded

HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/“、”,“、“:” 等会自动进行URL转码。不支持文件,一般用于表单提交。

  • multipart/form-data

与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。

  • application/json

以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(约定好的情况下)。

  • application/xml 和 text/xml

与application/json类似,这里用的是xml格式的数据,text/xml的话,将忽略xml数据里的编码格式。

vue-router

两种模式

  1. hash —— 即地址栏 URL 中的 # 符号:它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  2. history —— 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。hash 模式和 history 模式都属于浏览器自身的特性,

钩子函数

  1. **全局钩子:主要包括beforeEach(前置守卫)和aftrEach(后置钩子),一般用来判断权限,**以及以及页面丢失时候需要执行的操作
  2. 单个路由里面的钩子:主要用于写某个指定路由跳转时需要执行的逻辑
  3. 组件路由:主要包括 beforeRouteEnterbeforeRouteUpdate ,beforeRouteLeave,这几个钩子是路由导航守卫,都是写在组件里面

vuex的原理

Vuex:可以理解为Vue的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  • State:数据仓库。代表数据的唯一来源,一般Vuex所有的数据都会存储在State中。State本身是一种json对象。
  • getter:用来获取数据的。
  • Mutation:用来修改数据的。通过commit Mutation修改。Mutation里面的操作要同步的方式。
  • Action:用来提交Mutation的。可以进行异步操作。
  1. State由Mutations驱动变化
  2. 通过Actions与后端交互
  3. 通过State渲染前端
  4. 前端触发Actions来提交Mutations

闭包

闭包可以理解为“定义在一个函数内部的函数”,本质上,闭包是将函数内部和外部连接起来的一座桥梁。

父函数内部定义的子函数,如果没有引用父函数作用域中的变量,那么这个子函数不是闭包。也就是说,闭包是由函数和它所在的环境构成的,缺一不可。

闭包会让函数中的变量都被保存在内存中,内存消耗大,所以不能滥用闭包,可以在不使用该变量的时候将其delete

Promise

1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列

在JavaScript的世界中,所有代码都是**单线程执行的。**由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现.异步操作会在将来的某个时间点触发一个函数调用.

避免 回调地域问题(嵌套层次深)。

promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)

Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了.

  • resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
  • reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)

promise有三个状态:

1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败

Promise对象的状态改变,只有两种可能:

从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。

promise

Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。

job1.then(job2).then(job3).catch(handleError);//其中,job1、job2和job3都是Promise对象。

Object.toString和Object.prototype.toString的区别

Object构造函数本身没有toString方法。
依照原型链关系,Object构造函数的上游原型链是Function.prototype。调用Object.toString.call(param)本质上是调用Function.prototype.toString.call(param)

原型链终端Object.prototype对象上的toString()确实可以被继承下来,可以用来判断数据类型, 但是并不能满足所有的需求,作为子代的包装类和数组就重写了自己的toString(), 因此当我们调用toString()时,会调用自身原型上重写的toString(),重写后的toString()可以把对象转换成字符串,还可以把number类型的数值转换成不同进制的数。当我们需要知道一个变量或值是什么类型的话就可以通/过调用Object.prototype.toString() 来实现 需要用到call().

  • Object.toString()是Object构造函数上的方法,返回的是对应的函数
  • Object.prototype.toString()是Object原型对象上的方法,返回的是代表该对象的字符串
var obj = {};
Object.toString(obj);//"function Object() { [native code] }"
Object.prototype.toString.call(obj);//"[object Object]"
  • 为什么Array、String、Number、Boolean等不能直接调用toString()

    因为Array、String、Number、Boolean、RegExp、Date等类型都重写了toString(),如果直接调用则因为自身的原型对象上已有toString()方法,就不会调用到Object原型对象上的toString()方法了。
    

实现弹幕

播放时,设置其translateXtransform
暂停时,把当前的位置写为translateXtransform为0,这个时候弹幕就保持在那个位置不动了。

再次播放时,重新设置translateX和transform,当然,transform-duration肯定是依据弹幕长度,当前位置和终点位置(播放器宽度)计算出来的。

播放和暂停的逻辑全都由js处理。
弹幕到位了以后,dom会被移除。
再加上will-change的GPU加速

B站另外还做了一个操作就是复用dom,弹幕走到头以后不会移除,而是在有下一个新弹幕的时候把原来的dom节点复用,修改style,使其重新播放一次,这个也是性能提高的一个处理办法

https://blog.csdn.net/qq2712193/article/details/51725705

含对象的数组怎么排序

var str=[
    {name:"a",age:50},
    {name:"b",age:20},
    {name:"c",age:40},
    {name:"d",age:30},
];
function compare(key){
    return function(value1,value2){
        var val1=value1[key];
        var val2=value2[key];
        return val1-val2;
    }
}
str.sort(compare('age'));
console.log(str);

请求报文&响应报文

  • 请求报文:请求行:请求方法,HTTP协议版本;请求头部:Content-Type;空行;请求体
  • 响应报文:状态行:状态码;响应头部;空行;响应体;

引入css方式

  • 行内式

    通过html属性style实现

  • 嵌入式

    在style标签中写css样式,在body中引用

  • 链接式

    1.一般都使用这种方式,在桌面上新建一个css文件:test.css,内容为一个css样式

    1. 在test.html引入test.css文件

导入式

@import(url(demo.css))

1.基本不使用,因为页面会先加载html,然后再去加载css,这样就会造成页面样式的延迟。

深拷贝及实现深拷贝的三种方法

  • 递归

    //使用递归实现深拷贝函数
    function deepClone(obj) {
    var objClone = Array.isArray(obj) ? [] : {}
    if (obj && typeof obj === 'object') {
    for (key in obj) {
    	if (obj.hasOwnProperty(key)) {
    	//判断obj的子元素是否为object对象,如果是则就递归拷贝
    	if (obj[key] && typeof obj[key] === 'object') {
    		objClone[key] = deepClone(obj[key])
    	} else {
    //如果不为对象就直接拷贝
    objClone[key] = obj[key]
    }}}}
    return objClone
    }
    
  • obj1 = JSON.stringify(obj) + JSON.parse(obj1)

  • Jquery: $.extend(true,[],object)

  • 第三方函数库 lodsh

数组和链表的区别

不同:链表是链式存储结构;数组是顺序存储结构

链表通过指针来连接元素与元素,数组则是把所有元素按次序依次存储

链表的插入删除元素相对数组较为简单,不需要移动元素,且较为容易实现长度扩充,但是寻找某个元素较为困难;

数组寻找某个元素较为简单,但插入与删除比较复杂,由于最大长度需要再编程一开始时指定,故当达到最大长度时,扩充长度不如链表方便。

(1) 从逻辑结构角度来看

  • 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。
  • 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)

(2) 从内存存储角度来看

  • (静态)数组从栈中分配空间, 对于程序员方便快速,但自由度小。

  • 链表从堆中分配空间, 自由度大但申请管理比较麻烦.

Array.push原理

  • 逐个复制元素

  • 修改数组长度

    function ArrayPush () {
      var n = TO_UNIT32(this.length);
      var m = %_ArgumentsLength();
      for (var i = 0; i < m; i++) { // 逐个复制元素
        this[i + n ] = %_Arguments(i);
      }
      this.length = n + m; // 修改数组的length
      return this.length;
    }
    

关系型数据库 & 非关系型数据库区别

  • 1.成本:Nosql数据库简单易部署,基本都是开源软件,不需要像使用Oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。
  • 2.查询速度:Nosql数据库将数据存储于缓存之中,而且不需要经过SQL层的解析,关系型数据库将数据存储在硬盘中,自然查询速度远不及Nosql数据库。
  • 3.存储数据的格式:Nosql的存储格式是key,value形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
  • 4.扩展性:关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。Nosql基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
  • 5.持久存储:Nosql不使用于持久存储,海量数据的持久存储,还是需要关系型数据库
  • 6.数据一致性:非关系型数据库一般强调的是数据最终一致性,不像关系型数据库一样强调数据的强一致性,从非关系型数据库中读到的有可能还是处于一个中间态的数据,Nosql不提供对事务的处理。

数据可脏读、幻读、不可重复读

  • 脏读: 读取未提交数据.A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。就好像原本的数据比较干净、纯粹,此时由于B事务更改了它,这个数据变得不再纯粹。这种情况常发生于转账与取款操作中
  • 幻读:前后多次读取,数据总量不一致。事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。读取了其他事务新增的数据
  • 不可重复读: 前后多次读取,数据内容不一致。不可重复读是读取了其他事务更改的数据

一个数组很多数,找出/判断两个数相加等于10

public static void findSumNum(int[] a,int sum){
		Arrays.sort(a);
		int i=0,j=a.length-1;
		while(i<=j){
			if(a[i]+a[j]<sum) i++;
			else if(a[i]+a[j]>sum) j--;
			else {
				System.out.println(a[i]+","+a[j]);
				i++;
			}
		}		
	}

数组去重

if (!Array.prototype.unique) {
  Array.prototype.unique = function () {
    var hash = {}, result = [], type = '', item;
    for (var i = 0; i < this.length; i++) {
      item = this[i];
      type = Object.prototype.toString.call(item);

      if ( !hash[item + type] ) {
        hash[item + type] = true;
        result.push(item);
      }
    }
    return result;
  };
}

后代选择器,子选择器,相邻兄弟选择器

  • 后代选择器(包含子选择器,且包含子选择器的子孙选择器): p em
  • 子选择器(父选择器的一级子元素): h1 > strong
  • 相邻兄弟选择器: h1+p

sessionID

session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识------------称为session id,如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。

保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。

SQL:Drop、truncate、delete

  • 当你不再需要该表时, 用 drop;

  • 当你仍要保留该表,但要删除所有记录时, 用 truncate;

  • 当你要删除部分记录时(always with a WHERE clause), 用 delete.

前端 怎么做到一个屏幕分辨率的自适应

https://www.cnblogs.com/HCJJ/p/6408363.html

  • em:是一种相对单位,它相对于父元素的字体大小。浏览器默认的字体大小是16px,因此 1em 也就等于 16px。

  • rem是一种相对单位,它相对于根元素 html 的字体大小。

    REM会让页面根据不同的显示设备进行适配缩放,那么必然就会有一个 标准页面尺寸,就目前而言,整个前端开发界使用最多的标准页面尺寸则是根据iphone4或者 iPhone5为依据的 640px*1366px ,也有以iphone6为基准的750px。这个标准的页面尺寸,我们可以将其定义为1,如果当前的显示设备尺寸小于标准页面尺寸(640px或者750px)那么便让页面尺寸缩小,使其小于1。而当显示设备尺寸大于标准页面尺寸,我们即可以做一些其它的适配,也可以将页面整个居中显示在显示设备中然后不进行任何缩放操作。

    实际上rem布局与px布局并没有什么本质的区别,这个我们可以代入实例去理解,比如现在 htmlfont-size的大小是100px,即 1rem = 100px,如果现在页面中要放入一个200*200的盒子,那么按照等比关系:

    div{
        width:2rem;
        height:2rem;
        background:gray;
    }
    

    REM 实现的页面缩放适配原理, rem 是依据 html标记的 font-size 大小的相对单位,对于使用rem为单位的页面,在被载入到显示设备显示的时候,会根据显示设备的尺寸,然后对应的修改html标签的font-size值,这样便可以一处修改,整个页面内容都会发生改变,即实现根据设备尺寸进行缩放的效果。
    REM方式进行移动端布局的原理都是相同的,但是不同的在与对于设备尺寸的检测上,就目前而言分为两种,一种是通过CSS meida查询,另一种则是通过JS检测。

    1. CSS Media

      @media screen and (min-width:320px) and (max-width:359px) {
        html {
          font-size: 50px;
        }
      }
      @media screen and (min-width:360px) and (max-width:374px) {
        html {
          font-size: 56.25px;
        }
      }
      @media screen and (min-width:375px) and (max-width:383px) {
        html {
          font-size: 58.59375px;
        }
      }
      @media screen and (min-width:384px) and (max-width:399px) {
        html {
          font-size: 60px;
        }
      }
      @media screen and (min-width:400px) and (max-width:413px) {
        html {
          font-size: 62.5px;
        }
      }
      @media screen and (min-width:414px) and (max-width:431px) {
        html {
          font-size: 64.6875px;
        }
      }
      @media screen and (min-width:432px) and (max-width:479px) {
        html {
          font-size: 67.5px;
        }
      }
      @media screen and (min-width:480px) and (max-width:539px) {
        html {
          font-size: 75px;
        }
      }
      @media screen and (min-width:540px) and (max-width:639px) {
        html {
          font-size: 84.375px;
        }
      }
      @media screen and (min-width:640px) {
        html {
          font-size: 100px;
        }
        body {
          max-width: 640px !important;
          margin: 0px auto !important;
        }
      }
      

      响应式REM布局的优点在于可以根据设计稿的特点,自定义的对某些设备进行单独适配,而缺点是检测规则固定不可变,这一点相比于“JS自动换算”更为明显。

    2. JS检测

      (function(win,doc){
      
          var timer = null,
              html = doc.documentElement,
              baseWidth = html.dataset.basewidth*1 || 640,
              metaEl = document.querySelector('meta[name="viewport"]'),
              event = 'onorientationchange' in win ? 'onorientationchange' : 'resize';
      
          if(!metaEl){
              metaEl = document.createElement('meta');
              metaEl.setAttribute('name','viewport');
              metaEl.setAttribute('content','initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0');
              html.firstElementChild.appendChild(metaEl);
          }
      
          function layoutCalc(){
      
              var width = html.getBoundingClientRect().width,
                  ratio = width / baseWidth * 100,
                  devicePixelRatio = window.devicePixelRatio,
                  rem = ratio < 100 ?  ratio < 50 ? 50 : ratio : 100;
      
              if(!/\.\d+/.test(devicePixelRatio.toString())){
                  html.dataset.dpr = devicePixelRatio;
              }
      
              html.style.fontSize = rem + 'px';
      
          }
      
          win.addEventListener(event,function(){
              clearTimeout(timer);
              timer = setTimeout(layoutCalc,300);
          },false);
      
          win.addEventListener('pageShow',function(e){
              if(e.persisted){
                  clearTimeout(timer);
                  timer = setTimeout(layoutCalc,300);
              }
          },false);
      
          layoutCalc();
      
      }(window,document));
      

      自定义基准页面尺寸:通过为 html 标签添加 data-basewidth 属性来自定义指定基准页面的尺寸。

      <html data-basewidth="750" >
      </html>
      

      定义页面内容的字体大小:对于一些符合标准的dpr(设备像素比https://blog.csdn.net/a419419/article/details/79295799)值(只要是整数,例如:1,2,3),都会为 html 标签再附加一个 data-dpr 属性,然后开发者便可以根据这个属性为条件,实现在不同dpr情况下,对内容字体的大小的调整

      html[data-dpr="1"] .dpr-text{
          font-size:12px;
      }
      html[data-dpr="2"] .dpr-text{
          font-size:24px;
      }
      html[data-dpr="3"] .dpr-text{
          font-size:36px;
      }
      
      <p class="dpr-text">测试文字</p>
      

      相比“响应式方式”JS自动换算无需添加规则,适合于各类型的显示设备。

  • vh/vw都是相对于视口的单位,浏览器视口的区域就是通过 window.innerWidth以及 window.innerHeigth 度量得到的范围。浏览器会将整个视口的宽度或者高度划分为100等份,因此1vw或者1wh就是相对视口宽度或者高度的1%。例如浏览器视口的宽度是1920,那么 1920/100 每等份即19.2px。

一行三列排版

contain & cover

  • contain: 此时会保持图像的纵横比并将图像缩放成将适合背景定位区域的最大大小。等比例缩放图象到垂直或者水平其中一项填满区域。
  • cover: 此时会保持图像的纵横比并将图像缩放成将完全覆盖背景定位区域的最小大小。等比例缩放图象到垂直和水平两项均填满区域。

Vue watch,computed和method区别

  • computed:计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。

    注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。

  • methods: methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++)。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.a 将是 undefined。

  • watch: 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue))。理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,this.updateAutocomplete 将是 undefined。

能使用watch属性的场景基本上都可以使用computed属性,而且computed属性开销小,性能高,因此能使用computed就尽量使用computed属性.当执行异步操作的时候你可能就必须用watch而不是computed了

Vue不能检测到对象属性的添加或删除:三种解决方法

  • 方案一:利用Vue.set(object,key,value)
  • 方案二:利用this.$set(this.object,key,value)
  • 方案三:利用Object.assign({},this.obj)

手写找出数组重复最多的元素

function findNum(a){
    var result = [0,0];
      for (var i = 0; i < a.length; i++) {
          for (var j = 0,count = 0; j < a.length; j++) {
              if (a[i]==a[j]) {
                ++count;
              };
          };
          if(count>result[0]) {
                result[0] = count;
                result[1] = a[i];
          }else if(count==result[0]&&result[1]<a[i]) {
                result[1] = a[i];
          }
    }
          alert("数"+result[1]+"重复了最多次,为"+result[0]);
}
  var arr = [2,2,3,3,3,4,4,4,4,4,4,4,4,43,3];
  findNum(arr);

Document.write()与innerHtml()区别

  • document.write是直接将内容写入页面的内容流,会导致页面全部重绘
  • innerHTML将内容写入某个DOM节点,不会导致页面全部重绘

实现http长连接

  • 先创建http请求方法,如图
  • 然后设置请求地址
  • 在然后需要设置下请求参数的编码格式一般设置成utf8
  • 然后就开始设置长连接了,这个主要是再header中设置Connection=keep-alive
  • 如果需要设置长连接的有效时间就在添加Keep-Alive:timeout=60
  • 完成长连接的header设置后就开始设置请求参数了
  • 最后就是执行者http的长连接请求了

在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。

而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:

Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

https://www.cnblogs.com/blogtech/p/10981606.html

Websocket

允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。

当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

var Socket = new WebSocket(url, [protocol] );

etag标签(实体标签)

ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证。

的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag 返回给浏览器,浏览器把"3f80f-1b6-3e1cb03b" 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: "3f80f-1b6-3e1cb03b" 的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。

ETag`HTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。

如果给定URL中的资源更改,则一定要生成新的Etag值。 因此Etags类似于指纹,也可能被某些服务器用于跟踪。 比较etags能快速确定此资源是否变化,但也可能被跟踪服务器永久存留。

css动画 transform,transition ,animation

  • transform:描述了元素的静态样式,本身不会呈现动画效果,可以对元素进行 旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix.

    transform常常配合transition和animation使用

  • transition样式过渡,从一种效果逐渐改变为另一种效果。transition是一个合写属性:

    transition:transition-property transition-duration transition-timing-function transition-delay//从左到右分别是:css属性、过渡效果花费时间、速度曲线、过渡开始的延迟时间
    
  • animation动画 由@keyframes来描述每一帧的样式

    div{
      animation:myAnimation 5s infinite
    }
    @keyframes myAnimation {
      0%{left:0;transform:rotate(0);}
      100%{left:200px;transform:rotate(180deg);}
    }
    

    (1)transform仅描述元素的静态样式,常常配合transition和animation使用

    (2)transition通常和hover等事件配合使用,animation是自发的,立即播放

    (3)animation可设置循环次数

    (4)animation可设置每一帧的样式和时间,transition只能设置头尾

    (5)transition可与js配合使用,js设定要变化的样式,transition负责动画效果

    /*css:*/
    div{
        width:100px;
        height:100px;
        transition:all 1s;
    }
    //js
    divEle.onclick = function(){
        divEle.style.width = "200px";
        divEle.style.height = "200px";
    }
    

浏览器兼容性问题与解决方案

https://blog.csdn.net/weixin_38536027/article/details/79375411

typeof 类型判断

  • 使用typeof()或者typeof进行基本数据类型检测,null是Null类型,属于基本类型,但是typeof null 返回的是字符串’object’;

     console.log(typeof undefined);//未定义undefined
     console.log(typeof null);//空值,对象类型
    
  • 引用类型只能使用 instanceof,基本数据类型无法使用instanceof 进行检测数据类型,因为基本数据类型使用instanceof进行检测,结果都是返回false

css中什么属性让字体更清晰

  • -webkit-font-smoothing

将-webkit-font-smoothing设置为antialiased,变得非常平滑,效果非常不错。

其默认可以支持6个值(如图),暂时我能看到效果的就是三个:
none(用于小像素文本) | subpixel-antialiased(默认) | antialiased(反锯齿)

this的指向问题

  • 在全局作用域中,this的指向是window对象
  • ES5函数中this的指向:
    在`非严格模式`下,函数中的this指向window对象,因为此时函数fn是window的一个属性,所以运行fn时,fn中的this指向window。其实this的指向就是指向函数的`运行时`环境。
    
    在`严格模式`下,若不使用window调用函数,函数中的this指向undefined;使用window调用时,指向的时window对象。
    
var fn = function () {
    'use strict'
    console.log(this);
    console.log(this === window)
}
fn();
//undfined
//false
window.fn();
//Window对象
//true
在`严格模式`下有一种例外的情况,就是在定时器中的this,此时无论使用window调用还是不使用window调用,this都指向window。
  • 在ES6中箭头函数this的指向:在ES6中箭头函数this的指向取决于定义时环境中的this指向一致
    var fun = () => {
        console.log(this);
        console.log(this === window);
    }
    fun();
    //Window对象
    //true
    //定义箭头函数时,就是这个过程:()=>{...}所在的环境是window,所以运行fun()时,箭头函数内部的this指向window
    
    var obj = {
        name:'Jay',
        age:25,
        fn:()=>{console.log(this)},
        fun:function(){
            console.log(this)
        }
    };
    //在定义fn时,fn内部this的指向就是定义obj对象时所在的环境,obj所在的环境是window,所以调用obj.fn()时,返回的this就是Window对象
    obj.fn(); //Window对象
    obj.fun();//{name: "Jay", age: 25, fn: ƒ, fun: ƒ}
    
    • 在DOM事件中的this指向
      DOM事件处理函数中this的指向是触发该事件的对象
      
<div id='app'>App</div>
<script>
   var $id = document.querySelector('#app');
   $id.onclick = function () {
       console.log(this);
   }
</script>
//当点击App时,console.log(this),打印出来的值时 <div id='app'>App</div>
  • 构造函数中的this指向

    构造函数中的this的指向是通过构造函数所创建出的对象实例

    function Person (){
        this.name = 'Jay',
        this.age = 25;
        console.log(this);
    }
    var p1 = new Person();
    //Person {name: "Jay", age: 25}
    
    改变this的指向

    可以使用call()、apply()、bind()改变函数内部this的指向(ES6中的箭头函数除外)。其中call()和apply()在传入要绑定的this指向时,立即执行。bind()在传入要绑定的this指向时,并不执行,需要再次调用才会执行。

    使用bind()改变this的指向

     var obj = {
        name:'Jay',
        age:25
    };
    function fn(){
        console.log(this===obj);
        console.log(this);
    }
    //fn.bind(obj);不会立即执行,需要再次调用才会执行。
    var fn1 = fn.bind(obj);
    fn1();
    //true
    //{name: "Jay", age: 25}
    

    需要注意的是,当使用call()、apply()、bind()改变函数内部this的指向时,如果传入的不是一个对象,会调用相对的构造函数,进行隐式类型装换。

    function fn(){
        console.log(typeof this === 'object');
        console.log(this);
    }
    fn.apply('I am a string');
    //true
    //String{"I am a string"}
    

CSS行内和块状元素的区别?

HTML可以将元素分类方式分为行内元素、块状元素和行内块状元素三种。首先需要说明的是,这三者是可以互相转换的,使用display属性能够将三者任意转换:

​ (1)display:inline;转换为行内元素

(2)display:block;转换为块状元素

(3)display:inline-block;转换为行内块状元素

行内元素特征:

(1)设置宽高无效

(2)对margin仅设置左右方向有效,上下无效;padding设置上下左右都有效,即会撑大空间

(3)不会自动进行换行

块状元素特征:

(1)能够识别宽高

(2)margin和padding的上下左右均对其有效

(3)可以自动换行

(4)多个块状元素标签写在一起,默认排列方式为从上至下

行内块状元素特征

(1)不自动换行

(2)能够识别宽高

(3)默认排列方式为从左到右

scrollHeight、scrollTop、clientHeight、offsetHeight区别

  • scrollHeight:返回当前整个元素的高度(包括带滚动条的隐蔽的地方
  • scrollTop:clientHeight的顶部到scrollHeight顶部的高度
  • offsetTop :指当前元素距离上方或上层元素的距离
  • clientHeight: 返回当前元素在页面上的可视高度(包括padding;不包括border、margin、滚动条高度
  • offsetHeight:返回当前元素在页面上的可视高度(包括padding、border、滚动条高度;不包括margin

对HTML语义化标签的理解

HTML标签可以分为有语义的标签,和无语义的标签。比如table表示表格,form表示表单,a标签表示超链接,strong标签表强调。无语义标签典型的有div,span等。

  • 为什么要进行语义化?
      1,现在的开发基本上都是一个团队合作进行开发。这种情况下,我们写的代码不仅要让我们自己能看懂,而且也应该让别人也容易理解和阅读,要保证代码的可维护性,这一点很重要。但是在实际开发中,由于HTML的灵活性,以及CSS的强大,以至于实现同一种界面样式,不同的人写出来的代码可能实现方式都不太一样。实现糟糕的,可能全是div套div,这样的代码到时候维护的话可能就是一场灾难。这一点,个人觉得是最主要的因素。
      2,和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息
      3,考虑到代码的可复用性,可移植性,方便其他设备的解析执行。移动设备、盲人阅读器等。
  • 使用HTML语义化好处
    html语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;
    即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;
    搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于SEO;
    使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
  • 14
    点赞
  • 147
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程轨迹_

期望和你分享一杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值