备战前端面试—JS-Web-API篇

Ajax

XHR 的概念

考点1:XHR 对象

  1. XHR 是什么?

    XHR(XMLHttpRequest)即 XMLHttpRequest 对象。

    XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。它可以操作任何数据,而不仅仅是 XML 格式。XMLHttpRequest 可以同步或异步地返回 Web 服务器的响应,并且能够以文本或者一个 DOM 文档的形式返回内容。

  2. XHR 提供了哪些常用的方法?

    XHR 分为同步和异步模式。

    异步模式:

    xhr.open(method, URL, [async, user, password])

    此方法指定了请求的主要参数:

    • method:请求的方法,限定为 GETPOSTHEAD 之一。
    • URL:要请求的 url。通常是字符串,也可以是 url 对象(如果有搜索参数,避免转码问题)。
    • async:如果显示地设定为 false,将采用同步模式。
    • user,password:HTTP 基本身份验证(如果需要的话)的登录名和密码。

    发送请求:

    xhr.send([body])

    body:可选参数,请求体。

    之后需要监听 XHR 事件,以作出响应:

    这三个事件是最常用的:

    • load:当请求完成(200500),并且响应已完全下载。
    • error:当无法发送请求,如网络中断、URL 无效。
    • progress:在下载期间定期触发,报告当前进度。

    一旦有了结果,可以从 XHR 的以下属性中获得结果:

    • status:HTTP 状态码(一个数字):200404403 等,如果出现非 HTTP 错误,则为 0
    • statusText:HTTP 状态消息(一个字符串):状态码为 200 对应于 OK404 对应于 Not Found403 对应于 Forbidden
    • response:服务器的响应体。

    可以设置超时时间,如果给定时间内请求没有成功执行,请求就会取消,同时触发 timeout 事件:

    xhr.timeout = 10000; // timeout 单位是 ms,此处即 10 秒

    我们可以使用 xhr.responseType 属性来设置响应格式:

    • ""(默认)—— 响应格式为字符串,
    • "text" —— 响应格式为字符串,
    • "arraybuffer" —— 响应格式为 ArrayBuffer
    • "blob" —— 响应格式为 Blob
    • "document" —— 响应格式为 XML document(可以使用 XPath 和其他 XML 方法),
    • "json" —— 响应格式为 JSON(自动解析)。

    我们可以随时终止请求。调用 xhr.abort() 即可。


    同步请求:

    如果在 open 方法中将第三个参数 async 设置为 false,那么请求就会以同步的方式进行。

    JS 脚本将在 send() 处暂停,并在收到响应后恢复执行。这会阻塞页面加载。基于这些原因,同步请求使用的非常少,几乎从不使用。

AJAX 的相关应用

考点1: jQuery Ajax

  1. 什么是 Ajax?如何使用?

    AJAX(Async Javascript and XML)

    即异步的JavaScriptXML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页。

    jquery 的 ajax:

    $.ajax({
       type: 'POST',
       url: url,
       data: data,
       dataType: dataType,
       success: function () {},
       error: function () {}
    });
  2. Ajax 的原理是什么?如何实现?

    ajax 原理简单来说是通过 XHR 对象向服务器发送异步请求,同时在接收到响应后,使用 JS 操作 DOM 更新页面。

    实现过程:

    1. 创建核心对象 XHR

      const xhr = new XMLHttpRequest()
    2. 通过 XHR 的 open 方法与服务器建立连接

      xhr.open(method, url, [async][, user][, password])
    3. 构建请求所需的内容,通过 send 方法将请求发送给服务器

      xhr.send([body])
    4. 通过 XHR 对象的 onreadystatechange 事件监听服务端通信状态

      关于XMLHttpRequest.readyState属性有五个状态:

      0:UNSET,未打开,open 方法还未调用

      1:OPEND,未发送,send 方法还未调用

      2:HEADERS_RECEIVED,已获取响应头,服务端已返回响应头和响应状态

      3:LOADING,下载响应体,响应体下载中,responseText 已获取部分内容

      4:DONE,请求结束,整个请求过程完毕

    5. 接收并处理服务端响应的数据结果

    6. 将处理结果更新到 HTML页面中

    封装以后的 ajax 代码:

    function ajax(options) {
      const xhr = new XMLHttpRequest();
      //初始化配置
      options = options || {};
      options.type = (options.type || "GET").toUpperCase();
      options.dataType = options.dataType || "json";
      const params = options.data;
      //发送请求
      if (options.type === "GET") {
        xhr.open("GET", options.url + "?" + params, true);
        xhr.send(null);
      } else if (options.type === "POST") {
        xhr.open("POST", options.url, true);
        xhr.send(params);
      }
      //接收请求
      xhr.onreadystatechange = function () {
        //请求完成
        if (xhr.readyState === 4) {
          let status = xhr.status;
          if (status >= 200 && status < 300) {
            options.success && options.success(xhr.responseText, xhr.responseXML);
          } else {
            options.error && options.error(status);
          }
        }
      };
    }
    ajax({
      type: "POST",
      dataType: "json",
      data: {},
      url: "https://xxxxx",
      success: function () {},
      error: function () {},
    });

考点2:Fetch API

  1. 什么是 fetch?如何使用?

    fetch 是脱离了 XHR 的全新 API,是 ajax 的替代方案。解决了 ajax 在使用时必须引入 jQuery 的缺陷,并且是基于 Promise 的实现,符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里,更加人性化,同时写法简单方便。

    优势:

    • 更加底层,提供的API丰富(request, response)
    • 脱离了 XHR,是ES规范里新的实现方式
    • 支持 async/await 以书写同步代码的方式完成异步操作

    缺点:

    • 是一个低层次的 API,使用时仍然需要封装。
    • 默认不带 cookie,需要进行设置。
    • 只有网络错误能得到处理,服务器返回错误码时不会 reject。
    // Example POST method implementation:
    
    postData('http://example.com/answer', {answer: 42})
      .then(data => console.log(data)) // JSON from `response.json()` call
      .catch(error => console.error(error))
    
    function postData(url, data) {
      // Default options are marked with *
      return fetch(url, {
        body: JSON.stringify(data), // must match 'Content-Type' header
        cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
        credentials: 'same-origin', // include, same-origin, *omit
        headers: {
          'user-agent': 'Mozilla/4.0 MDN Example',
          'content-type': 'application/json'
        },
        method: 'POST', // *GET, POST, PUT, DELETE, etc.
        mode: 'cors', // no-cors, cors, *same-origin
        redirect: 'follow', // manual, *follow, error
        referrer: 'no-referrer', // *client, no-referrer
      })
      .then(response => response.json()) // parses response to JSON
    }

考点3:Axios

  1. 什么是 axios?如何使用?

    axios 是对原生 XHR 的封装,ajax 的另一个替代方案。同时也是 Promise 的实现版本,符合最新 ES 规范。可用于 NodeJS 和浏览器。

    有以下几条特性:

    • 在浏览器中创建 XMLHttpRequests
    • 在 node.js 中直接创建 http 请求
    • 支持 Promise API
    • 支持拦截请求和响应
    • 客户端支持防止CSRF(让你的每个请求都带一个从 cookie 中拿到的key)
    • 提供了一些并发请求的接口

    使用上也简化了,更加灵活:

    const config = {
      url: 'http://api.com',
      method: 'POST',
      header: {
        'Content-Type': 'application/json'
      },
      data: {
        name: 'John',
        age: 22
      }
    }
    axios(config);

DOM

DOM 操作

考点1:DOM 方法

  1. 常用的原生 DOM 操作方法有哪些?

    创建节点:

    • createElement:创建新元素

      const divEl = document.createElement("div");
    • createTextNode:创建文本节点

      const textEl = document.createTextNode("content");
    • createDocumentFragment:创建文档碎片,是更轻量级的文档

      const fragment = document.createDocumentFragment();
    • createAttribute:创建属性节点,可以是自定义属性

      const dataAttribute = document.createAttribute('custom');

    查询节点:

    • querySelector:传入有效的 css 选择器,即可选中首个 DOM 元素

      document.querySelector('.element')
      document.querySelector('#element')
      document.querySelector('div')
      document.querySelector('[name="username"]')
      document.querySelector('div + p > span')
    • querySelectorAll:返回一个包含节点子树内所有匹配的元素节点列表,没有则返回空列表。

      const container = document.querySelector("#test");
      const matches = container.querySelectorAll("div.highlighted > p");
    • getElementsBy系列

      document.getElementById('id属性值');//返回拥有指定id的对象的引用
      document.getElementsByClassName('class属性值');//返回拥有指定class的对象集合
      document.getElementsByTagName('标签名');//返回拥有指定标签名的对象集合
      document.getElementsByName('name属性值'); //返回拥有指定名称的对象结合

    更新节点:

    • innerHTML:可修改节点内部的子树

      // 获取<p id="p">...</p >
      var p = document.getElementById('p');
      // 设置文本为abc:
      p.innerHTML = 'ABC'; // <p id="p">ABC</p >
      // 设置HTML:
      p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
      // <p>...</p >的内部结构已修改
    • innerText、textContent:自动对文本进行 HTML 编码

      // 获取<p id="p-id">...</p >
      var p = document.getElementById('p-id');
      // 设置文本:
      p.innerText = '<script>alert("Hi")</script>';
      // HTML被自动编码,无法设置<script>节点:
      // <p id="p-id">&lt;script&gt;alert("Hi")&lt;/script&gt;</p >

      两者的区别在于读取属性时,innerText不返回隐藏元素的文本,而textContent返回所有文本

    • styleDOM节点的style属性对应所有的CSS,可以直接获取或设置。遇到-需要转化为驼峰命名

      // 获取<p id="p-id">...</p >
      const p = document.getElementById('p-id');
      // 设置CSS:
      p.style.color = '#ff0000';
      p.style.fontSize = '20px'; // 驼峰命名
      p.style.paddingTop = '2em';

    添加节点

    • innerHTML:如果是空节点,会添加新节点。否则会直接替换掉原来的所有子节点

      const div = document.createElement('div');
      div.innerHTML = '<span>child</span>'
    • appendChild:把一个子节点添加到父节点的末尾,如果该节点已存在,会先删除再插入

      const list = document.getElementById('list'),
      const haskell = document.createElement('p');
      haskell.id = 'haskell';
      haskell.innerText = 'Haskell';
      list.appendChild(haskell);
    • insertBefore:把子节点插入到父节点中指定的节点之前

      parentElement.insertBefore(newElement, referenceElement)
    • setAttribute:在指定元素中添加一个属性节点,如果元素中已有该属性改变属性值

      const div = document.getElementById('id')
      div.setAttribute('class', 'white');//第一个参数属性名,第二个参数属性值。

    删除节点:

    • removeChild:首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把它删掉

      // 拿到待删除节点:
      const self = document.getElementById('to-be-removed');
      // 拿到父节点:
      const parent = self.parentElement;
      // 删除:
      const removed = parent.removeChild(self);
      removed === self; // true

      删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。

DOM 渲染

考点1:DOM 渲染方式

  1. 什么是 SPA?与传统 web 开发有什么区别?

    SPA(single page application)即单页面应用。是一种客户端渲染方式。服务端返回宿主 html 模板,再由 JS 操作 DOM 渲染页面,请求数据。

    传统 web 开发,网页内容在服务端渲染完成,⼀次性传输到浏览器。

    SPA 在用户的角度提供了更优秀的交互体验,从开发者的角度上也减少了代码编写的工作量,提高了工作效率。目前主流的网站开发方式均为 SPA

  2. 什么是 SSR?SSR 解决了什么问题?

    SSR(server-side rendering)即服务端渲染,指由服务端完成 html 结构的拼接,发送到浏览器,再将其激活(为其绑定状态与事件)成为可交互页面的过程。

    由后端渲染首屏 dom 结构后返回,前端拿到首屏结构及 SPA 结构,应用激活后仍按 SPA 方式运行。

    SSR SPA 的基础上进行改良,主要解决了以下问题:

    • seo。搜索引擎优先爬取页面 html 结构,使用 SSR 时,服务端已经生成了业务相关的 html,有利于 seo
    • 首屏直接渲染。用户无需等待所有 JS 加载,由服务端返回首屏页面。

    同时也存在缺点:

    • 增加项目复杂度
    • 库的支持不友好
    • 代码兼容问题
    • 服务端负载变大

考点2:首屏和白屏

  1. 首屏和白屏是什么?如何计算?

    白屏时间:

    从输入 URL 到浏览器开始渲染<body>标签或者解析完<head>标签(对应DOMContentLoaded结束)的这段时间就是白屏时间。

    计算方式:DOMContentLoadedEventEnd - fetchStart

    首屏时间:

    从输入 URL 到浏览器中当前视口的内容渲染完毕,呈现出具体画面的这段时间就是首屏时间。

    计算方式:参考阿里ARMS,使用ARMS的计算方法,将可见dom元素数量增长最快的时间点作为首屏时间。

DOM 事件

考点1:事件与事件流

  1. 什么是事件?什么是事件流?

    JS 和 html 之间的交互是通过事件实现的。事件就是用户或浏览器执行的某种操作,比如鼠标点击、移入移出。

    当事件发生时,浏览器会创建一个事件对象 event,并将详细信息放入其中,作为参数传递给事件处理程序。

    <input type="button" value="Click me" id="elem">
    <script>
      elem.onclick = function(event) {
        // 显示事件类型、元素和点击的坐标
        alert(event.type + " at " + event.currentTarget);
        alert("Coordinates: " + event.clientX + ":" + event.clientY);
      };
    </script>

    DOM 结构是一个以 document 为根节点的多叉树。当一个 html 元素产生事件时,该事件会在该元素节点与根节点之间传播,在其经过的路径上所有节点都会接收到该事件,这个传播过程就是 DOM 事件流。事件流描述的是从页面中接收事件的顺序。

考点2:事件模型

  1. 事件模型有哪几种?

    事件模型可以分为三种:

    • 原始事件模型(DOM0级)
    • 标准事件模型(DOM2级)
    • IE事件模型(基本不用)

    原始事件模型:

    事件绑定监听函数比较简单,有两种方式:

    • HTML代码中直接绑定
    <input type="button" onclick="fun()">
    • 通过JS代码绑定
    var btn = document.getElementById('.btn');
    btn.onclick = fun;

    特性:

    • 绑定速度快

    DOM0级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行。

    • 只支持冒泡,不支持捕获
    • 同一个类型的事件只能绑定一次

    标准事件模型:

    一个事件分三个阶段:

    • 事件捕获阶段:事件从document一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。(很少被使用)
    • 事件处理阶段:事件到达目标元素,触发目标元素的监听函数。
    • 事件冒泡阶段:事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

    事件捕获:

    使用 on<event> 属性或使用 HTML 特性(attribute)或使用两个参数的 addEventListener(event, handler) 添加的处理程序,对捕获一无所知,它们仅在第二阶段和第三阶段运行。

    为了在捕获阶段捕获事件,我们需要将处理程序的 capture 选项设置为 true

    elem.addEventListener(..., {capture: true})
    // 或者,用 {capture: true} 的别名 "true"
    elem.addEventListener(..., true)

    capture 选项有两个可能的值:

    • 如果为 false(默认值),则在冒泡阶段设置处理程序。
    • 如果为 true,则在捕获阶段设置处理程序。

    事件处理:

    引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过 event.target 访问。

    事件冒泡:

    当一个事件发生在一个元素上,将会从目标元素冒泡到document。它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。父元素上的处理程序始终可以获取事件实际发生位置的详细信息。

    通常,它会一直上升到 <html>,然后再到 document 对象,有些事件甚至会到达 window,它们会调用路径上所有的处理程序。

    但是任意处理程序都可以决定事件已经被完全处理,并停止冒泡。

    用于停止冒泡的方法是 event.stopPropagation()

    如果一个元素在一个事件上有多个处理程序,即使其中一个停止冒泡,其他处理程序仍会执行。

    有一个 event.stopImmediatePropagation() 方法,可以用于停止冒泡,并阻止当前元素上的处理程序运行。使用该方法之后,其他处理程序就不会被执行。


    IE事件模型:

    共有两个过程:

    • 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
    • 事件冒泡阶段:事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
  2. 解释下什么是事件委托?应用场景?

    事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown……)的处理委托给另一个元素。

    事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素。当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件,然后在外层元素上去执行函数。父元素可以通过 event.target 访问目标元素。

    优点:

    • 简化初始化并节省内存:无需添加许多处理程序。
    • 更少的代码:添加或移除元素时,无需添加/移除处理程序。
    • DOM 修改 :我们可以使用 innerHTML 等,来批量添加/移除元素。

    局限性:

    • 首先,事件必须冒泡。而有些事件不会冒泡(focusblur)。此外,低级别的处理程序不应该使用 event.stopPropagation()
    • 其次,委托可能会增加 CPU 负载,因为容器级别的处理程序会对容器中任意位置的事件做出反应,而不管我们是否对该事件感兴趣。mousemovemouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的。

    应用场景:

    如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件,如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的。这时候就可以事件委托,把点击事件绑定在父级元素ul上面,然后执行事件的时候再去匹配目标元素。

    还有一种场景是上述列表项并不多,我们给每个列表项都绑定了事件,但是如果用户能够随时动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的。

BOM

BOM 概念

考点1:BOM 与 DOM

  1. 说说你对 BOM 的理解?

    BOM(Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象。

    其作用就是和浏览器进行一些交互操作。如前进后退、滚动条上下滚动、刷新、浏览器窗口变化,以及获取客户的一些信息如:浏览器版本,屏幕分辨率。

    浏览器的全部内容可以看成DOM,而整个浏览器可以看成BOMDOM 的顶级对象是 document,而BOM 的顶级对象是 window

考点2:页面生命周期

  1. 说说 HTML 页面的生命周期?

    HTML 页面的生命周期包含三个重要事件:

    • DOMContentLoaded —— 浏览器已完全加载 HTML,并构建了 DOM 树,但像 <img> 和样式表之类的外部资源可能尚未加载完成。
    • load —— 浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。
    • beforeunload/unload —— 当用户正在离开页面时。

    DOMContentLoaded 事件:

    触发时机:

    发生在 document 对象上。在 DOM 树构建完毕后,就会触发此事件,此时页面只包含基本的 DOM 结构。

    当浏览器处理一个 HTML 文档,并在文档中遇到 <script> 标签时,就会在继续构建 DOM 之前运行它。这是一种防范措施,因为脚本可能想要修改 DOM,甚至对其执行 document.write 操作,所以 DOMContentLoaded 必须等待脚本执行结束。外部样式表不会影响 DOM,因此 DOMContentLoaded 不会等待它们。

    <script>
      function ready() {
        alert('DOM is ready');
        // 图片目前尚未加载完成(除非已经被缓存),所以图片的大小为 0x0
        alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
      }
      document.addEventListener("DOMContentLoaded", ready);
    </script>
    <img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

    但如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成:

    <link type="text/css" rel="stylesheet" href="style.css">
    <script>
      // 在样式表加载完成之前,脚本都不会执行
      alert(getComputedStyle(document.body).marginTop);
    </script>

    DOMContentLoaded 等待脚本时,它现在也在等待脚本前面的样式。

    常见的应用场景:

    Firefox,Chrome 和 Opera 都会在 DOMContentLoaded 中自动填充表单。


    load事件:

    触发时机:

    当整个页面的资源(包括图片、样式和其他资源)都加载完毕时,会触发 window 对象上的 load 事件。可以通过 onload 属性获取此事件。

    <script>
      window.onload = function() { // 与此相同 window.addEventListener('load', (event) => {
        alert('Page loaded');
        // 此时图片已经加载完成
        alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
      };
    </script>
    <img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

    beforeunload事件:

    触发时机:

    如果访问者触发了离开页面的导航或试图关闭窗口,beforeunload 处理程序将要求进行更多确认。

    如果我们要取消事件,浏览器会询问用户是否确定。

    window.onbeforeunload = function() {
      return "There are unsaved changes. Leave now?";
    };

    unload事件:

    触发时机:

    当访问者离开页面时,window 对象上的 unload 事件就会被触发。我们可以在那里做一些不涉及延迟的操作,例如关闭相关的弹出窗口。

    let analyticsData = { /* 带有收集的数据的对象 */ };
    window.addEventListener("unload", function() {
      navigator.sendBeacon("/analytics", JSON.stringify(analyticsData));
    });

BOM 对象

考点1:Window 对象

  1. 怎么理解 window 对象?

    BOM 的核心对象是window,它表示浏览器的一个实例。

    在浏览器中,window对象有双重角色,即是浏览器窗口的一个接口,又是全局对象。

    因此所有在全局作用域中声明的变量、函数都会变成window对象的属性和方法。

  2. 如何控制 window 窗口?

    关于窗口控制方法如下:

    • moveBy(x,y):从当前位置水平移动窗体x个像素,垂直移动窗体y个像素,x为负数,将向左移动窗体,y为负数,将向上移动窗体
    • moveTo(x,y):移动窗体左上角到相对于屏幕左上角的(x,y)点
    • resizeBy(w,h):相对窗体当前的大小,宽度调整w个像素,高度调整h个像素。如果参数为负值,将缩小窗体,反之扩大窗体
    • resizeTo(w,h):把窗体宽度调整为w个像素,高度调整为h个像素
    • scrollTo(x,y):如果有滚动条,将横向滚动条移动到相对于窗体宽度为x个像素的位置,将纵向滚动条移动到相对于窗体高度为y个像素的位置
    • scrollBy(x,y): 如果有滚动条,将横向滚动条向左移动x个像素,将纵向滚动条向下移动y个像素

    window.open() 既可以导航到一个特定的url,也可以打开一个新的浏览器窗口

    如果 window.open() 传递了第二个参数,且该参数是已有窗口或者框架的名称,那么就会在目标窗口加载第一个参数指定的URL

    window.open('htttp://www.vue3js.cn','topFrame')
    ==> < a href=" " target="topFrame"></ a>

    window.open() 会返回新窗口的引用,也就是新窗口的 window 对象

    const myWin = window.open('http://www.vue3js.cn','myWin')

    window.close() 仅用于通过 window.open() 打开的窗口

    新创建的 window 对象有一个 opener 属性,该属性指向打开他的原始窗口对象

考点2:Location 对象

  1. 什么是 location 对象?有什么作用?

    Location 对象是浏览器提供的原生对象,提供 URL 相关的信息和操作方法。通过 window.locationdocument.location 属性,可以拿到这个对象。

    location属性描述如下:

    属性名 例子 说明
    hash “#contents” url中#后面的字符,没有则返回空串
    host www.wrox.com:80 服务器名称和端口号
    hostname www.wrox.com 域名,不带端口号
    href http://www.wrox.com:80/WileyCDA/?q=javascript#contents 完整url
    pathname “/WileyCDA/“ 服务器下面的文件路径
    port 80 url的端口号,没有则为空
    protocol http: 使用的协议
    search ?q=javascript url的查询字符串,通常为?后面的内容

    除了 hash之外,只要修改location的一个属性,就会导致页面重新加载新URL

    location.reload(),此方法可以重新刷新当前页面。这个方法会根据最有效的方式刷新页面,如果页面自上一次请求以来没有改变过,页面就会从浏览器缓存中重新加载

    如果要强制从服务器中重新加载,传递一个参数true即可

考点3:History 对象

  1. 什么是 history 对象?有什么作用?

    history对象主要用来操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定URL跳转。

    常用的属性如下:

    • history.go()

    接收一个整数数字或者字符串参数:向最近的一个记录中包含指定字符串的页面跳转

    history.go('xxx.com')

    当参数为整数数字的时候,正数表示向前跳转指定的页面,负数为向后跳转指定的页面

    history.go(3) //向前跳转三个记录
    history.go(-1) //向后跳转一个记录
    • history.forward():向前跳转一个页面
    • history.back():向后跳转一个页面
    • history.length:获取历史记录数
  2. 了解过 vue-router 吗?history 模式和 hash 模式有什么区别?

    hash 模式:

    形式上:hash 模式 url 里面永远带着 # 号,开发当中默认使用这个模式。

    本质是一个浏览器内置的发布订阅,改变 hash 会广播到onhashchange事件,可以在window对象上监听这个事件:

    window.onhashchange = function(event){
         console.log(event.oldURL, event.newURL);
         let hash = location.hash.slice(1); 
         document.body.style.color = hash;
    }

    每次 hash 发生变化,新旧 url 都会被记录下来,从而可以实现前进后退操作。

    history 模式:

    原理是利用了 history 对象的 API。其中比较重要的两个是 pushStatereplaceState

    history 不是依靠 url 改变来切换路由的,因为 hash 不变的情况下 url 改变不会触发任何事件,所以需要依赖内部实现的发布订阅模式,通知相应的组件。并且这个过程需要实现持久化存储,保证在刷新之后还能停留在当前路由。

    使用 history 模式,如果直接输入 URL 回车或者刷新是会发送真实请求的。因此在服务端需要配置重定向返回 index,再由前端处理路由匹配。