幽灵节点

因为行内块状元素默认是以文字的基线对齐的造成的,

line-height和vertical-align都与基线有关。line-height行高定义是两个基线之间的距离,vertical-align的默认值是baseline就是基线对齐

  1. 解决方法:修改line-height大小
1
2
3
<div class="con">
<img src="../img/jiaoyue.png" /><span>I am very good</span>
</div>
1
2
3
4
5
6
7
8
.con{
border:1px solid red;
font-size: 0;
line-height: 0;
}
.con span{
font-size: 16px;
}

2、修改vertical-align对齐方式

1
2
3
4
5
6
7
8
9
10
11
.con{
border:1px solid red;
}
.con span{

}
img{
height:50px;
width:50px;
vertical-align:bottom
}

3、让vertical-align失效:设置元素为block即可

画0.5px

  1. 采用meta viewport

    1
    <meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>
  2. 采用transform:scale()

    1
    transform: scale(0,0.5);
  3. 渐变

    1
    background: linear-gradient(0deg, #fff, #000);

泛洪攻击

SYN泛洪攻击

SYN攻击利用的是TCP三次握手机制,攻击端利用伪造的IP地址向被攻击端发出请求,而被攻击端发出的响应报文将永远发送不到目的地,那么被攻击端在等待关闭这个连接的过程中消耗了资源,如果有成千上万的这种连接,主机资源将被耗尽,从而达到攻击的目的。我们可以利用路由器的TCP拦截功能,使网络上的主机受到保护(以Cisco路由器为例)。

DHCP(动态主机配置协议)报文泛洪攻击

ARP报文泛洪攻击

为什么vue的data返回的是函数

数据以函数返回值形式定义,这样每复用一次组件,就都会返回一份新的data,类似于给每个组件实例都创建以一个私有的数据空间,让每个组件实例维护各自的数据。而单纯的写对象就会导致所有实例共用一份data数据。

行内元素、块状元素

行内-line

  • 设置宽高无用
  • margin只有左右有用上下无用;padding上下左右都可以
  • 不会自动换行

块状-block

  • 直接占一行
  • 能识别宽高,margin和padding都有效
  • 自动换行

行内块-inline-block

  • 能识别宽高
  • 从左到右排列
  • 不自动换行

避免ajax中get方法产生缓存

get请求存在缓存,可以减少服务器运行的压力。但是会影响程序的正常运行。出现信息与数据库匹配的问题。

在参数中传一个随机数,就会避免浏览器对get方法异步修改数据缓存,导致不能及时看到最新效果

1
2
var time = new Date().getTime();
xhr.open("GET","User.do?_=time&username="+username,true);

正则匹配

  • [^ABC]匹配除了[…]中的东西
  • [A-Z] 匹配这区间内的
  • [.] 匹配除了换行符(\n, \r)之外的任何单字符
  • [\s\S] 匹配所有,\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。
  • \w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]

CI/CD

CI 持续集成

自动构建和测试应用软件

CD 持续部署

githook

在Git 在事件之前或之后执行的脚本, 用于控制 git 工作的流程。

使用cookie、token的前端鉴权问题

  • cookie无法跨域
  • 移动端支持的不好
  • 容量、性能缺陷,紧跟域名不必要时也带上造成消耗,安全问题容易被篡改。
  • cookie本身不是用来做本地存储的,主要用来解决http无状态协议的状态管理不足有关的。

token

  • 可避开同源策略
  • 不参与与服务器的通信,避免CSRF攻击,没有cookie的性能安全问题

OAuth

DNS优化解析查找

首先解析dns的顺序:浏览器缓存>系统缓存>路由器缓存>ISP DNS缓存>到根域名服务器开始进行递归查询。

DNS prefetch(预读取)

在加载网页页面的时候,对网页中的的herf属性中的域名进行后台预解析,将解析结果缓存到浏览器端。

判断网页来源

referer:判断是从哪个网址来的

navigator.userAgent(platform):匹配从哪个设备来的

common.js和ES6的区别

  • CommonJS 模块是运行时加载,加载整个模块。而ES6 模块是编译时输出接口,需要啥加载啥
  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。(只读引用)

参考

CSS的样式隔离

  • 命名空间:
    这很好理解,其实就是给每个不同模块使用的css规划好命名,这样所有的css就都不会出现冲突,这种方法虽然很好理解和简单,但是编写起来很繁琐,维护成本会很高,当然,现在也有打包工具很容易就可以实现就是了。

  • css Modules:
    这其实跟命名空间有点类似,vue应该就是使用类似的方法,给选择器加上特殊的字符串,达到css隔离的效果。

  • css-in-js:

    styled-components是一个针对React的 css in js 类库,降低js对css文件的依赖,组件样式隔离避免样式污染。

  • Shadow DOM:
    Shadow-dom 是游离在 DOM 树之外的节点树,但是他的创建基于普通 DOM 元素(非 document),并且创建后的 Shadow-dom 节点可以从界面上直观的看到。更重要的是,Shadow-dom 具有良好的密封性。

css样式隔离

CSS 百分比参照问题

可以对元素的margin设置百分数,百分数是相对于父元素的width计算,不管是margin-top/margin-bottom还是margin-left/margin-right。(padding同理)

为什么margin-top/margin-bottom的百分数也是相对于width而不是height呢?
CSS权威指南中的解释:
我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距是父元素的
height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,
上下外边距因为父元素height的增加也会增加,如此循环。而相比之下,width更加稳定。

XMLHttpRequest超时

XMLHttpRequest.timeout代表着一个请求在被自动终止前所消耗的毫秒数。默认值为 0,意味着没有超时。

在IE中,超时属性可能只能在调用 open() 方法之后且在调用 send() 方法之前设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);

xhr.timeout = 2000; // 超时时间,单位是毫秒

xhr.onload = function () {
// 请求完成。在此进行处理。
};

xhr.ontimeout = function (e) {
// XMLHttpRequest 超时。在此做某事。
};

xhr.send(null);

或者:在调用XMLHttpRequest的send方法后,调用setTimeout方法,设置超时时间值。在调用成功的方法内,调用clearTimeout()方法清除超时设置。

js千分数

1
let num = 1234567890;num.toLocaleString();

package.json

  • ~符号,匹配最近小版本依赖包。1.2.3匹配所有的1.2.x,不包括1.3.0。
  • ^ 符号,尽量使用最新版本,但是保证不产生兼容性,1.2.3匹配所有1.x.x的包,不包括2.0.0。

推荐~更稳定

两个tab(同源网页)之间的通信

  1. localstorage
  2. cookie
  3. window.postMessage()

类型转换问题

1
[] 转为字符串是 ""       // String([]) 返回""[] 转为数字是 0            // Number([]) 返回0[] 转为布尔值是 true        // Boolean([]) 返回true

函数柯里化

1
function add(x) {    var sum = x;    var tmp = function (y) {        sum = sum + y;        return tmp;    };    tmp.valueOf = function () {        return sum;    };    return tmp;}
1
function add(num){    let sum=0;    sum = sum+num;    let tempFun=function(numB){        if(arguments.length===0){            return sum;        }else{            sum= sum+ numB;            return tempFun;        }    }        tempFun.valueOf=function(){        return sum;    }    tempFun.toString=function(){        return sum+'';    }        return tempFun;}var result=add(2)(3)(4)(5)();

当一个对象转换成原始值时,先查看对象是否有valueOf方法,如果有并且返回值是一个原始值,
那么直接返回这个值,否则没有valueOf或返回的不是原始值,那么调用toString方法,返回字符串表示

判断当前网页是否被用户使用

  • window.onblur & window.onfocus

需要页面起码被用户操作后才可以触发这两个事件

  • document.hidden

true时被隐藏,false正常显示包括被其他应用挡住。

大量数据处理

  • 分页
  • 懒加载

优化措施

一些大量的计算逻辑可以单独开一个web worker来处理

Keep-alive原理

也是如同定义了一个组件一样,在定义为keep-alive之后再设置abstract: true(该属性可以是当前组件的虚拟dom不渲染成真实dom

1
// src/core/components/keep-alive.jsexport default {  name: 'keep-alive',  abstract: true, // 判断当前组件虚拟dom是否渲染成真实dom的关键  props: {      include: patternTypes, // 缓存白名单      exclude: patternTypes, // 缓存黑名单      max: [String, Number] // 缓存的组件  },  created() {     this.cache = Object.create(null) // 缓存虚拟dom     this.keys = [] // 缓存的虚拟dom的键集合  },  destroyed() {    for (const key in this.cache) {       // 删除所有的缓存       pruneCacheEntry(this.cache, key, this.keys)    }  }, mounted() {   // 实时监听黑白名单的变动   this.$watch('include', val => {       pruneCache(this, name => matched(val, name))   })   this.$watch('exclude', val => {       pruneCache(this, name => !matches(val, name))   }) }, render() {    // 先省略... }}

created

初始化缓存vnode和vnode对应键的集合

destroyed

删除cache中缓存的vnode实例

mounted

实时监听黑白名单的改变

render

第一步:获取keep-alive包裹着的第一发个子组件对象及其组件名;

第二步:根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则执行第三步;

第三步:根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键),否则执行第四步;

第四步:在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key);

第五步:最后并且很重要,将该组件实例的keepAlive属性值设置为true。(设置过后会不再进入$mount环节,在mounted之前的就都不会执行了)

渲染过程

vue

  1. 先调用原型上的_render函数将组件转换成VNode实例, _render调用createElement和createEmptyVNode进行转换。
  2. createElement有根据不同场景选择new VNode或者createComponent来完成VNode实例化
  3. 完成实例化后再调用_update函数把VNode渲染成真实DOM,在patch阶段调用完成

template

  1. 是否有el对象,无则挂载,有则判断是否有模板(template)
  2. 有模板则将模板转换编译为render函数,无则编译el对象外层html为模板
  3. 实例进行挂载,根据根节点render函数的调用,递归生成虚拟dom
  4. 通过diff算法对比渲染到真实dom
  5. 组件内部data发生变化的时候,组件和子组件引用props重新调用render函数,生成虚拟dom,重返第4步

判断区分数字的方法

如果参数值为 NaN 或字符串、对象、undefined等非数字值则返回 true, 否则返回 false

1
isNaN(“Hello”)  //trueisNaN(2187309) //false

字符串复制指定次数

1
let str='asd'str.repeat(3)

Web Components

  1. window.customElement.defind(‘user-card’, UserCard) ps:UserCard是一个定义的类

  2. 结合第一个方法更加简单的写模板

  3. Shadow DOM

    • this.attachShadow()方法的参数{ mode: 'closed' },表示 Shadow DOM 是封闭的,不允许外部访问

参考

webpack流程

  • 初始化流程:从配置文件和 Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数
  • 编译构建流程:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
  • 输出流程:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到文件系统

ES5和ES6类写法

  • es6
1
class Person{  constructor(){    this.name = 1  }}class Child extends Person{    //构造函数    constructor(name,age) {      super(name)//相当于获得父类的this指向      this.age = age;//自己的私有属性    }let child = new Child();
  • es5
1
let Person = (function(){  function Person(name){    this.name = name;  }  Person.prototype.get = function(){    return this.name;  }    return Person;})()var p = Person()

链表和数组

主要区别在动态性和空间消耗上。

使用链表结构可以客服数组链表需要预先知道数据大小的缺点,也是可以充分利用计算机内存空间实现灵活的内存动态管理。

但是也是去了数组随机读取的优点,还因为增加节点的指针域,空间开销变大。

1
function linkedList(){      // 封装一个内部类      function Node(data){        this.data = data;        this.next = null;      }      // 属性,声明一个链表头和链表的长度      this.head = null;      this.length = 0;}

Symbol的用处

  • 因为不可被枚举遍历,可以用来存一些不需要遍历和处理的数

  • 用其替代常量,可以不用思考怎么命名不会重复的常量,他们都是唯一的。

    • const TYPE_AUDIO = Symbol()const TYPE_VIDEO = Symbol()
      
      1
      2
      3
      4
      5

      - 使用Symbol定义类中的私有方法和属性

      - ```js
      const PASSWORD = Symbol()class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd }}export default Login
      调用时
      1
      import Login from './a'const login = new Login('admin', '123456')login.checkPassword('123456')  // truelogin.PASSWORD  // oh!no!login[PASSWORD] // oh!no!login["PASSWORD"] // oh!no!

参考

哈希表、冲突、解决方法

哈希表是一个基于数组的存储方式,由哈希函数和数组构成。

存储数据时用函数计算数据的地址,再将数据存进指定地址位置的数组中。函数就是哈希函数,而这个数组就是哈希表。

哈希冲突是指哈希函数算出来的地址被别的元素占用。

解决方法:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址)

css的+、~

  • +加选择器

如果要选择紧接在一个元素后的另一个元素,而且二者有相同的父元素。可以使用相邻兄弟选择器。

这里面的 + 只会影响下一个p标签的样式,不会影响上一个 p 标签的样式。

  • ~选择器

目的是查找某一个元素后的所有节点

实现localStorage的跨域

使用postMessage和iframe结合。

babel转const(es5实现const)

通过Object.defineProperty()为数据对象定义writable:false