JS Web API 面试题

DOM

DOM是哪种数据结构

树(DOM树),基于树状结构才有了父节点、子节点。


DOM操作的常用API

  • DOM节点操作
    • 获取1个DOM元素:getElementByld()/querySelector()
    • 获取多个DOM元素(nodeList集合):getElementsByTagName()/getElementsByClassName()/querySelectorAll()
  • DOM结构操作(具体可参考“JS中修改/创建/移动/删除 HTML DOM元素
    ):
    • document.createElement()创建 元素节点
    • document.createTextNode() 创建 文本节点
    • Node.appendChild() 添加/移动 子节点
    • Node.removeChild() 删除 子节点
  • attribute操作
  • property的操作:
    • 取值:用“.”就可以, var id = div1.id; var className = div1.className;
    • 赋值:和基本的js对象属性赋值一样,用“.”即可,div1.className = 'a'; div1.align = 'center'; div1.AAAAA = true; div1.BBBBB = [1, 2, 3];
      • 对属性Property可以赋任何类型的值,而对特性Attribute只能赋值字符串
  • 使用getAttribute()获取 和 直接获取property值 的区别:直接获取property的方式只能获取节点本来具有的属性,而getAttribute()可以获取自定义的属性,例如data-xxx;
    • 补充:html5允许自定义属性,可以通过data-xxx来设置我们需要的自定义属性,进行数据存放。
    • jquery中获取自定义属性的方法: 1是.attr('data-xxx'),2是.data('xxx')
    • js中获取自定义属性的方法:
      • 通过attribute: getAttribute('data-xxx')
      • 通过dataset(html5属性):以下例子假设自定义属性data-xxx
        • 取值:ele.dataset.xxx
        • 赋值:ele.dataset.xxx = "3m666";
        • 新增data-age属性:ele.dataset.age = "100";
        • 删除:设置成null,或者deleteele.dataset.xxx = null; delete ele.dataset.age;

attribute和property的区别

  • attribute:修改html属性改变html结构
    • attribute 是“死”的,是 DOM元素 在文档中作为 html 标签拥有的固有属性
  • property:修改JS对象属性会体现到html结构
    • property 是“活”的,是经过浏览器解析后 DOM元素 在 js 中作为对象拥有的属性
    • “class”在Property中叫做“className”,因为“class”是ECMA的关键字。所以通过.获取样式名时要通过ele.className获取!
  • attributes是属于property的一个子集
  • 有些固有属性通过.getAttribute()获取到的是不同的,比如:获取onclick属性时,通过getAttribute()获取到的是函数执行结果,而通过.获取到的是函数体(例子)。所以一般只有在取自定义值的时候才用getAttribute()
  • 两者都有可能引起DOM重新渲染,但建议尽量使用property(但是使用property无法获取自定义属性)
HTML attribute(特性) DOM property(属性)
值永远是字符串或 null 值可以是任意合法 js 类型
大小写不敏感 大小写敏感
不存在时返回 null 不存在时返回 undefined
对于 href, 返回 html 设置的值 对于 href 返回解析后的完整 url
更新 input的value, 属性property也更新 更新 input的value, 特性attribute不更新例子

(可参考这篇博客


一次性插入多个DOM节点,考虑性能

将频繁操作改为一次性操作:

  1. 通过createDocumentFragment()先创建一个文档片段,这个文档片段是保存在JS中的(不是在DOM树中)
  2. 将循环10次产生的子节点都添加到文档片段中
  3. 将 文档片段 添加到DOM树上
    将频繁操作改为一次性操作

BOM

可参考JS Web API BOM

如何识别浏览器的类型

通过navigator.userAgent识别浏览器的类型。


分析拆解url各个部分

  • location.href:整个网站地址
  • location.protocol:采用的协议(比如https:/http:
  • location.host:域名
  • location.search:路由参数,即?后的内容
  • location.hash:网址的哈希,即#后的内容
  • location.pathname:路径

location例子


事件

  • 事件代理【重点】:需要绑定事件的元素太多时将事件绑定在他们的父元素上
  • 冒泡例子事件代理例子,可以帮助理解下面的事件监听函数设计逻辑

编写一个通用的事件监听函数(事件代理)

  • 【简单版】可监听 普通绑定通用事件监听函数通用的事件监听函数【简单版】
  • 【正式版】可以同时监听 普通绑定 和 代理绑定 的通用事件监听函数通用的事件监听函数【正式版】普通绑定时this就指向触发事件的DOM元素事件代理时就需要事件对象.target来获取触发事件的DOM元素
    • 注意:事件代理的监听就是我们希望绑定在div上的事件可以且仅在监听到a标签点击事件时触发

Element.matches()

  • 如果 元素 匹配指定的 选择器 字符串,则Element.matches()返回true,否则返回false。
  • 语法let result = element.matches(selectorString);
    • result 的值为 true 或 false.
    • selectorString 是个css选择器字符串.
  • MDN文档

event事件对象

  • 可参考“DOM基础”
  • DOM事件的回调函数中的第一个参数event指的是事件对象
  • 可以使用**event.preventDefault()取消事件的默认动作**,比如:如果 type 属性是 “submit”,在事件传播的任意阶段可以调用任意的事件句柄,通过调用该方法,可以阻止提交表单。注意,如果 Event 对象的 cancelable 属性是 fasle,那么就没有默认动作,或者不能阻止默认动作。无论哪种情况,调用该方法都没有作用。
  • 事件对象.target就是事件绑定函数对应的事件触发的DOM元素

target 事件属性

  • 事件对象.target 事件属性可返回事件的目标节点(DOM元素)触发该事件的节点),如生成事件的DOM元素、文档或窗口。
  • 具体可参考菜鸟教程

描述事件冒泡的流程

  • 基于DOM树形结构,事件流图示
    • DOM结构是一个树型结构,当一个DOM元素触发一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为 DOM 事件流(DOM event flow )。
  • 冒泡:事件会顺着触发元素往根节点冒泡传播
  • 应用场景:事件代理(简单例子

无限下拉的图片列表,如何监听每个图片的点击?

  • 事件代理
  • e.target获取触发元素(参考在上面)
  • 用**Element.matches()**来判断是否是触发元素(参考在上面)

AJAX

手写简易ajax

手写简易ajax
运行结果

模拟404情况,换成不存在的地址:
模拟404情况
运行结果

浏览器的同源策略

  • 可参考JS Web API AJAX
  • 同源策略:ajax请求时,浏览器要求当前网页和server必须同源(为了安全)
    • 注意:同源是浏览器规定的,在服务端是可以发起跨域攻击的,比如爬虫,因为server端并无同源策略
  • 同源协议、域名、端口,三者必须一致
    • 比如:前端http://a.com:8080/;server:https://b.com/api/xxx(默认443端口)那么这前后端是三者都不一致
  • 同源策略限制了跨域时的以下行为
    • Cookie、LocalStorage 和 IndexDB 跨域无法读取,只有同源才能获取他们
      • sessionstorage同源也不一定共享,毕竟只在同一个浏览器窗口才共享(参考本文最下方
    • DOM 和 JS 对象跨域无法获取
    • Ajax请求跨域时无效,可发送,但浏览器会拒绝接受响应

跨域的使用场景

  • 跨域问题浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同源的路径,这能有效的阻止跨站攻击。
  • 前提:
    • 所有的跨域,都必须经过server端允许和配合(包括前端jsonp)
    • 未经server端允许就实现跨域,说明浏览器有漏洞,危险信号
    • 具体配合可参考[《JS Web API AJAX》]
  • 加载img CSS js可无视同源策略:
    • 比如我们经常引用的js/CSS的库<link/><script>直接使用cdn地址就是跨域的。
    • <script>可实现JSONP
    • 而图片比较特殊,如果该图片做了防盗链,则无法显示(比如百度)
    • <img/>可用于使用第三方统计服务来统计打点(比如统计访问次数),也就是把需要的参数放入img,在地址处使用第三方统计服务,这样就可以避免跨域问题
      1
      2
      3
      <img src=跨域的图片地址/>
      <link href=跨域的css地址/>
      <script src=跨域的js地址> </script>
  • 开发环境中,前后端联调使用nginx反向代理proxy反向代理 根据url派发不同的端口,把跨域变为不跨域,使Ajax请求变成同源的从而传递数据
    • 例子1:假设前端页面是3000端口,后端页面是8000端口。那么用户打开页面时打开的就是3000端口的页面,前端页面中使用ajax请求获取数据时就会去获取3000端口下的对应路径的数据。而后端页面是8000端口,所以数据其实保存在8000端口下的对应路径中。这就无法获取数据。此时使用nginx进行反向代理,遇到/api/开头的url时就分配到8000端口,遇到/开头的url时就分配到3000端口,这样就没问题了
    • 例子2:
      • 开发环境中,假设前端服务是http://localhost:8089/,后端接口是存在http://test01.7debao.com/服务上的
      • 那么前端打开页面时打开的就是http://localhost:8089/,前端页面中使用ajax请求获取数据时就会去获取http://localhost:8089/下的对应路径的数据
      • 而后端接口是存在http://test01.7debao.com/服务上的,所以数据其实保存在http://test01.7debao.com/下的对应路径中,这就导致无法获取数据
      • 此时使用proxy进行反向代理,结合axios配置给接口加d baseUrl/api,遇到以 /api 开头的URL请求会被代理分配到后端服务,其他以 / 开头的URL请求会被前端服务处理显示页面或返回404错误
      • 注意: 生产和测试环境下,我开发的项目前后端代码应该是部署在同一域名下,接口请求不存在跨域问题,所以不需要设置反向代理,具体是运维在云服务上配的,我只能看到没有处理接口,连axios的baseUrl都没设置,看起来是同源直接请求

跨域的实现方式


实际项目中 ajax 的常用插件


存储

描述cookie localStorage sessionStorage区别

  • 共同点:都保存在浏览器端
  • 区别:
  1. 生命周期
    • Cookie:设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。未设置则默认为关闭浏览器后失效。(不是浏览器标签页,而是整个浏览器)
    • Localstorage:除非被手动清除,否则永久保存,窗口或浏览器关闭也一直保存,因此用作持久数据
    • Sessionstorage:仅在当前网页会话下有效,关闭页面或浏览器后就会被清除(刷新页面不会被清除),自然也就不可能持久保持。
  2. 存放数据
    • Cookie:4k左右(cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下)
    • Localstorage和sessionstorage:可以保存5M的信息
  3. 是否跟随http请求发送出去
    • Cookie:每次都会携带在http头中,如果使用cookie保存过多数据会带来性能问题
    • 其他两个:不会自动把数据发给服务器,仅在客户端即浏览器中保存,不参与和服务器的通信
  4. API易用性
  5. 应用场景
    • 从安全性来说,因为每次http请求都回携带cookie信息,这样子浪费了带宽,所以cookie应该尽可能的少用,此外cookie还需要指定作用域,不可以跨域调用,限制很多,但是对于用户识别用户登陆来说,cookie还是比storage好用
    • 其他情况下可以用storage,localstorage可以用来在页面传递参数
    • sessionstorage可以用来保存一些临时的数据,防止用户刷新页面后丢失了一些参数。
  6. 作用域:
    • cookie和localStorage:在所有同源窗口中都是共享的
    • sessionStorage:在同一个浏览器窗口是共享的(不同浏览器、同一个页面也是不共享的)
    • 关于同源可参考阮一峰,简单来说就是A网页设置的 Cookie,B网页不能打开
,