- 语义
- 区块和段落元素
- section article nav header footer aside hgroup
- 音频和视频
- audio video
- 表单改进
- 提供强制校验的API
- 内置提供:valid和:invalid这两个伪类,来设置元素通过或未通过时的样式
- required属性 如果输入为空,表单不会提交,并会提示错误
- pattern属性 支持正则表达式
- minlength maxlength 来强制条目的长度
- output元素:执行计算然后在output元素中展示结果
- 提供强制校验的API
- 改进iframe,新增sandbox seamless srcdoc属性
- 区块和段落元素
- 流通性(通信)
- Web sockets
- 在单个TCP连接上进行全双工通讯的协议
- 替代了Ajax轮询(缺点是:每次都包含体积很大的HTTP请求头,节省了服务器资源和带宽)的方案
- [https://www.runoob.com/html/html5-websocket.html]
- 服务器向浏览器推送事件,允许网页自动获得来自服务器的更新
- webRTC 即时通信,类似于视频会议
- Web sockets
- 离线 & 存储
- 离线资源缓存
- 在线和离线事件,用于检测是否存在可用网络连接
- 客户端会话和持久化存储(DOM存储)
- IndexedDB 能够在浏览器存储大量结构化数据
- 多媒体
- audio video
- WebRTC 即时通信
- 提供camera api,允许使用计算机的摄像头
- 绘画 & 效果
- canvas
- WebGL 3D图像效果
- SVG
- 性能 & 集成
- web workers 把JavaScript计算委托给后台线程
- History API 允许操作浏览器的历史记录
- contentEditable标准化
- 拖放API
- requestAnimationFrame 允许控制动画渲染以获得更优性能
- 全屏API
- 在线离线事件(处于当前tab和离开当前tab)
- 设备访问
- 摄像头
- 触控事件
- 地理位置定位
- 检测设备方向
面试学习5
css3动画
transition
- transition: 执行变化的属性 变化持续的时间 变化的样式
- 并不是所有的属性都支持
- 需要事件触发,没办法自动发生
1
transition: all 2s ease-in-out
animation
- 可以设置任意多的关键帧,所以动画比较丰富
1
2
3
4
5@keyframes 动画名 {
0% { top: 0; left: 0px}
50% { top: 30px; left: 20px; }
100% { top: 0; left: 30px;}
}
transform
- 顾名思义就是变形的意思,这里涉及的变形包括rotate旋转、skew扭曲、scale缩放、translate移动、matrix矩阵变形
- 常用的有:translate(x,y)进行2d转换、scale(x,y)进行2d缩放、rotate(角度数)进行2d旋转
类数组转数组
- Array.prototype.slice.call(类数组),因为数组slice方法如果不带任何参数,就是默认将数组从头到尾都浅拷贝一份
- Array.from()
- 对于有遍历器接口的类数组,可以直接使用扩展运算符
关于this
- this指向:指向最后一个调用它的对象
- 如何改变this指向
- new
- 箭头函数
- call/apply/bind
- _this = this
函数调用有4种方式:直接调用、作为对象的方法、构造函数、call/apply
dns解析过程
- 浏览器缓存
- 操作系统缓存
- 本地Host文件
- 路由器缓存
- 运营商DNS服务
- 根域名服务器
- 顶级域名服务器
- 主域名服务器
- 保存结果至缓存
TCP三次握手主要目的是要数据的发送和接收同步,通俗地讲就是
- A:要连接你
- B:好的收到,是现在连接吗
- A:现在连接吧
TCP四次挥手
- A:我要走了
- B:好的收到,要等一下,我这边还有几句话没说完
- B:我说完了,可以走了
- A:那拜拜了
TCP和UDP的区别
- 有连接和无连接
- 保证数据的正确性和可能发生丢包
- 保证数据顺序,后者不保证
==运算符会首先将操作对象转化为相同类型,具体表现为
- 只要其中有一个是NaN,就返回false
- 如果两个都是null或者undefined,返回true
- 如果两个都是基本数据类型,且类型不同,则将两者都将转化数值类型再比较
- 如果是引用类型值,则将其转化为基本类型再比较
bfc三个特性
- 防止外边距折叠(margin塌陷)
- 包含浮动元素
- 防止内容被浮动元素覆盖
如何获取url信息
- URL很多信息都存储在window.location这个属性中,打印即可
- 经常会用到如何获取URL的参数及参数值,具体如下:
1
2
3
4
5
6
7
8
9
10
11
12function GetRequest() {
var url = window.location.search; //获取url中"?"符后的字串
var theRequest = new Object()
if (url.indexOf("?") != -1) {
var str = url.substr(1)
strs = str.split("&")
for(var i = 0; i < strs.length; i ++) {
theRequest[strs[i].split("=")[0]]=unescape(strs[i].split("=")[1])
}
}
return theRequest
}
es5和es6关于类的区别
- 前者的toString方法是可枚举的,后者不可枚举
面试学习4
浏览器跨标签通信
获取句柄,父页面通过window.open()这个接口打开子页面,然后设置当子页面加载onload的时候,将传递的信息作为postMessage的参数;这时子页面上就可以调用window.onmessage接口,获取到父页面传递过来的信息
1
2
3
4
5
6
7
8
9//A.html
const child = window.open('child.html', 'child')
child.onload = () => {
child.postMessage('message', location.origin)
}
//B.html
window.onmessage = event => {
event.data
}localstorage、cookie
内存泄漏
- 意外的全局变量,使得这个变量挂在window对象上,没办法被清除,解决方法是:使用严格模式、将其设置为null
- 忘记关停定时器,导致定时器内的dom节点一直被引用,没办法回收
- 没有移除事件监听器
- 闭包
- 本以为已经移除了一些没用的dom节点,没想到移除的dom节点还被其他节点所引用,导致无法彻底移除
面试学习3
盒模型
- IE盒模型
- width = border + padding + content
- W3C标准盒模型
- width = content
可以通过box-sizing来设置不同的盒模型,该属性默认是content-box,可以改为border-box
怪异模式和标准模式
- 盒模型不同
尽量用border-box,这样可以直接设置子元素的width,不受padding的影响
new这个过程发生了什么
- 创建了一个空对象
- 将构造函数的this指向这个空对象
- 为新对象添加属性
- 返回新对象
vue双向绑定原理:数据劫持、发布-订阅模式
具体实现:数据劫持是通过Object.defineProperty()
视图到数据这一块可以通过事件监听来实现
比较关键的就是数据到视图这一块
定义一个observer观察者,用来劫持并监听所有数据的变化,如果有变化,就通知订阅者
定义一个watcher订阅者,接收来自观察者的信息,当数据发生变化时,执行函数,更新视图
定义一个compile,用来扫描解析节点和指令、初始化模板数据、初始化订阅者
任何没有设置doctype的Html都将以混杂模式来解析
浅拷贝
- object.assgin
- 展开运算符
深拷贝
- JSON.parse(JSON.stringify(obj))
- 递归逐一赋值
new运算符的执行过程
- 创建一个空对象
- 将构造函数的this指向空对象
- 为空对象添加属性
- 返回该对象
es6推出的新数据结构set和map
- set集合中的元素是唯一的、不重复
- map和对象类似,区别在于map的键可以是任意数据类型
- 两者都提供了一些方法,让我们处理数据
函数柯里化
- 为函数预置参数,以便重复利用
数组乱序1
2
3arr.sort(function (){
return Math.random() - 0.5
})
数组扁平化1
2
3arr.flat = function (){
return this.toString().split(',').map(item => +item)
}
数组去重1
2
3
4
5
6
7
8
9function only(arr){
var newarr = []
for(var i = 0; i < arr.length; i++){
if(newarr.indexOf(arr[i]) == -1){
newarr.push(arr[i])
}
}
return newarr
}
面试学习2
正则去掉字符串首尾空格
- str.replace(/(^\s)|(\s$)/g, ‘’)
输入URL发生了什么
- 当发送一个 URL 请求时,不管这个 URL 是 Web 页面的 URL 还是 Web 页面上每个资源的 URL,浏览器都会开启一个线程来处理这个请求,同时在远程 DNS 服务器上启动一个 DNS 查询(浏览器缓存->系统缓存->路由器缓存)。这能使浏览器获得请求对应的 IP 地址。
- 浏览器与远程 Web 服务器通过 TCP 三次握手协商来建立一个 TCP/IP 连接。该握手包括一个同步报文,一个同步-应答报文和一个应答报文,这三个报文在 浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,而后服务器应答并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
- 一旦 TCP/IP 连接建立,浏览器会通过该连接向远程服务器发送 HTTP 的 GET 请求。远程服务器找到资源并使用 HTTP 响应返回该资源,值为 200 的 HTTP 响应状态表示一个正确的响应。
- 此时,Web 服务器提供资源服务,客户端开始下载资源。
- 浏览器解析HTML生成DOM树,在根据CSS生成渲染树;浏览器缓存相应的信息,查看是否需要更新缓存;呈现页面。
缓存4个字段及优先级
- Expires
- Cache-control:max-age=6000(毫秒)/no-cache/no-store/private/public
- last-modified
- Etag
强缓存>弱缓存
cache-control>expires
ETag > Last-Modified
ctrl f5 所发送的请求头包含no cache,才会跳过缓存;f5发送请求头中会触发协商缓存
性能优化:重排重绘、事件委托、异步无阻塞加载js、懒加载、虚拟列表、缓存、代码分割、雪碧图、减少HTTP请求
- 编码优化
- 提高数据读取速度,缓存对象成员值
- DOM
- 缓存DOM属性和元素
- 重排、重绘时,先让元素脱离文档流,操作完毕后再插入文档流,减少重排重绘次数
- 事件委托
- 流程控制
- 避免使用for in
- 减少迭代
- 静态资源优化
- 压缩静态文本?
- 图片优化
- 响应式图片
- 视频替换gif图
- 交付优化
- 异步无阻塞加载JS
- script放底部
- deferer async
- 动态创建script标签
- ajax请求js代码注入页面
- 懒加载
- 优先加载关键css
- 资源提示
- dns-prefetch
- preconnect
- prefetch
- prerender
- preload
- 快速响应的用户界面
- 骨架屏
- loading动画
- 异步无阻塞加载JS
- 构建优化
- 预编译
- 代码分割
- 服务端渲染
- import函数导入模块
- 善用缓存
css3动画和js动画的区别
- css
- 浏览器对前者会进行一定的优化
- 自然降级
- js
- 兼容性好
- 效果丰富
移动端兼容
点击事件有300ms延迟,可以用fastclick解决,或者使用zepto的touch模块
非可点击元素监听click事件,需要设置cursor: pointer
h5底部输入框被键盘遮挡
css动画页面闪白、卡顿,解决:可能地使用合成属性transform和opacity来设计CSS3动画
移动端布局
- 响应式布局,媒体查询
- rem,根据font-size来布局
- 设置viewport中的width
- vm + rem 对于vm的兼容性,可以使用viewport-units-polyfill解决
1像素问题
- 物理像素和逻辑像素,之间存在一个比例关系,可以通过window.devicePixelRatio获取,所以设计稿上的1px,在实际上会比较粗
- 解决方案
- 媒体查询,根据-webkit-min-device-pixel-ratio的不同,来设置小数像素
- 用js来获取这个比例,再设置小数像素
- border-image
- background-image
腾讯一面总结
json jsonp
- json是一种数据格式;
- jsonp是一种数据调用格式,带callback的json就是jsonp
- 利用script标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个script元素,地址指向第三方的API网址,并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如:callback({“name”:”hax”,”gender”:”Male”}) 这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。主要是利用了html标签的src属性没有同源限制,也就是支持跨域
domready onroad
- 首先要清楚dom文档加载的步骤为:1.解析html结构;2.加载外部脚本和样式表文件;3解析并执行脚本;4.dom树构建完成;5.加载图片等外部文件;6.页面加载完毕。domready(也叫DOMContentLoaded ),在第4步完成后触发;图片onload是在第5步完成后触发;页面onload是第6步完成后触发。由此可见三者执行顺序为:domready→图片load→页面load。
- domready和onload事件区别,前者:在DOM文档结构准备完毕后就可以对DOM进行操作;后者:整个document文档(包括图片等加载信息)加载完成后才能对DOM进行操作。关键区别就在于后者需要等待图片等资源加载完毕后才执行
js事件(捕获 冒泡)
- dom2级事件
- 事件流:从页面接收事件的顺序,主要分为事件冒泡流和事件捕获流
- 事件冒泡:事件从嵌套层次最深的最具体的元素接收,然后逐级向上传播到不具体的节点;事件捕获则反之
- 三个阶段:捕获阶段、目标阶段、冒泡阶段
事件处理程序:dom0级、dom2级:addEventListener、removeEventListener
1
2
3btn.addEventListener("click", function(){
alert(this.id);
}, false);true代表在捕获时调用,false代表在冒泡时调用,这样可以添加多个事件处理程序
- 一般都是将事件处理程序添加到冒泡阶段,兼容性更好
- 事件委托(事件代理)
作用域链是在定义时还是执行时创建的?
- 执行环境中所有的变量和函数都保存在变量对象中,由解析器在后台使用
- 每个函数都有自己的执行环境
- 当代码在一个环境中执行时,会创建变量对象的一个作用域链,这说明函数定义时没有作用域链存在,只有调用时有
- 作用域链最前端是当前执行代码的变量对象,如果环境是函数,则变量对象是活动对象
- 作用:标识符解析
原生ajax post请求
- XMLHttpRequest对象
- open方法,接收三个参数:get或post、请求Url、是否异步发送
send方法
1
2
3
4
5
6
7xhr.open("get", "example.txt", false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}发送异步请求,需要检测XHR对象的readyState属性,这个属性一变化,就会触发readystatechange事件
1
2
3
4
5
6
7
8
9
10
11
12var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){ // 4代表已经接收到全部响应数据
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
xhr.send(null);
异步script加载方式
- 脚本加载会导致DOM构建停止,出现白屏,所以一般都是把脚本放在body标签底部位置进行加载
除了底部加载脚本这个方法,还有其他方法解决阻塞问题?
- defer属性
- 渲染文档的时候,异步下载资源,但不会立即执行,会等到所有元素解析完再执行
- 兼容性问题,只被Internet Explorer 4+和Firefox 3.5+支持,不是理想方案
- async属性
- 在渲染文档是异步下载资源
- defer和async的区别
- defer按顺序执行,async乱序
- defer下载完后不会立即执行;而async下载完后会立即执行,因此执行过程中也会阻塞元素渲染
动态脚本加载,是非阻塞Javascript下载中最常用的模式,因为它可以跨浏览器,而且简单易用
1
2
3
4var script = document.createElement ("script");
script.type = "text/javascript";
script.src = "file1.js";
document.body.appendChild(script);用XHR对象下载代码,并注入到页面
- defer属性
基本类型值 引用类型值
- undefined null boolean string number object symbol这七种数据类型
- 基本数据类型是按值访问的,存放在栈内存中
- 引用类型值是按引用访问的,存放在堆内存中
- typeof能够返回 undefined null boolean string number object function
- 如何检测一个数组是数组?
- instanceof
- 原型链方式 数组.proto.constructor===Array
- Object.prototype.toString.call(数组)
- Array.isArray()
内存泄漏
- 如果闭包的作用域链中保存着一个HTML 元素,那么就意味着该元素将无法被销毁
- 需要解除对DOM对象的引用
xss跨站脚本
- 反射型(非持久型)
- 对于 xss 反射型攻击,主要是诱使用户点击恶意的链接或者访问存在漏洞的内容,可以有如下方式:
- 攻击者可以将恶意链接直接发送给受信任用户,发送的方式有很多种,比如 email, 网站的私信、评论等
- 攻击者可以购买存在漏洞网站的广告,将恶意链接插入在广告的链接中
- 对于 xss 反射型攻击,主要是诱使用户点击恶意的链接或者访问存在漏洞的内容,可以有如下方式:
- 存储型(持久型)——>>>输入检查
- 将一段恶意代码写在评论中,等待其他用户浏览评论时,就自动执行了js代码(获取cookie,并传输给攻击者的服务器);
- 基于DOM ——>>>输出检查
- 通过恶意脚本修改DOM结构
- 如何防范?
- HttpOnly 防止劫取 Cookie
- 输入检查,对用户输入进行检查、过滤和转义
- 输出检查,在变量输出到html页面时,将其进行编码或转义
- 反射型(非持久型)
csrf跨站请求伪造
- 劫持受信任用户向服务器发送非预期请求
- 攻击者借助受害者的cookie骗取服务器的信任
- 涉及到浏览器的cookie策略
- cookie有两种:会话期cookie和持久性cookie,后者可以指定过期时间
- 攻击者放了一个链接,这个链接指向一些删除操作,主要目的是改变服务器的数据
如何防范?
- 验证码
referer check
- 在http请求头中的referer字段,表示该请求的来源地址
对每一个删帖请求,验证其referer值,如果该值指向其他网站,那就有可能是跨站伪请求
1
2
3
4if (req.headers.referer !== '正确的站点地址') {
res.write('csrf 攻击');
return;
}检查referer,还能防止图片盗链
- 当referer为空时, 返回正确的图;当referer不为空, 且host命中我的目标网站时, 返回正确的图;当referer不为空, 但host未能命中我的目标网站时, 返回错误的图
- 添加token验证
- 基本思路是在请求中添加一些攻击者无法伪造的信息,这些信息也不能存储在cookie中。在请求中添加一个类似随机数的token,服务器建立拦截器来验证
二叉树与二叉查找树
什么是树?
- 树由一组以边连接的节点组成
一棵树最上面的节点称为根节点
一个节点下面有多个节点,那这个节点被称为父节点
没有任何子节点的节点称为叶子节点
从一个节点到另一个节点的这一组边被称为路径
以某种顺序访问树中所有节点称为树的遍历
树的层数就是树的深度
每一个节点都有一个与之相关的值,这个值被称为键
二叉树是一种特殊的树,它的特点是子节点的个数不超过两个
二叉查找树是一种特殊的二叉树,特点是较小的值保存在左节点,较大的值保存在右节点
无论是二叉树还是二叉查找树,都是由节点组成的,因此我们首先定义Node节点类1
2
3
4
5
6
7
8
9
10function Node(data, left, right){
this.data = data
this.left = left
this.right = right
this.show = show
}
function show(){
return this.data
}
接下来就可以定义一棵二叉查找树了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31function BST(){
this.root = null
this.insert = insert
this.inOrder = inOrder
}
function insert(data){
let node = new Node(data, null, null)
if(this.root == null){
this.root = node
}else {
let current = this.root
let parent
while(true){
parent = current
if(data < current.data){
current = current.left
if(current == null){
parent.left = node
break
}
}else{
current = current.right
if (current == null) {
parent.right = node
break
}
}
}
}
}
至此,我们已经能够向二叉树中插入节点了,我们还需要能够遍历这棵二叉树(以一定的顺序来显示节点)
遍历二叉树有三种方式:中序,先序,后序。其中,中序按节点键值的升序来遍历;先序则是先访问根节点,再访问左子树和右子树;后序则先访问叶子节点,然后是左子树、右子树、根节点1
2// 中序代码如下
function
数据结构篇——集合
集合中的元素被称为成员,这种数据结构有两个特点:
- 集合内的成员是无序的
- 集合内的成员不可重复
在这里我们用数组来实现集合Set类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94function Set() {
this.dataStore = []
this.add = add
this.remove = remove
this.size = size
this.union = union
this.intersect = intersect
this.subset = subset
this.difference = difference
this.show = show
}
function add(data){
if(this.dataStore.indexOf(data) < 0){
this.dataStore.push(data)
return true
}else {
return false
}
}
function remove(data){
let pos = this.dataStore.indexOf(data)
if(pos > -1) {
this.dataStore.splice(pos, 1)
return true
}else {
return false
}
}
// 判断一个元素是否在集合中
function contains(data){
if(this.dataStore.indexOf(data)>-1){
return true
}else {
return false
}
}
// 合并两个集合
function union(set){
let tempSet = new Set()
for(let i = o; i < this.dataStore.length; i++){
tempSet.add(this.dataStore[i])
}
for(let i = 0; i < set.dataStore.length; ++i){
if(!tempSet.contains(set.dataStore[i])){
tempSet.add(set.dataStore[i])
}
}
return tempSet
}
// 返回两个集合的交集
function intersect(set){
let tempSet = new Set()
for(let i = 0; i < this.dataStore.length; i++){
if(set.contains(this.dataStore[i])){
tempSet.add(this.dataStore[i])
}
}
return tempSet
}
// 返回集合的长度
function size(){
return this.dataStore.length
}
// 判断一个集合是否是另一个集合的子集
function subset(set){
if(this.size() > set.size()){
return false
}else {
for(let i of this.dataStore){
if(!set.contains(i)){
return false
}
}
}
return true
}
// 返回两个集合的补集
function difference(set){
let tempSet = new Set()
for(let i = 0; i < this.dataStore.length; i++){
if(!set.contains(this.dataStore[i])){
tempSet.add(this.dataStore[i])
}
}
return tempSet
}