1. 浏览器运行态下的JS
JS = BOM + DOM + ECMAScript
我们来看一下他们的概念
- DOM(Document Object Model):文档对象模型,描述了处理网页内容的方法和接口,根对象是document(window.document)
- BOM(Browser Object Model):浏览器对象模型,描述了与浏览器进行交互的方法和接口,由location、navigator、history、screen、window五个对象组成,根对象是window
2. BOM
1. location:主要提供当前窗口中加载文档的信息以及导航功能
1. 保存URL信息
比如以这个url为例:www.juejin.cn/frontend?so…
| 属性 | 值(字符串) | 说明 |
|---|---|---|
| location.href | 完整地址 | |
| location.protocal | https: | 页面使用的协议 |
| location.hostname | www.juejin.cn | 服务器名 |
| location.pathname | frontend | URL路径与文件名 |
| location.search | ?sort=newest | URL查询字符串 |
| location.hash | #content | 哈希地址 |
| location.port | 端口号 |
这里的location.search会获取到?之后的参数,不过是一个长长的字符串,很有可能需要我们将其处理成我们需要的格式,有一下两种方法
- 利用URLSearchParams实例
let qs = location.search // '?sort=newest&num=10'
let queryParams = new URLSearchParams(qs)
这个实例上暴露了:get()/set()/delete/has()/toString()等方法,也可以进行遍历,得到所有参数的key-value的数组
for(let item of queryParams){
console.log(item)
}
//打印出两个数组
//['sort' , 'newest']
//['num' , '5']
- 当然我们也可以自己手写一个函数
let search = '?sort=newest&num=10'
let qs = search.substring(1) //去掉问号
let arr = qs.split('&').map(i => i.split('='))
console.log(arr); // [ [ 'sort', 'newest' ], [ 'num', '10' ] ]
2. 操作地址
assign(): 跳转到新的URL,并增加一条历史记录replace(): 跳转到URL,不增加历史记录reload(): 重新加载当前页面;可以接收一个参数
location.reload() //重新加载当前页面,但可能从缓存加载(页面自上次请求以来没修改过时)
location.reload(true) //重新加载当前页面,从服务器加载
2. navigator:浏览器系统信息大集合
面试方向:
- userAgent 读取信息=>判断浏览器兼容性、上报信息等操作
- 剪切板、键盘等操作
3. history:存储当前页面的状态
面试方向:
- 路由方向=>history和hash的模式利弊:
1. Hash模式
- 定义:
hash模式是一种吧前端路由的路径用#拼接在真实url后面的模式。当url发生变化时,不会重新发起请求,而是触发onhashchange事件。 - 特点:
- hash的改变记录在
window.history中,不利于SEO的优化。hash只能修改#后面的部分,所以只能跳转到与当前url同文档的url。 ash通过window.onhashchange的方式,来监听hash的改变,借此实现无刷新跳转的功能。hash永远不会提交到server端(可以理解为只在前端自生自灭)。
2. History模式
- 先来了解几个api
history.pushState(data, title [, url])pushState主要用于往历史记录堆栈顶部添加一条记录。各参数解析如下:
①data会在onpopstate事件触发时作为参数传递过去;
②title为页面标题,当前所有浏览器都会忽略此参数;
③url为页面地址,可选,缺少时表示为当前页地址
history.replaceState(data, title [, url])
上述为添加,此处为更改
history.state:存储data数据
- history存在的问题
使用
history模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果nginx没有匹配得到当前的url,就会出现404的页面。
4. screen - 荧幕相关
面试方向 - 判断区域大小
1. window视窗判断 - 整个宽高
- 全局入口处:
window.innerHeight,window,innerWidth - 文本处获取:
document.body(documentElement).clientHeight
2. 网页视图的size - 内容宽高
document.body(documentElement).offsettHeight
offsetHeight = clientHeight + 滚动条 + 边框
3. 整个内容的宽高(包括不在页面可滚动部分)
scrollWidth/scrollHeight
4. 判断距离
- offsetTop : 距离常规上面的距离
- scrollTop :距离上面滚动的距离
3. Event 事件类型
1.冒泡和捕获
<div id="app">
<p id="dom"></p>
</div>
- 冒泡 - ms:p => div => body => document
- 捕获 - ns:document => body => div => p
对于冒泡和捕获,在
addEventListener中有一个useCapture参数来选择。
el.addEventListener(event, function, useCapture) //默认为false - 冒泡
// 追问:1. 如何阻止事件的传播?
// 1. 阻止事件传递(可以是冒泡,也可以是捕获)
event.stopPropagation() //阻止传递行为 => 无法阻止默认事件
// 2. 阻止默认事件 - a标签这种
event.preventDefault()
// 3. 阻止事件传递,并且阻止后续再监听相同类型的事件
event.stopImmediatePropagation
2. 手写兼容IE的addEventListener
IE - attachEvent vs addEventListener
区别:
- 传参:
attachEvent对于事件名都要加上on - 执行顺序:
attachEvent- 后绑定先执行;addEventListener- 先绑定先执行; - 解绑:
detachEventVSremoveEventListener() - 阻断:
event.cancelBubble = trueVSevent.stopPropagation() - 默认事件拦截:
event.returnValue = falseVSevent.preventDefault()手写:
class bindEvent {
constructor(element){
this.element = element
}
// 执行
addEventListener(type,handler){
if(this.element.addEventListener){
this.element.addEventListener(type,handler,false)
} else if(this.element.attachEvent) {
this.element.attachEvent('on' + type,()=>{
handler.call(this.element)
})
} else {
this.element['on' + type] = handler
}
}
//解绑
removeEventListener(type,handler){
if(this.element.removeEventListener){
this.element.removeEventListener(type,handler,false)
} else if(this.element.detachEvent) {
this.element.detachEvent('on' + type,()=>{
handler.call(this.element)
})
} else {
this.element['on' + type] = null
}
}
// 阻断
static stopPropagation(e){
if(e.stopPropagation){
e.stopPropagation()
} else {
e.cancelBubble = true
}
}
// 默认事件拦截
static preventDefault(e){
if(e.preventDefault){
e.preventDefault()
} else {
e.returnValue = false
}
}
}
3. 性能优化 - 事件代理
<ul class="list">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
//当ul中有多个li,我们要给li添加点击事件,要使用循环给每一个li添加点击事件,这样性能非常低。
var list = document.querySelector('list');
var li = list.getElementsByTagName('li');
for(var n = 0; n < li.length; n++) {
li[n].addEventListener('click', function() {
// 业务逻辑
})
}
//所以我们可以使用事件代理,通过li冒泡到list触发点击事件
function onClick(e) {
var e = e || window.event;
if(e.target.nodeName.toLowCase() === 'li') {
// 业务逻辑
var liList = this.querySelectorAll('li');
// ……
}
}
list.addEventListener('click', onClick, false)
4. 网络层
1. ajax
// 1.实例化
const xhr = new XMLHttpRequest();
// 2. 初始化建立
xhr.open(method,url,async) // get/post请求;地址;是否为异步请求
// 3. 方法的发送
xhr.send(data) //get - 可以不传或传null;post - encodeURIComponent编码拼接
// 4. 接收
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4) {
// 判断http状态码
if(xhr.status >= 200 &&
xhr.status < 300 ||
xhr.status == 304) {
// xhr.responseText
} else {
// xhr.statusText
}
}
};
// 超时时间
xhr.timeout = 30000
xhr.ontimeout = () => {
// 超时后
}
// 报错
xhr.onerror = function (e){
// xhr.statusText
}
2. XMLHttpRequest的实例属性
1. readyState - 状态
XMLHttpRequest.readyState返回一个整数,表示实例对象的当前状态。该属性只读。它可能返回以下值。
-
0,表示 XMLHttpRequest 实例已经生成,但是实例的
open()方法还没有被调用。 -
1,表示
open()方法已经调用,但是实例的send()方法还没有调用,仍然可以使用实例的setRequestHeader()方法,设定 HTTP 请求的头信息。 -
2,表示实例的
send()方法已经调用,并且服务器返回的头信息和状态码已经收到。 -
3,表示正在接收服务器传来的数据体(body 部分)。这时,如果实例的
responseType属性等于text或者空字符串,responseText属性就会包含已经收到的部分信息。 -
4,表示服务器返回的数据已经完全接收,或者本次接收已经失败。 当
readyState发生变化,就会触发readyStateChange事件
2. onreadyStateChange - 监听函数
XMLHttpRequest.onreadystatechange属性指向一个监听函数。实例的readyState属性变化,就会执行这个属性。
3. response - 返回所有数据
XMLHttpRequest.response属性表示服务器返回的数据体(即 HTTP 回应的 body 部分)。它可能是任何数据类型,比如字符串、对象、二进制对象等等,具体的类型由XMLHttpRequest.responseType属性决定。XMLHttpRequest.response属性是只读的。
4. responseType - 返回数据类型
XMLHttpRequest.responseType属性是一个字符串,表示服务器返回数据的类型。这个属性是可写的,可以在调用open()方法之后、调用send()方法之前,设置这个属性的值,告诉浏览器如何解读返回的数据。如果responseType设为空字符串,就等同于默认值text,它还可以等于以下值。
-
""(空字符串):等同于
text,表示服务器返回文本数据。 -
"arraybuffer":ArrayBuffer 对象,表示服务器返回二进制数组。
-
"blob":Blob 对象,表示服务器返回二进制对象。
-
"document":Document 对象,表示服务器返回一个文档对象。
-
"json":JSON 对象。
5. responseText,responseXML,responseURL - 接收的不同数据类型
XMLHttpRequest.responseText属性返回从服务器接收到的字符串,该属性为只读。只有 HTTP 请求完成接收以后,该属性才会包含完整的数据。
XMLHttpRequest.responseXML属性返回从服务器接收到的 HTML 或 XML 文档对象,该属性为只读。如果本次请求没有成功,或者收到的数据不能被解析为 XML 或 HTML,该属性等于null。这要求在发送请求前,XMLHttpRequest.responseType属性要设为document。
XMLHttpRequest.responseURL属性是字符串,表示发送数据的服务器的网址。
6. status,statusText - http状态
XMLHttpRequest.status属性返回一个整数,表示服务器回应的 HTTP 状态码。状态码的相关内容会在下面单独开列出。
XMLHttpRequest.statusText属性返回一个字符串,表示服务器发送的状态提示。
7. timeout, ontimeout
XMLHttpRequest.timeout属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性等于0,就表示没有时间限制。
XMLHttpRequest.timeout属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性等于0,就表示没有时间限制。
3. XMLHttpRequest的监听属性
XMLHttpRequest 对象可以对以下事件指定监听函数。
- onloadstart:HTTP 请求发出的监听函数
- onprogress:正在发送和加载数据的监听函数
- onabort:请求中止,比如用户调用了
abort()方法的监听函数 - onerror:请求失败的监听函数
- onload:请求成功完成的监听函数
- ontimeout:超时的监听函数
- onloadend:请求完成(成功或失败)的监听函数
4. XMLHttpRequest的实例方法
1. open()
2. send()
3. setRequestHeader() - 设置请求头
XMLHttpRequest.setRequestHeader()方法用于设置浏览器发送的 HTTP 请求的头信息。该方法必须在open()之后、send()之前调用。如果该方法多次调用,设定同一个字段,则每一次调用的值会被合并成一个单一的值发送。
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
4. getResponseHeader(), getAllResponseHeaders() - 得到请求头信息
XMLHttpRequest.getResponseHeader("balabala")方法返回 HTTP 头信息指定字段的值,如果还没有收到服务器回应或者指定字段不存在,返回null。该方法的参数不区分大小写。如果有多个字段同名,它们的值会被连接为一个字符串,每个字段之间使用“逗号+空格”分隔。
5. abort() - 终止请求
XMLHttpRequest.abort()方法用来终止已经发出的 HTTP 请求。调用这个方法以后,readyState属性变为4,status属性变为0。
5. ajax封装手写
ajax({
url: 'reqUrl',
method: 'get',
async: true,
timeout: 30000,
data: {info:'lkh'}
}).then(
res => {},
err => {}
).catch(err => {})
function ajax (options){
let {url,method,async,timeout,data} = options
const xhr = new XMLHttpRequest()
// 判断是否有timeout
if(timeout){
xhr.timeout = timeout
}
return new Promise((resolve,reject) => {
xhr.onreadystatechange = () => {
if(xhr.readyStatus === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
resolve(xhr.responseText)
} else {
reject(xhr.statusText)
}
}
}
// 定义失败的回调
xhr.onerror = err => {
reject(err)
}
xhr.ontimeout = () =>{
reject('timeout')
}
//传参
let _params = []
let encodeData = ''
for(let key in data){
_params.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
}
encodeData = _params.join('&')
//method为get拼接url
if(method === 'get'){
const index = url.indexOf('?')
if(index === -1){
url += '?'
} else if(index !== url.length - 1){
url += '&'
}
url += encodeData
}
//open
xhr.open(method,url,async)
//send
if(method === 'get'){
xhr.send(null)
} else {
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
xhr.send(encodeData)
}
})
}
6. 常见的状态码
- 100
Continue继续。客户端应继续其请求
- 200
OK请求成功。一般用于GET与POST请求 - 201
Created已创建。成功请求并创建了新的资源 - 202
Accepted已接受。已经接受请求,但未处理完成 - 204
No Content无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 - 205
Reset Content重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 - 206
Partial Content部分内容。服务器成功处理了部分GET请求
- 301
Moved Permanently永久重定向。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 - 302
Found临时重定向。与301类似。但资源只是临时被移动。客户端应继续使用原有URI - 303
See Other查看其它地址。与301类似。使用GET和POST请求查看 - 304
Not Modified未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 - 305
Use Proxy使用代理。所请求的资源必须通过代理访问 - 307
Temporary Redirect临时重定向。与302类似。使用GET请求重定向
- 400
Bad Request客户端请求的语法错误,服务器无法理解 - 401
Unauthorized请求要求用户的身份认证 - 402
Payment Required保留,将来使用 - 403
Forbidden服务器理解请求客户端的请求,但是拒绝执行此请求 - 404
Not Found服务器无法根据客户端的请求找到资源(网页)。 - 405
Method Not Allowed客户端请求中的方法被禁止 - 406
Not Acceptable服务器无法根据客户端请求的内容特性完成请求 - 407
Proxy Authentication Required请求要求代理的身份认证,与 401 类似,但请求者应当使用代理进行授权 - 408
Request Time-out服务器等待客户端发送的请求时间过长,超时 - 409
Conflict服务器完成客户端的 PUT 请求是可能返回此代码,服务器处理请求时发生了冲突 - 410
Gone客户端请求的资源已经不存在。410 不同于 404,如果资源以前有现在被永久删除了可使用 410 代码,网站设计人员可通过 301 代码指定资源的新位置 - 411
Length Required服务器无法处理客户端发送的不带Content-Length的请求信息 - 412
Precondition Failed客户端请求信息的先决条件错误 - 413
Request Entity Too Large由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 - 414
Request-URI Too Large请求的URI过长(URI通常为网址),服务器无法处理 - 415
Unsupported Media Type服务器无法处理请求附带的媒体格式 - 416
Requested range not satisfiable客户端请求的范围无效 - 417
Expectation Failed服务器无法满足Expect的请求头信息
- 500
Internal Server Error服务器内部错误,无法完成请求 - 501
Not Implemented服务器不支持请求的功能,无法完成请求 - 502
Bad Gateway作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 - 503
Service Unavailable由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 - 504
Gateway Time-out充当网关或代理的服务器,未及时从远端服务器获取请求 - 505
HTTP Version not supported服务器不支持请求的HTTP协议的版本,无法完成处理
7. content-type内容类型
1. 响应头
在响应中常见的Content-Type有:
application/jsonajax请求数据返回jsonapplication/javascriptjavascript文件text/csscss文件(注意与js不同的是这里是text,application通常表示可执行或可解析的二进制数据)text/htmlhtml文件text/plain纯文本
2. 请求头
- 使用form表单发送给请求,通常使用
application/x-www-form-urlencoded - 对于二进制数据、文件、非ASCII字符,应使用
multipart/form-data - json数据,使用
application/json