幽灵节点
因为行内块状元素默认是以文字的基线对齐的造成的,
line-height和vertical-align都与基线有关。line-height行高定义是两个基线之间的距离,vertical-align的默认值是baseline就是基线对齐
- 解决方法:修改line-height大小
1 | <div class="con"> |
1 | .con{ |
2、修改vertical-align对齐方式
1 | .con{ |
3、让vertical-align失效:设置元素为block即可
画0.5px
采用meta viewport
1
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>
采用transform:scale()
1
transform: scale(0,0.5);
渐变
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 | var time = new Date().getTime(); |
正则匹配
[^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无法跨域
- 移动端支持的不好
- 容量、性能缺陷,紧跟域名不必要时也带上造成消耗,安全问题容易被篡改。
- 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 百分比参照问题
可以对元素的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,意味着没有超时。
1 | var xhr = new XMLHttpRequest(); |
或者:在调用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(同源网页)之间的通信
- localstorage
- cookie
- 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
- 先调用原型上的_render函数将组件转换成VNode实例, _render调用createElement和createEmptyVNode进行转换。
- createElement有根据不同场景选择new VNode或者createComponent来完成VNode实例化
- 完成实例化后再调用_update函数把VNode渲染成真实DOM,在patch阶段调用完成
template
- 是否有el对象,无则挂载,有则判断是否有模板(template)
- 有模板则将模板转换编译为render函数,无则编译el对象外层html为模板
- 实例进行挂载,根据根节点render函数的调用,递归生成虚拟dom
- 通过diff算法对比渲染到真实dom
- 组件内部data发生变化的时候,组件和子组件引用props重新调用render函数,生成虚拟dom,重返第4步
判断区分数字的方法
如果参数值为 NaN 或字符串、对象、undefined等非数字值则返回 true, 否则返回 false
1 | isNaN(“Hello”) //trueisNaN(2187309) //false |
字符串复制指定次数
1 | let str='asd'str.repeat(3) |
Web Components
window.customElement.defind(‘user-card’, UserCard)
ps:UserCard是一个定义的类结合第一个方法更加简单的写模板
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 Login1
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