Skip to main content

浏览器基础知识点及常考面试题

事件机制

事件捕获和事件冒泡

事件的触发过程是怎么样的?知道什么是事件代理嘛?

事件触发三阶段

  • 捕获:window 往事件触发处传播,遇到注册的捕获事件会触发
  • 目标:传播到事件触发处时触发注册的事件
  • 冒泡:从事件触发处往 window 传播,遇到注册的冒泡事件会触发
info

● e.target是触发事件的元素(事件是在哪个元素上触发的) ● e.currentTarget是绑定事件的元素

注册事件

addEventListener

该函数的第三个参数可以是布尔值,也可以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 false (冒泡阶段触发),useCapture 决定了注册的事件是捕获事件还是冒泡事件。对于对象参数来说,可以使用以下几个属性

  • capture:布尔值,和 useCapture 作用一样
  • once:布尔值,值为 true 表示该回调只会调用一次,调用后会移除监听
  • passive:布尔值,表示永远不会调用 preventDefault

一般来说,如果我们只希望事件只触发在目标上,这时候可以使用 stopPropagation 来阻止事件的进一步传播。通常我们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件。

事件代理

利用事件冒泡的原理,子元素触发的事件尤其父元素代理执行;即子元素触发事件调用父元素上绑定的事件处理函数。

使用场景:如果一个节点中的子节点是动态生成的,那么子节点需要注册事件的话应该注册在父节点上

我们可以通过e.target可以找到真正触发该事件的元素

事件代理的方式相较于直接给目标注册事件来说,有以下优点:

  1. 节省内存
  2. 不需要给子节点注销事件

跨域

什么是跨域?为什么浏览器要使用同源策略?你有几种方式可以解决跨域问题?了解预检请求嘛?

跨域:由于浏览器同源策略的限制,禁止操作不同源下的资源

同源:协议、域名、端口号相同

同站:二级域名相同即可

禁止的操作:

  1. ajax请求无法发送
  2. dom无法获取
  3. Storage、Cookie、IndexDB无法访问

为是么要有同源策略:安全( 其实主要是用来防止 CSRF 攻击的)

CSRF:拿到用户的cookie,模拟用户登陆,然后进行一些非法操作。前提: 1. 用户登录受信任的网站A并且生成Cookie。2. 在不登出网站A的情况下,访问危险网站B

然后我们来考虑一个问题,请求跨域了,那么请求到底发出去没有?

  • 如果是简单请求,会发送真正的请求,服务器正常处理请求并返回响应信息,只不过浏览器会拦截这个响应
  • 如果是非简单请求,则会先发送一个OPTIONS预检请求(Access-Control-Request-Method、Access-Control-Request-Headers、Origin),这个请求不会携带任何数据,然后服务器判断是否允许访问,然后返回与跨域相关的首部。(Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers)浏览器根据服务器返回的相关首部判断服务器是否允许当前域名访问,如果是的话才会发送真正的请求

跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

::: info

  • 简单请求:

    • 请求方法是:GET、POST、HEAD
    • 请求的首部仅仅包括:Accept(客户端可以接受的媒体类型)、Accept-Language、Content-Type、Content-Lanuage
    • Content-Type的值为:text/palin、application/x-www-form-urlencoded、multipart/form-data
    • 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 非简单请求:不满足简单请求的条件的就是非简单请求 :::

跨域请求如何发送

  1. CORS

最常见和推荐的解决方式,需要服务器的支持

需要服务器返回Access-Control-Allow-Origin为当前的请求的域名/'*'

跨域请求默认是不携带Cookie的,如果想要携带Cookie的话则需要客户端设置 withCredentials = true & 响应头返回Access-Control-Allow-Credential:true

浏览器可以向服务器自动发起跨域请求/预检请求。

CORS这种跨域方式需要区分简单请求和复杂请求

  1. jsonp

需要服务器的支持

只能发起get请求。利用了浏览器对于img的src和script的src链接的资源没有跨域的限制。(script、img、link、iframe)。

  • 创建一个script标签,src属性的值是要访问的服务器,携带一个特殊的参数callback=func(函数名,可以随便起,在js中定义一个名字一致的函数即可;callback这个key也是和服务器约定的)
  • 服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
  • 在js中定义一个func函数,该函数的参数就是请求返回的数据

script标签发挥的内容会被浏览器执行

function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
window[callback] = function(data) {
resolve(data)
document.body.removeChild(script)
}
params = { ...params, callback } // wd=b&callback=show
let arrs = []
for (let key in params) {
arrs.push(`${key}=${params[key]}`)
}
script.src = `${url}?${arrs.join('&')}`
document.body.appendChild(script)
})
}
jsonp({
url: 'http://localhost:3000/say',
params: { wd: 'Iloveyou' },
callback: 'show'
}).then(data => {
console.log(data)
})
  1. document.domain + iframe

该方式只能用于二级域名相同的情况下,比如a.test.com和b.test.com就可以使用这种方式来实现跨域

只需要给页面添加document.domain = 'test.com'就可以实现二级域名相同的与可以跨域

iframe加载另一个页面

在当前页面中通过iframe.contentWindow.xxx来访问另一个页面中的xxx数据

info

但是需要注意的是这种方式即将在chrome中不能使用,因为chrome计划将document.domain变为只读属性。因为改写domain是不安全的,不一定二级域名相同的网站都是属于一个公司

  1. window.postMessage

window.onmessage事件监听数据

  1. window.name

同一个窗口打开的所有页面共享同一个window.name(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

存储

有几种方式可以实现存储功能,分别有什么优缺点?什么是 Service Worker?

一般由服务器设置,大小不超过4kb,每次http请求都会被携带,所以会影响性能。可以设置过期时间,不设置则默认是当前会话窗口

info
  • http请求发送cookies的条件:

1、本地已经缓存有cookies 2、根据请求的URL来匹配cookies的domain、path属性,如果都符合才会发送。

  • 第三方Cookie

我们一般认为cookie的 domain 是当前域名或当前域名的父级的cookie称为第一方cookie,否则为第三方cookie。

  • 同域名下cookie的数量和大小限制

同域名下cookie的总大小不超过4KB(byte)超过这个限制的cookie会被自动忽略,不会被设置。发向服务器的所有 cookie 的大小不能4KB。所有超出该限制的 cookie 都会被截掉并且不会发送至服务器。

  • 几个关键属性:

    • httpOnly:不能通过js访问cookie,可以减少XSS攻击
    • Secure:cookie只能通过https请求携带
    • SameSite:规定浏览器不能在跨域请求中携带 Cookie,减少 CSRF 攻击(当前网页的 URL 与 Cookie 的 domain 一致时,才会带上 Cookie)

SessionStorage

大小为5M,只在当前会话(标签页)有效,关闭tab页会被清理,不参与和服务端通信

LocalStorage

大小为5M,永久的本地存储,除非用户主动删除,否则不会失效。不参与和服务端通信

Storage的值是一个字符串,所以一般存储的时候都会序列化一下

对比

  1. Storage浏览器提供了对应的API,而cookie的设置和读取都只能通过document.cookie
info
  • Storage.getItem() 该方法接受一个键名作为参数,返回键名对应的值。
  • Storage.setItem() 该方法接受一个键名和值作为参数,将会把键值对添加到存储中,如果键名存在,则更新其对应的值。
  • Storage.removeItem() 该方法接受一个键名作为参数,并把该键名从存储中删除。
  • Storage.clear() 调用该方法会清空存储中的所有键名。
  1. cookie存储数据大小有限,不能超过4kb,会影响http请求性能;Storage可以存储5M的数据,而且不会与服务器通信,仅仅是浏览器的本地存储