前端高频面试题

前言 

很多小伙伴为了面试会去看一些大厂的经典面试题,这里的 “看” 只是说加深一下以往的印象,也就是说你之前是用到过或者是学过,只是长时间用不到有点淡忘了。千万不要为了面试而死记硬背,这是程序员最大的悲哀,请记住一句话:“未经你思考的知识是不属于你的”

楼主2018年毕业,三年前端开发经验。前段时间花了半个月时间面试,收到七八个中大厂offer。以下是我对前端开发一些碎片化知识的总结,所谓碎片化,其实都是积木化,每一块积木都可以单独学习,自主拼接,进而组合成自己想要的形状,充分运用。

文章太长,可以查看左侧边栏底部的目录进行快速定位,若文章中有错误,也麻烦各位大佬能够在评论区指出,非常感谢!


HTML

1、什么是HTML语义化?

在编程中,语义指的是一段代码的含义,这个HTML元素有什么作用,扮演了什么样的角色。简单的概括为:在适当的位置使用适当的标签,用正确的标签做正确的事

2、HTML5新增语义元素?

Header nav article section aside footer main stong em small

3、为什么要语义化?

清晰的代码结构: 使页面没有css的情况下,也能够呈现出很好的内容结构

有利于SEO: 爬虫依赖标签来确定关键字的权重,因此可以和搜索引擎建立良好的沟通,帮助爬虫抓取更多的有效信息

提升用户体验: 例如title、alt可以用于解释名称或者解释图片信息,以及label标签的灵活运用。

便于团队开发和维护: 语义化使得代码更具有可读性,让其他开发人员更加理解你的html结构,减少差异化。

方便其他设备解析: 如屏幕阅读器、盲人阅读器、移动设备等,以有意义的方式来渲染网页。

4、b和strong的区别?

两者虽然在网页中显示效果样,但实际目的不同。

这个标签对应bold ,即文本加粗,其目的仅仅是为了加粗显示文本,是种样式/风格需求

这个标签意思是加强,表示该文本比较重要,提醒读者/终端注意。为了达到这个目的,浏览器等终端将其加粗显示;

为了加粗而加粗, 为了标明重点而加粗。

最重要的区别的就是样式标签与语义化标签的区别。最容易理解的场景就是盲人朋友使用阅读设备阅读网时: 会重读, 不会

5、Iframe有哪些缺点?

iframe会阻塞主页面的Onload事件;搜索引擎的检索程序无法解读这种页面,不利于SEO;iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载;使用iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过javascript动态给iframe添加src属性值,这样可以绕开以上两个问题。

6、说说减少DOM数量的方法?

可以使用伪元素,阴影实现的内容尽不使用DOM实现,如清除浮动、样式实现等;

按需加载,减少不必要的渲染;

结构合理,语义化标签,减少代码;

7、一次性给你大量DOM元素怎么优化?

1.缓存dom对象: 首先不管在什么场景下。操作Dom般首先会去访问Dom ,尤其是像循环遍历这种时间复杂度可能会比较高的操作。那么可以在循环之前就将主节点,不必循环的Dom节点先获取到,那么在循环里就可以直接引用,而不必去重新查询。

    // 不好的做法
    for (let i = 0; i < 10; i++) {
      document.getElementById("temp").innerHTML = ""
      document.getElementById("temp").innerHTML += "

temp

"; } // 改进的做法 let temp = document.getElementById(temp); for (let i = 0; i < 10; i++) { temp.innerHTML = ""; temp.innerHTML += "

temp

"; } //再改进 let temp = document.getElementById("temp"); let fragments = "" for (let i = 0; i < 10; i++) { fragments += "

temp

"; } temp.innerHTML = ""; temp.innerHTML = fragments;

2.文档片段: 利用document.createDocumentFragment()方法创建文档碎片节点,创建的是一个虚拟的节点对象。向这个节点添加dom节点,修改dom节点并不会影响到真实的dom结构。我们可以利用这一点先将我们需要修改的dom并修改完,保存至文档碎片中,然后用文档碎片次性的替换真实的dom节点。与虚拟dom类似,同样达到了不频繁修改dom而导致的重排跟重绘的过程。

    //创建10个段落,常规的方式
    for (let i = 0; i < 10; i++) {
      let p = document.createElement("p");
      let oTxt = document.createTextNode("段落" + i);
      p.appendChild(oTxt);
      document.body.appendChild(p);
    }

    //使用了createDocumentFragment()的程序
    let pFragment = document.createDocumentFragment();
    for (let i = 0; i < 10; i++) {
      let p = document.createElement("p");
      let oTxt = document.createTextNode("段落" + i);
      p.appendChild(oTxt);
      pFragment.appendChild(p);
    }
    document.body.appendChild(pFragment);

3.用innerhtml代替高频的appendChild

4.虚拟dom

8、Html5有哪些新特性?

1.拖拽释放(Drag and drop) API

2.语义化更好的内容标签( header,nav,footer,aside,article,section,main )

3.音频、视频API(audio,video)

4.画布(Canvas) API

5.地理(Gealocation) API

6.本地离线存储localStorage长期存储数据,浏览器关闭后数据不丢失;

7. sessionStorage的数据在浏览器关闭后自动删除

8.表单控件, calendar、date、 time、 email、url、search

9.新的技术webworker, websocket, Geolocation

9、如何区分html和html5?

1.文档类型声明


 


2.结构语义

Html:没有体现结构语义化的标签,通常都是这样来命名的

, 这样表示网站的头部

Html5:在语义上却有很大的优势,提供了一些新的HTML5标签比如: article、 footer、header、nav、 section , 这些通俗易懂

10、前端如何处理网站seo?

1.突出重要内容

合理的设计title 、description 和keywords

标题:只强调重点即可,尽量做到每个页面的<title> 标题中不要设置相同的内容。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><meta keywords>标签:关键词,列举出几个页面的重要关键字即可,切记过分堆砌。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><meta description>标签:网页描述,需要高度概括网页内容,切记不能太长、 过分堆砌关键词,每个页面也要有所不同。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>2</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>语义化书写HTML代码,符合W3C标准</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">尽量让代码语义化,在适当的位置使用适当的标签,用正确的标签做正确的事。让阅读源码者和”蜘蛛”都一目了然。比如: h1-h6是用于标题类的,<nav> 标签是用来设置页面主导航,列表形式的代码使用ul或ol ,重要的文字使用strong等。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>3</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong><a></strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>链接</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">页内链接,要加title 属性加以说明,让访客和”蜘蛛”知道。而外部链接,链接到其他网站的,则需要加上rel="nofollow" 属性,告诉"蜘蛛” 不要爬,因为一旦"蜘蛛”爬了外部链接之后,就不会再回来了。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>4</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.正文</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>标题要用</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>h1标签</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">h1标签自带权重,"蜘蛛”认为它最重要,一个页面有且最多只能有一个H1标签,放在该页面最重要的标题上面,如首页的logo.上可以加H1标签。副标题用<h2> 标签,而其它地方不应该随便乱用h标题标签。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>5.<img>应使用"alt"属性加以说明</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当网络速度很慢,或者图片地址失效的时候,就可以体现出alt属性的作用,他可以让用户在图片没有显示的时候知道这个图片的作用。同时为图片设置高度和宽度,可提高</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">页</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面的加载速度。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>6</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>表格应该使用<caption> 表格标题标签</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">caption元素定义表格标题。caption 标签必须紧随table标签之后</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>7</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong> <strong> 、<em>标签</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">需要强调是使用<strong>标签在搜索引擎中能够得到高度的重视,它能突出关键词,表现重要的内容,<em>标签强调效果仅次于<strong> 标签; <b>、<i> 标签:只是用于显示效果时使用,在SEO中不会起任何效果。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>8</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>重要内容不要用JS输出</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为”蜘蛛" 不会读取JS里的内容,所以重要内容必须放在HTML里。前端框架针对SEO的缺陷,可通过服务端渲染弥补</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>9</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>尽少使用iframe框架</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为"蜘蛛”一般不会读取其中的内容。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>10</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>搜索引擎会过滤掉display:none其中的内容</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>11</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>蜘蛛只能抓取a标签中href</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><a href= "Default.aspx?id=1" >测试</a>最好后面不要带参数<a href= "Default.aspx" >测试</a>如果带上参数蜘蛛不会考虑的。这样的话,就需要用到URL写了。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>12</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>蜘蛛不会执行JavaScript</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">换句话说如果在a标签中使用了onclick蜘蛛是不会抓到的。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>13</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>蜘蛛只能抓到get请求的页面,不会抓到post请求的页面</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>14</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>我们希望网页的前台页面全部被蜘蛛抓到</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">但是不希望后台页面被蜘蛛抓到,蜘蛛可没有那么智能,知道你的网站哪个是前台页面,哪个是后台页面。</span></span></span><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">这里就需要创建一个名为"robots.txt” (注意robots.txt是一个协议,不是命令, -般最好要遵守的robots.txt是搜索</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">引</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">擎搜索该网站时的第一个文件。</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、JavaScript标签的async和defer属性的区别?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">两者共同点都是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使脚本</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">异步加载</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">defer 属性在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。多个设置了 defer 属性的脚本是顺序执行的</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">async 属性当脚本加载完成后立即执行js脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个 async 属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序依次执行。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当一个script标签内同时包含defer与async属性时,只会触发async ,不会触发defer ,除非浏览器不兼容async。</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、src和href的区别?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">src 用于替换当前元素,href 用于在当前文档和引用资源之间确立联系。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,例如 js 脚本,img 图片和 frame 等元素。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将 js 脚本放在底部而不是头部。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">href 是 Hypertext Reference 的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加<link  href=”common.css” rel=”stylesheet”/>那么浏览器会识别该文档为 css 文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用 link 方式来加载 css,而不是使用@import 方式。</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>13、Doctype的作用?严格模式和混杂模式的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DOCTYPE是document type (文档类型) 的缩写。<!DOCTYPE >声明位于文档的最前面,处于标签之前,它不是html标签。主要作用是告诉浏览器的解析器使用哪种HTML规范或者XHTML规范来解析页面。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">严格模式和混杂模式都是浏览器的呈现模式,浏览器究竟使用混杂模式还是严格模式呈现页面与网页中的DTD(文件类型定义)有关,DTD里面包含了文档的规则。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">严格模式:又称标准模式,是指浏览器按照W3C标准来解析代码,呈现页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">混杂模式:又称为怪异模式或者兼容模式,是指浏览器按照自己的方式来解析代码,使用一种比较宽松的向后兼容的方式来显示页面。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>14、Meta有哪些属性,作用是什么</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">meta标签用于描述网页的元信息,如网站作者、描述、关键词,meta通过name=xxx和content=xxx的形式来定义信息,常用设置如下:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">meta元素包含四大属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>charset属性</strong></span></span></strong><strong> </strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">声明了页面的字符编码</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">常用的值: UTF-8(Unicode字符编码)、 ISO-8859-1(拉J字母表的字符编码)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>conten</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>t</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>属性</strong></span></span></strong> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通常配合name或http</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">equiv使用,能够给这两个属性提供一个值 </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>http-equiv</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>属性</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可用用做 HTTP头部的某些作用,通过定义该属性可以改变服务器和用户代理的行为。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>n</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>ame</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>属性 </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用于定义页面的元数据。他不能与http-equiv、charset共存。通常是content配合使用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>15、前端性能优化</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;"><strong>内容优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)减少HTTP请求数:这条策略是最重要最有效的,因为一个完整的请求要经过DNS寻址,与服务器建立连接,发送数据,等待服务器响应,接收数据这样一个消耗时间成本和资源成本的复杂的过程。常见方法:合并多个CSS文件和js文件,利用CSS Spri</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">tes整合图像,Inline Images(使用 data:URL scheme在实际的页面嵌入图像数据 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">),合理设置HTTP缓存等。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)减少DNS查找</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)避免重定向(302.303)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)使用Ajax缓存</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(5)延迟加载组件,预加载组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(6)减少DOM元素数量:页面中存在大量DOM元素,会导致javascript遍历DOM的效率变慢。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(7)最小化iframe的数量:iframes 提供了一个简单的方式把一个网站的内容嵌入到另一个网站中。但其创建速度比其他包括JavaScript和CSS的DOM元素的创建慢了1-2个数量级。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(8)避免404:HTTP请求时间消耗是很大的,因此使用HTTP请求来获得一个没有用处的响应(例如404没有找到页面)是完全没有必要的,它只会降低用户体验而不会有一点好处。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;"><strong>Cookie优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)减小Cookie大</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)针对Web组件使用域名无关的Cookie</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;"><strong>css优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)将CSS代码放在HTML页面的顶部(在文档内加载你的样式表,这样做的好处是:提高网页渲</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">染性能,避免网页出现白屏或者是没有样式的内容)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)避免使用CSS表达式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)使用<link>来代替@import</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)避免使用Filters</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;"><strong>js优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)将JavaScript脚本放在页面的底部。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)将JavaScript</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">和CSS作为外部文件来引用:在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏览器中产生缓存。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)缩小JavaScript和CSS</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)删除重复的脚本</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(5)最小化DOM的访问:使用JavaScript访问DOM元素比较慢。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(6)减少作用域链查找</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(7)在 Javascript中使用”+”号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生成新的字符串变量,然后将拼接结果赋值给新变量。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;"><strong>图片优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)合理控制图片大小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)通过CSS Sprites优化图片 (这是减少图像请求的有效方法,把所有的背景图像都放到一个图片文</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">件中,然后通过CSS的background-image和background-position属性来显示图片的不同部分;合并后的图片会比分离的图片总和要小,这是因为它降低了图片自身的开销)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)不要在HTML中使用缩放图片</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)图标尽量使用矢量图标</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>16、优雅降级和渐进增强?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>渐进增强:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优雅降级:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>区别:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.优雅降级是从复杂的现状开始,并试图减少用户体验的供给</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.降级(功能衰减)意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h2 style="margin-left:.0001pt;text-align:justify;"></h2> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>CSS</strong></strong></h2> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、让一个div水平垂直居中</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"></p> <pre><code class="language-css"> div { position: absolute; left: 50%; top: 50%; margin-left: -250px; margin-top: -250px; width: 500px; height: 500px; background: yellow; z-index: 1; }</code></pre> <pre><code class="language-css"> div { position: absolute; left: 50%; top: 50%; width: 500px; height: 500px; background: yellow; z-index: 1; transform: translate3d(-50%, -50%, 0); }</code></pre> <pre><code class="language-css"> .parent { display: flex; } .child { margin: auto; }</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、介绍一下BFC 以及如何触发BFC</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>什么是BFC</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BFC全称 Block Formatting Context 即块级格式上下文,简单的说,BFC是页面上的一个隔离的独立容器,不受外界干扰或干扰外界</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>BFC的渲染规则是什么</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BFC是页面上的一个隔离的独立容器,不受外界干扰或干扰外界</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">计算BFC的高度时,浮动子元素也参与计算(即内部有浮动元素时也不会发生高度塌陷)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BFC的区域不会与float的元素区域重叠</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BFC内部的元素会在垂直方向上放置</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BFC内部两个相邻元素的margin会发生重叠</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>如何触发BFC</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根元素,即HTML元素</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">float不为 none</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">overflow的值不为 visible</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">position 为 absolute 或 fixed</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">display的值为 inline-block 或 table-cell 或 table-caption 或 grid</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>BFC</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>在布局中的应用?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">防止margin重叠(塌陷)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自适应多栏布局</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">清除内部浮动</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、display:none和visibility:hidden的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>display:none</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">隐藏后的元素不占据任何空间</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">给子元素设置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">display:none 不会显示出来</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">修改后会引起回流</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">会影响计数器的计数</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(ol)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>visibility:hidden</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">隐藏后的元素空间依旧保留</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">visibility具有继承性,给父元素设置visibility:hidden;子元素也会继承这个属性。但是如果重新给子元素设置visibility: visible,则子元素又会显示出来</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">修改后不会引起回流</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">会影响计数器的计数</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(ol)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、清除浮动的方法</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>设置父元素高度</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置父元素的高度解决的是元素浮动产生的父元素高度塌陷问题,其内部元素浮动影响并未彻底清除,且需要进行计算然后再设置, 比较固定,一旦元素的高度发生改变,父元素的高度也需要再次计算设置,不够灵活。除非内容高度固定一成不变,否则不推荐使用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>clear +空元素</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在浮动元素下方添加空div,并给该元素写css样式:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">{clear:both;height:0;veflow.hidden;}</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>伪元素+clear</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用自带的属性可以非常好的解决浮动影响。该方法直观有效,哪里需要清除就在哪里添加一个兄弟元素,设置clear属性即可,一般属性值都设置为both清除两侧的浮动,也可以根据实际需要清除左侧或右侧,灵活方便直观。在bootstrap 4.0框架中的clearfix应用了该访法,其是在父元素中设置了伪元素,并设置了伪元素隐藏。</span></span></p> <pre><code class="language-css"> .cearfix:after { display: block; clear: both; content: ""; }</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>利用BFC</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据BFC的规则,计算BFC的高度时,浮动元素也参与计算。因此清除浮动,只需要触发一个BFC即可</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、Css盒模型</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">盒模型是css中的一种基础设计模式, web页面中的所有元素都可以当做一个盒模型,每一个盒模型都是由content, margin , padding和border等属性组合所构成的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS中的盒模型有两种: W3C标准模型和IE的传统模型。不同之处在于两者的计算方式不同。给元素设置宽度width和高度height,在w3c盒子模型中,width和height只是content部分,在IE盒模型中,这个width和height包括了 content、padding和border三个部分</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、Css选择器有哪些? 哪些属性可以继承?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>选择器</strong></span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">标签名选择器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">类选择器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ID选择器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">相邻选择器(h1+p )</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子选择器(ul> li)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后代选择器(li a)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通配符选择器(* )</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">属性选择器( a[rel=" external"] )</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">伪类选择器( a:hover, li:nth-child )</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">群组选择器( div,p )</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>继承属性</strong></span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font:组合字体</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font-family:规定元素的字体系列</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font-weight:设置字体的粗细</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font-size:设置字体的尺寸</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font-style:定义字体的风格</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">font-variant:偏大或偏小的字体</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">text-indent:文本缩进</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">text-align:文本水平对齐</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">line-height:行高</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">word-spacing:增加或减少单词间的空白</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">letter-spacing:增加或减少字符间的空白</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">text-transform:控制文本大小写</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">direction:规定文本的书写方向</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">color:文本颜色</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">visibility: 隐藏元素</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">caption-side:定位表格标题位置</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">border-collapse:合并表格边框</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">border-spacing:设置相邻单元格的边框间的距离</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">empty-cells:单元格的边框的出现与消失</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">table-layout:表格的宽度由什么决定</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">quotes:设置嵌套引用的引号类型</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">cursor:箭头可以变成需要的形状</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>非继承属性</strong></span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">display</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文本属性:vertical-align、text-decoration</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">盒子模型的属性:宽度、高度、内外边距、边框等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">背景属性:背景图片、颜色、位置等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定位属性:浮动、清除浮动、定位position等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">生成内容属性:content、counter-reset、counter-increment</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">轮廓样式属性:outline-style、outline-width、outline-color、outline</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">页面样式属性:size、page-break-before、page-break-after</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、flex:1的完整写法是?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex属性是flex-grow、 flex-shrink、 flex-basis 的简写</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex-grow:定义项目的放大比例,默认为0 ,即如果存在剩余空间,也不放大</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex-shrink:定义了项目的缩小比例,默认为1 ,即如果空间不足,该项目将缩小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex-basis:定义的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-grow和flex-shrink生效前的尺寸,浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto,即项目的本来大小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex:1的完整写法是</span></span></p> <pre><code class="language-css">flex-grow: 1; flex-shrink: 1; flex-basis: 0%;</code></pre> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、行内元素和块级元素什么区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">行内元素会在一条直线上排列(默认宽度只与内容有关) , 都是同一行的,水平方向排列。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">块级元素各占据一行(默认宽度是它本身父容器的100% (和父元素的宽度一致 , 与内容无关) ,垂直方向排列。块级元素从新行开始,结束接着一个断行。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">块级元素可以包含行内元素和块级元素。行内元素不能包含块级元素,只能包含文本或者其它行内元素。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">行内元素与块级元素属性的不同,主要是盒模型属性上,行内元素设置width无效, height无效(可以设置line-height) , margin上下无效,padding上下无效</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、Link和@important的区别</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务; @import属于CSS范畴,只能加载CSS。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">link引用CSS时,在页面载入时同时加载; @import需要页面网页完全载入以后加载。所以会出现一开始没有css样式,闪烁</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">下出现样式后的页面(网速慢的情况下)</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">link支持使用Javascript控制DOM去改变样式;而@import不支持。</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、响应式和自适应的区别</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、响应式布局实现方案</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>媒体查询</strong></span></span></strong></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS3媒体查询可以让我们针对不同的媒体类型定义不同的样式,当重置浏览器窗口大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>百分比布局</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过百分比单位,可以使得浏览器中组件的宽和高随着浏览器的高度的变化而变化,从而实现响应式的效果。Bootstrap里面的栅格系统就是利用百分比来定义元素的宽高,CSS3支持最大最小高,可以将百分比和max(min)一起结合使用来定义元素在不同设备下的宽高。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">计算困难</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可以看出,各个属性中如果使用百分比,相对父元素的属性并不是唯一的。比如width和height相对于父元素的width和height,而margin、padding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,造成我们使用百分比单位容易使布局问题变得复杂。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>rem布局</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">REM是CSS3新增的单位,rem单位都是相对于根元素html的font-size来决定大小的,根元素的font-size相当于提供了一个基准,当页面的size发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。 因此,如果通过rem来实现响应式的布局,只需要根据视图容器的大小,动态的改变font-size即可(而em是相对于父元素的)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>视口单位</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度,除了vw和vh外,还有vmin和vmax两个相关的单位</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从对比中我们可以发现,vw单位与百分比类似,但确有区别,前面我们介绍了百分比单位的换算困难,这里的vw更像"理想的百分比单位"。任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Flex弹性布局,兼容性较差</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Grid网格布局,兼容性较差</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Columns栅格系统,往往需要依赖某个UI库,如Bootstrap</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、重排和重绘?如何避免?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>什么是重绘重排</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当我们改变了</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">个元素的尺寸位置属性时,会重新进行样式计算(computedstyle)布局(layout)绘制( paint )以及后面的所有流程,这种行为称为重排。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当改变了某个元素的颜色属性时不会重新触发布局,但还是会触发样式计算和绘制这就是重绘。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们可以发现重排和重绘都会占用主线程,还有JS也会运行在主线程,所以就会出现抢占执行时间的问题,如果你写了一个不断导致重排重绘的动画,浏览器则需要在每一帧都运行样式计算布局和绘制的操作。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>触发的一些因素</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.页面首次进入的渲染。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.浏览器resize</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.元素位置和尺寸发生改变的时候</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.可见元素的增删</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.内容发生改变</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.字体的font的改变</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7. CSS伪类激活</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>css避免</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用transform替代top等位移;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用visibility替换display: none</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免使用table布局</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">尽可能在DOM树的最末端改变class</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免设置多层内联样式,尽量层级扁平</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将动画效果应用到position属性为absolute或fixed的元素上</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免使用CSS表达式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将频繁重绘或者回流的节点设置为图层,比如video , iframe</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS3硬件加速( GPU加速) , 可以是transform:translateZ(0)、opacity、 filters、 will-change,Will-change提前告诉浏览器元素会发生什么变化;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>J</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>avascript避免</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免频繁操作样式,合并操作</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免频繁操作DOM ,合并操作;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">防抖节流控制频率;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免频繁读取会引发回流/重绘的属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对具有复杂动画的元素使用绝对定位</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>13、Css预处理器</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>CSS预处理器</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">为CSS增加编程特性的拓展语言,可以使用变量、简单逻辑判断、函数等基本编程技巧;CSS预处理器编译输出还是标准的CSS样式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Less、 Sass都是是动态的样式语言,是CSS预处理器,CSS上的一种抽象层。他们是一种特殊的语法/语言而编译成CSS。less变量符号是@ , Sass变量符号是$;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>解决的问题</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS语法不够强大,因为无法嵌套导致有很多重复的选择器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">没有变量和合理的样式复用机制,导致逻辑上相关的属性值只能以字面量的形式重复输出,难以维护</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>常用规范</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">变量、嵌套语法、混入、@import. 运算、函数、继承</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>CSS预处理器带来的好处</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS代码更加整洁,更易维护,代码量更少</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">修改更快,基础颜色使用变量,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">处动处处动.</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">常用代码使用代码块,节省大量代码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS嵌套减少了大量的重复选择器,避免</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">些低级错误</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">变量、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">混入大大提升了样式的复用性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">额外的工具类似颜色函数( lighten,darken ,transparentize等等) , mixins , loops ,这些方法使css更像一个真正的编程语言,让开发者能够有能力生成更加复杂的css样式。</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>14、em px rem vh vw的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>px:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">表示像素,所谓像素就是呈现在我们显示器上的一个个小点,每个像素点都是大小等同的,所以像素为计量单位被分在了绝对长度单位中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>em:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(1em = 16px)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>rem:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">相对单位,相对的只是HTML根元素font-size的值。同理,如果想要简化font-size的转化,我们可以在根元素html中加入font-size: 62.5%</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>vw:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">就是根据窗口的宽度,分成100等份,100vw就表示满宽,50vw就表示一半宽。(vw 始终是针对窗口的宽),同理,vh则为窗口的高度</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>15、三栏布局(左右固定100px,中间自适应)</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>浮动+margin</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左float:left; width:100px</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">右float:right; width:100px</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中margin: 0 100px</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>绝对定位+margin</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左top:0; left:0; width:100px </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">右top:0; right:0; width:100px</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中margin: 0 100px</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex布局</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左 width:100px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">右 width: 100px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中 flex:1;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>float + c</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>alc计算</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左 width:100px; float: left;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">右 width: 100px; float: right;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中 width: calc(100%-200px)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>table布局</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父 display:table  table-layout: fixed;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左中右 display: table-cell;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左右 width:100px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中 width: 100%</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>g</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>rid布局</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父 display:grid  grid-template-columns: 100px auto 100px;</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>16、弹性盒模型flexbox</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Flexible Box</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 简称 flex,意为”弹性布局”,可以简便、完整、响应式地实现各种页面布局</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。采用flex布局的元素称为容器,容器中默认存在两条轴,主轴和交叉轴,呈90度关系。项目默认沿主轴排列</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>容器属性:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-direction:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">决定主轴的方向(即项目的排列方向)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-wrap:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">弹性元素永远沿主轴排列,那么如果主轴排不下,通过flex-wrap决定容器内项目是否可换行</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-flow:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>justify-content:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义了项目在主轴上的对齐方式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>align-items:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义项目在交叉轴上如何对齐</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>align-content:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>容器成员属性:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>order:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义项目的排列顺序。数值越小,排列越靠前,默认为0</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-grow: </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义项目的放大比例(容器宽度>元素总宽度时如何伸展)默认为0,即如果存在剩余空间,也不放大</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-shrink:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义了项目的缩小比例(容器宽度<元素总宽度时如何收缩),默认为1,即如果空间不足,该项目将缩小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>flex-basis:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-grow和flex-shrink生效前的尺寸,浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto,即项目的本来大小,如设置了width则元素尺寸由width/height决定(主轴方向),没有设置则由内容决定</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>align-self:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">允许单个项目有与其他项目不一样的对齐方式,可覆盖</span></span><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>align-items</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">属性,默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>17、Grid网格布局</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Grid</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 布局即网格布局,是一个二维的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">网格</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>18、单行溢出、多行溢出</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>单行溢出</strong></span></span></strong></span></p> <pre><code class="language-css"> p { overflow: hidden; line-height: 40px; width: 400px; height: 40px; border: 1px solid red; text-overflow: ellipsis; white-space: nowrap; }</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>多行溢出</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"></p> <pre><code class="language-css"> p { width: 400px; border-radius: 1px solid red; -webkit-line-clamp: 2; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; }</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>19、如何让浏览器支持一个小于12px的字体</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>z</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>oom</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">zoom 的字面意思是“变焦”,可以改变页面上元素的尺寸,属于真实尺寸</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">zoom:50%,表示缩小到原来的一半</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">zoom:0.5,表示缩小到原来的一半</span></span></p> <pre><code class="language-css"> .span1 { font-size: 12px; display: inline-block; zoom: 0.8; }</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>-webkit-transform:scale()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">针对chrome浏览器,加webkit前缀,用transform:scale()这个属性进行缩</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">放</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">注意的是,使用scale属性只对可以定义宽高的元素生效,所以,下面代码中将span元素转为行内块元素</span></span></p> <pre><code class="language-css"> .span1 { font-size: 12px; display: inline-block; -webkit-transform: scale(0.8); }</code></pre> <p></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:.0001pt;text-align:left;"><strong><strong>20、display有哪些值及作用</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>block :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">块对象的默认值。用该值为对象之后添加新行</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>none :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">隐藏对象。与visibility属性的hidden值不同,其不为被隐藏的对象保留其物理空间</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>inline :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">内联对象的默认值。用该值将从对象中删除行</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>compact :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">分配对象为块对象或基于内容之上的内联对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>m</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>arker :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">指定内容在容器对象之前或之后。要使用此参数,对象必须和:after及:before 伪元素一起使用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>inline-table :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将表格显示为无前后换行的内联对象或内联容器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>list-item :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将块对象指定为列表项目。并可以添加可选项目标志</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>run-in :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">分配对象为块对象或基于内容之上的内联对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>t</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>able :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将对象作为块元素级的表格显示</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:.0001pt;text-align:left;"><strong><strong>21、position的值</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>static(默认):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在一般情况下,我们不需要特别的去声明它,但有时候遇到继承的情况,我们不愿意见到元素所继承的属性影响本身,从而可以用position:static取消继承,即还原元素定位的默认值。设置为 static 的元素,它始终会处于页面流给予的位置(static 元素会忽略任何 top、 bottom、left 或 right 声明)。一般不常用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>relative(相对定位):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">相对定位是相对于元素默认的位置的定位,它偏移的top,right,bottom,left 的值都以它原来的位置为基准偏移,而不管其他元素会怎么样。注意 relative 移动后的元素在原来的位置仍占据空间。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>absolute(绝对定位):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置为 absolute 的元素,如果它的父容器设置了 position 属性,并且 position 的属性值为 absolute 或者 relative,那么就会依据父容器进行偏移。如果其父容器没有设置 position 属性,那么偏移是以 body 为依据。注意设置 absolute 属性的元素在标准流中不占位置。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>fixed(固定定位):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">位置被设置为 fixed 的元素,可定位于相对于浏览器窗口的指定坐标。不论窗口滚动与否,元素都会留在那个位置。它始终是以 body 为依据的。注意设置 fixed 属性的元素在标准流中不占位置。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>22、css3有哪些新特性</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">新增选择器 p:nth-child(n){color: rgba(255, 0, 0, 0.75)}</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">弹性盒模型 display: flex;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">多列布局 column-count: 5;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">媒体查询 @media(max-width: 480px){.box: {column-count: 1;}}</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">个性化字体 @font-face{font-family:BorderWeb;src:url(BORDERW0.eot);}</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">颜色透明度 color: rgba(255, 0, 0, 0.75);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">圆角 border-radius: 5px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">渐变 background:linear-gradient(red, green, blue);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">阴影 box-shadow:3px 3px 3px rgba(0, 64, 128, 0.3);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">倒影 box-reflect: below 2px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文字装饰 text-stroke-color: red;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文字溢出 text-overflow:ellipsis;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">背景效果 background-size: 100px 100px;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">边框效果 border-image:url(bt_blue.png) 0 10;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">旋转 transform: rotate(20deg);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">倾斜 transform: skew(150deg, -10deg);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">位移 transform:translate(20px, 20px);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缩放 transform: scale(.5);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">平滑过渡 transition: all .3s ease-in .1s;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">动画 @keyframes anim-1 {50% {border-radius: 50%;}} animation: anim-1 1s;</span></span></p> <p></p> <p></p> <hr> <h2>JavaScript</h2> <h4 style="margin-left:.0001pt;text-align:left;"><strong><strong>1、javascript数据类型?存储差别?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>基本数据类型:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">js 一共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 和 ES10 中新增的 BigInt 类型。Symbol 代表创建后独一无二且不可变的数据类型,它的出现我认为主要是为了解决可能出现的全局变量冲突的问题。BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>复杂数据类型:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">指的是 Object 类型,所有其他的如 Array、Date 等数据类型都可以理解为 Object 类型的子类。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>存储差别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、Javascript的原生对象、内置对象、宿主对象?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>原生对象:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">独立于宿主环境的 ECMAScript </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实现提供的对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">avaScript中的原生对象有Object、Function、Array、String、Boolean、Math、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError和Global。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>内置对象:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">由 ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现 </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">目前定义的内置对象只有两个:Global 和 Math </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>宿主对象:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">由 ECMAScript 实现的宿主环境提供的对</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">所有的 BOM 和 DOM 对象都是宿主对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、数组常用的方法?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>增:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">push()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">unshift()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">splice()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">concat()</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>删:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">pop()、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">shift()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">splice()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">slice()</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>改:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">splice()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>查:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">includes()、indexOf()、find()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>排序:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">reverse()、sort()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>转换:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">join()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>迭代:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">some()  every()  forEach()  filter()  map()</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、字符串常用方法?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>增: </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">+、${}、concat</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>删:</strong></span></span></strong> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">slice()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、substr()、substring()</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>改:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">trim()、trimLeft()、trimRight()、repeat() </span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>查:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">chatAt()、indexOf()、includes()、startWith()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>转换:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">toLowerCase()、toUpperCase()、split()</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>迭代:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">some()、every()、forEach()、filter()、map()</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、==和===的区别</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">等于操作符用两个等于号( == )表示,如果操作数相等,则会返回 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">true</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在JavaScript中存在隐式转换。等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">全等操作符由 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">true</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。即类型相同,值也需相同</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、深拷贝和浅拷贝的区别?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浅拷贝---浅拷贝是指复制对象的时候,只对第一层键值对进行独立的复制,如果对象内还有对象,则只能复制嵌套对象的地址</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">深拷贝---深拷贝是指复制对象的时候完全的拷贝一份对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。其实只要递归下去,把那些属性的值仍然是对象的再次进入对象内部一 一进行复制即可。</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>浅拷贝</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.Object.assign()</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.slice()</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.concat()</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.扩展运算符</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>深拷贝</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.JSON.stringify(JSON.parse())</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对象上的 value 值为 undefined 、 symbol和函数的键值对会被忽略,</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">NaN、无穷大、无穷小会被转为 null</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.递归深拷贝函数</span></span></p> <pre><code class="language-javascript"> // 深拷贝函数封装 function deepCopy(obj) { // 根据obj的类型判断是新建一个数组还是对象 let newObj = Array.isArray(obj)? [] : {}; // 判断传入的obj存在,且类型为对象 if (obj && typeof obj === 'object') { for(key in obj) { // 如果obj的子元素是对象,则进行递归操作 if(obj[key] && typeof obj[key] ==='object') { newObj[key] = deepCopy(obj[key]) } else { // // 如果obj的子元素不是对象,则直接赋值 newObj[key] = obj[key] } } } return newObj // 返回新对象 } // 对象的深拷贝案例 let obj1 = { a: '1', b: '2', c: { name: 'Demi' } } let obj2 = deepCopy(obj1) //将obj1的数据拷贝到obj2 obj2.c.name = 'dingFY' console.log(obj1) // {a: "1", b: "2", c: {name: 'Demi'}} console.log(obj2) // {a: "1", b: "2", c: {name: 'dingFY'}}</code></pre> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、什么是闭包?闭包的作用是什么?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>三个特性:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数嵌套函数</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数内部可以引用外部的参数和变量</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">参数和变量不会被垃圾回收机制回收</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>作用:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#3a3a3a;">使用闭包主要是为了设计私有的方法和变量</span></span><span style="background-color:#ffffff;"><span style="color:#3a3a3a;">,</span></span><span style="background-color:#ffffff;"><span style="color:#3a3a3a;">闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、原型和原型链</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在 js 中我们是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性值,这个属性值是一个对</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">象,这个对象包含了可以由该构造函数所有实例共享的属性和方法。当我们使用构造函数新建一个</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后,在这个</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的内部将包含一个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原型链的终点是null</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>获取原型的方法</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">p.__proto__</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">p.constructor.prototype</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Object.getPrototypeOf(p)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、作用域和作用域链</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">作用域,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">即变量和函数生效(</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">也就是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能被访问)的区域或集合</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>作用域分类</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">全局作用域:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数作用域:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">块级作用域:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>作用域链</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量或是直接报错</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、ES5实现继承的几种方法</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>原型链继承</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原型链继承的原理很简单,直接让子类的原型对象指向父类实例,当子类实例找不到对应的属性和方法时,就会往它的原型对象,也就是父类实例上找,从而实现对父类的属性和方法的继承</span></span></p> <p style="margin-left:0;text-align:left;"></p> <pre><code class="language-javascript"> // 父类 function Parent() { this.name = 'Demi' } // 父类的原型方法 Parent.prototype.getName = function () { return this.name } // 子类 function Child() {} // 让子类的原型对象指向父类实例, 这样一来在Child实例中找不到的属性和方法就会到原型对象(父类实例)上寻找 Child.prototype = new Parent() Child.prototype.constructor = Child // 根据原型链的规则,顺便绑定一下constructor, 这一步不影响继承, 只是在用到constructor时会需要 // 然后Child实例就能访问到父类及其原型上的name属性和getName()方法 const child = new Child() child.name // 'Demi' child.getName() // 'Demi'</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">由于所有Child实例原型都指向同一个Parent实例, 因此对某个Child实例的父类引用类型变量修改会影响所有的Child实例</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在创建子类实例时无法向父类构造传参, 即没有实现super()的功能</span></span></p> <pre><code class="language-javascript"> // 示例 function Parent() { this.name = ['Demi'] } Parent.prototype.getName = function () { return this.name } function Child() {} Child.prototype = new Parent() Child.prototype.constructor = Child // 测试 const child1 = new Child() const child2 = new Child() child1.name[0] = 'foo' console.log(child1.name) // ['foo'] console.log(child2.name) // ['foo'] (预期是['Demi'], 对child1.name的修改引起了所有child实例的变化)</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>构造函数继承</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">构造函数继承,即在子类的构造函数中执行父类的构造函数,并为其绑定子类的this,让父类的构造函数把成员属性和方法都挂到子类的this上去,这样既能避免实例之间共享一个原型实例,又能向父类构造方法传参</span></span></p> <pre><code class="language-javascript"> function Parent(name) { this.name = [name] } Parent.prototype.getName = function () { return this.name } function Child() { Parent.call(this, 'Demi') // 执行父类构造方法并绑定子类的this, 使得父类中的属性能够赋到子类的this上 } //测试 const child1 = new Child() const child2 = new Child() child1.name[0] = 'foo' console.log(child1.name) // ['foo'] console.log(child2.name) // ['Demi'] child2.getName() // 报错,找不到getName(), 构造函数继承的方式继承不到父类原型上的属性和方法</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:找不到父类原型上的属性和方法</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>组合式继承</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">既然原型链继承和构造函数继承各有互补的优缺点, 那么我们为什么不组合起来使用呢, 所以就有了综合二者的组合式继承</span></span></p> <pre><code class="language-javascript"> function Parent(name) { this.name = [name] } Parent.prototype.getName = function () { return this.name } function Child() { // 构造函数继承 Parent.call(this, 'Demi') } //原型链继承 Child.prototype = new Parent() Child.prototype.constructor = Child //测试 const child1 = new Child() const child2 = new Child() child1.name[0] = 'foo' console.log(child1.name) // ['foo'] console.log(child2.name) // ['Demi'] child2.getName() // ['Demi']</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">找每次创建子类实例都执行了两次构造函数(Parent.call()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">和new Parent()),虽然这并不影响对父类的继承,但子类创建实例时,原型中会存在两份相同的属性和方法,这并不优雅</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>寄生式继承</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">为了解决构造函数被执行两次的问题, 我们将指向父类实例</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">改为指向父类原型, 减去一次构造函数的执行</span></span></p> <pre><code class="language-javascript"> function Parent(name) { this.name = [name] } Parent.prototype.getName = function () { return this.name } function Child() { // 构造函数继承 Parent.call(this, 'Demi') } //原型链继承 // Child.prototype = new Parent() Child.prototype = Parent.prototype //将`指向父类实例`改为`指向父类原型` Child.prototype.constructor = Child //测试 const child1 = new Child() const child2 = new Child() child1.name[0] = 'foo' console.log(child1.name) // ['foo'] console.log(child2.name) // ['Demi'] child2.getName() // ['Demi']</code></pre> <p style="margin-left:0;text-align:left;"></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、ES6继承</strong></strong></span></h4> <pre><code class="language-javascript"> class Parent { constructor(name) { this.name = name; } getName() {} } class Child extends Parent { constructor(name, age) { super(name); this.age = age; } getAge() {} } let person = new Child('Demi', 24) console.log(person) // {name: 'Demi', age: 24}</code></pre> <p style="text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、this对象的理解?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">每一个方法或函数都会有一个this对象,this对象是方法(或函数)在执行时的那个环境,也可以说是这个函数在那个作用域下运行的。说的更通俗一点:this就相当于咱们平时说话时候说的“我”,“我家”的概念。就是说当一个方法在运行的时候,它是属于谁的。它在运行的时候它的家是谁家。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象</span></span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>在实际开发中,</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>this 的指向可以通过四种调用模式来判断。</strong></span></span></strong></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,this 指向这个新创建的对象</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.第四种是 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.普通函数在执行的时候才绑定this</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数在定义的时候就确定this,它的this指向在定义的时候继承自外层第一个普通函数的this。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>13、执行上下文和执行栈</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>执行上下文</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念, JavaScript 中运行任何的代码都是在执行上下文中运行。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>执行上下文分类</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">全局执行上下文:这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2. 将this指针指向这个全局对象。一个程序中只能存在一个全局执行上下</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数执行上下文:每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤,具体过程将在本文后面讨论。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>执行栈</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">执行栈,在其他编程语言中也被叫做调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文</span></span></p> <p></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>14、new操作符干了什么?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建一个新的对象obj</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将对象与</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">构造</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数通过原型链连接起来</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将构</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">造</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数中的this绑定到新建的对象obj上</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">构造</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数返回类型作判断,如果构造方法返回了一个对象,那么返回该对象,否则返回第一步创建的新对象</span></span></p> <pre><code class="language-javascript"> function myNew(Func, ...args) { // 1.创建一个新对象 const obj = {} // 2.新对象原型指向构造函数原型对象 obj.__proto__ = Func.prototype // 3.将构建函数的this指向新对象 let result = Func.apply(obj, args) // 4.根据返回值判断 return result instanceof object ? result : obj } //测试 function Person(name, age) { this.name = name; this.age = age; } Person.prototype.say = function () { console.log(this.name) } let p = myNew(Person, "Demi", 123) console.log(p) // Person {name: "Demi", age: 123}</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>15、事件模型</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件是用户操作网页时发生的交互动作或者网页本身的一些操作,现代浏览器一共有三种事件模型。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>事件流三个阶段</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件捕获阶段(capture phase)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">目标阶段(target phase)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件冒泡阶段(bubbling phase)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>事件模型</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原始事件模型(DOM0级)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE事件模型(基本不用)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">标准事件模型(DOM2级)</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.第一种事件模型是最早的 DOM0 级模型,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js 属性来指定监听函数。这种方式是所有浏览器都兼容的。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.第二种事件模型是 IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段,和事件冒泡阶段。事件处理阶段会首先执行目标元素绑定的监听事件。然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到 document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。这种模型通过 attachEvent 来添加监听函数,可以添加多个监听函数,会按顺序依次执行。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.第三种是 DOM2 级事件模型,在该事件模型中,一次事件共有三个过程,第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE 事件模型的两个阶段相同。这种事件模型,事件绑定的函数是 addEventListener,其中第三个参数可以指定事件是否在捕获阶段执行。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>16、typeof和instanceof的区别</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">typeof 操作符返回一个字符串,表示未经计算的操作数的类型</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <pre><code class="language-javascript"> typeof 1 // 'number' typeof '1' // 'string' typeof undefined // 'undefined' typeof true // 'boolean' typeof Symbol() // 'symbol' typeof null // 'object' typeof [] // 'object' typeof {} // 'object ' typeof console // 'object' typeof console.log // 'function'</code></pre> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上</span></span></span></p> <pre><code class="language-javascript"> //定义构建函数 let Car = function () {} let benz = new Car() benz instanceof Car // true let car = new String('xxx') car instanceof String // true let str = 'xxx' str instanceof String // false</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>typeof与instanceof都是判断数据类型的方法,区别如下:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>17、什么是事件代理?应用场景</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件代理(Event Delegation),又称之为事件委托。“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>应用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件,如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的。这时候就可以事件委托,把点击事件绑定在父级元素ul</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">上面,然后执行事件的时候再去匹配目标元素</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">li</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果用户能够随时动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>18、ajax原理是什么?如何实现?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>AJAX</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>全称(Async Javascript and XML)</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Ajax的原理</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面</span></span></p> <pre><code class="language-javascript"> const request = new XMLHttpRequest() request.onreadystatechange = function (e) { if (request.readyState === 4) { //整个请求过程完毕 if (request.status >= 200 && request.status <= 300) { console.log(request.responseText) // 服务端返回的结果 } else if (request.status >= 400) { console.log("错误信息:" + request.status) } } } request.open('POST', 'http://xxx') request.send()</code></pre> <p></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>19、XMLHttpRequest.readyState状态码</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>状态0(请求未初始化):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(XMLHttpRequest)对象已经创建或已被abort()方法重置,但还没有调用open()方法</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>状态1(载入服务器连接已建立):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">已经调用open() 方法,但是send()方法未调用,尚未发送请求</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>状态2(载入完成,请求已接收):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">send()方法已调用,HTTP请求已发送到web服务器,请求已经发送完成,未接收到响应</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>状态3(交互,请求处理中):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">所有响应头部都已经接收到。响应体开始接收但未完成,即可以接收到部分响应数据</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>状态4(请求完成,且响应已就绪):</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">已经接收到了全部数据,并且连接已经关闭</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>20、bind、call、applay的区别?如何实现一个call</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向</span></span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>applay</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>call</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">call方法的第一个参数也是this的指向,后面传入的是一个参数列表</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">改变this指向后原函数会立即执行,且此方法只是临时改变this指向一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">次</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>bind</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">改变this指向后</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不会立即执行,而是返回一个永久改变this指向的函数</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>实现call</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <pre><code class="language-javascript"> Function.prototype.myCall = function (obj, ...args) { const fn = Symbol('fn') // 声明一个独有的Symbol属性, 防止fn覆盖已有属性 obj = obj || window // 若没有传入this, 默认绑定window对象 obj[fn] = this // this指向调用call的对象,即我们要改变this指向的函数 const result = obj[fn](...args) // 执行当前函数 delete obj[fn] // 删除我们声明的fn属性 return result // 返回函数执行结果 } //测试 let obj = { name: 'Demi' } // 全局函数 function getName(arg) { console.log(this.name) console.log(arg) } // 将全局函数this指向obj getName.myCall(obj, 'arg') // name arg</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>21、说说你对事件循环的理解?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,而实现单线程非阻塞的方法就是事件循环</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在JavaScript中,所有的任务都可以分为</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同步任务和异步任务。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同步任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">也就是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">立即执行的任务,同步任务一般会直接进入到主线程中执行</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">异步任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">异步执行的任务,比如ajax网络请求,setTimeout定时函数等</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在执行同步</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的时候,如果遇到了异步事件,js 引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当异步事件执行完毕后,再将异步事件对应的回调加入到与当前执行栈中不同的另一个任务队列中等待执行。任务队列可以分为宏任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">队列</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">和微任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">队</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">队</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行。当微任务对列中的任务都执行完成后再去判断宏任务对列中的任务。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">微任务包括了 promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。</span></span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">宏任务包括了 script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲染等。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>22、DOM的常见操作</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">任何 HTML或XML文档都可以用 DOM表示为一个由节点构成的层级结构</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>创建节点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">createElement</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建新元素,接受一个参数,即要创建元素的标签名</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">createTextNode</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建一个文本节点</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">createDocumentFragment</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用来创建一个文档碎片,它表示一种轻量级的文档,主要是用来存储临时节点,然后把文档碎片的内容一次性添加到DOM中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">createAttribute</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建属性节点,可以是自定义属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>查询节点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">querySelector</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">传入任何有效的css 选择器,即可选中单个 DOM元素(首个)querySelectorAll</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回一个包含节点子树内所有与之相匹配的Element节点列表,如果没有相匹配的,则返回一个空节点列表</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">getElementById('id')</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回拥有指定id的对象的引用getElementsByClassName('class')</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回拥有指定的对象集合getElementsByTagName('标签名')</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回拥有指定标签名的对象集合getElementsByName('name属性值')</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 返回拥有指定名称的对象结合</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>更新节点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">innerHTML</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">innerText</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自动对字符串进行HTML编码,保证无法设置任何HTML标签</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">, </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不返回隐藏元素的文本</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">textContent</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自动对字符串进行HTML编码,保证无法设置任何HTML标签</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">, </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回所有文本</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">s</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">tyle</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DOM节点的style属性对应所有的CSS,可以直接获取或设置。遇到需要转化为驼峰命名</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>添加节点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">innerHTML</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">appendChild</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把一个子节点添加到父节点的最后一个子节点</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">insertBefore</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把子节点插入到指定的位置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子节点会插入到referenceElement之前</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">setAttribute</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在指定元素中添加一个属性节点,如果元素中已有该属性改变属性值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>删除节点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">removeChild</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把自己删掉</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>23、说说你对BOM的理解?常见的BOM对象有哪些?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">BOM (Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率</span></span></span></p> <p> <a href="http://img.e-com-net.com/image/info8/c50a04edd95e4f6f8901340305675030.jpg" target="_blank"><img alt="前端高频面试题_第1张图片" height="140" src="http://img.e-com-net.com/image/info8/c50a04edd95e4f6f8901340305675030.jpg" width="620" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Window</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">open:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">既可以导航到一个特定的url,也可以打开一个新的浏览器窗口</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">close:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">仅用于通过</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">关闭</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> window.open() 打开的窗口</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Window.location</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">location</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对象主要用来获取</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">url</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">信息</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">hash:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">u</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">rl</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中#后面的字符,没有则返回空串</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">host:域名</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">和端口号</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">hostname:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">域名,不带端口号</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">href:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">完整url</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">pathname:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">服务器下面的文件路径</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">port:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">url的端口号,没有则为空</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">protocol:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用的协议</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">search:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">url的查询字符串,通常为?后面的内容</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Window.navigator</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">navigator 对象主要用来获取浏览器的属性,区分浏览器类型</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/39d26eb14f5b42258fa1cbbf3cea1540.jpg" target="_blank"><img alt="前端高频面试题_第2张图片" height="675" src="http://img.e-com-net.com/image/info8/39d26eb14f5b42258fa1cbbf3cea1540.jpg" width="650" style="border:1px solid black;"></a></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/f4fdddafb0cd41b58d96b823e9104caf.jpg" target="_blank"><img alt="前端高频面试题_第3张图片" height="664" src="http://img.e-com-net.com/image/info8/f4fdddafb0cd41b58d96b823e9104caf.jpg" width="650" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Window.screen</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">保存的纯粹是客户端能力信息,也就是浏览器窗口外面的客户端显示器的信息,比如像素宽度和像素高度</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/f9058a110ca84fa0acff54601cfd322b.jpg" target="_blank"><img alt="前端高频面试题_第4张图片" height="264" src="http://img.e-com-net.com/image/info8/f9058a110ca84fa0acff54601cfd322b.jpg" width="648" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Window.history</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">history对象主要用来操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定URL跳转</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">history.go()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">接收一个整数数字或者字符串参数:向最近的一个记录中包含指定字符串的页面跳转</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">history.forward():向前跳转一个页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">history.back():向后跳转一个页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">history.length:获取历史记录数</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>24、JavaScript中内存泄漏的几种情况</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>常见的内存泄漏</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1. setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2. 闭包(dom元素删除, 闭包中还在引用)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3. 控制台日志</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4. 循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.意外的全局变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>解决内存泄漏</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.使用严格模式,可以避免意外的全局变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.清理dom元素, dom = null</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.setTimeout第一个参数为函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>25、JavaScript本地存储的几种方式?区别和应用场景?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>sessionStorage、localStorage和cookie的区别</strong></span></span></strong></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.相同点是都是保存在浏览器端、且同源的</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.存储大小限制也不同,cookie数据不能超过4K,同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.sessionStorage和localStorage支持事件通知机制,可以将数据更新的通知发送给监听者</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.sessionStorage和localStorage的api接口使用更方便</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>应用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">标记用户与跟踪用户行为的情况,推荐使用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">cookie</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适合长期保存在本地的数据(令牌),推荐使用localStorage</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">敏感账号一次性登录,推荐使用sessionStorage</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>26、Cookie的优缺点?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优点:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.极高的扩展性和可用性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.通过编程方式,控制保存在cookie中的session对象的大小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.通过加密和SSL(安全传输技术),减少cookie被破解的可能性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.只在cookie中存放不敏感数据,被盗也不会有重大的损失</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.控制cookie的生命周期,可用让其永远有效,偷盗者就有可能拿到一个过期的cookie</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>缺点:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.cookie数量和长度的限制,每个最多只能有20条的cookie,长度不能超过4kb,超过就会被截取</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.安全性问题,被人拦截,就可以得到cookie的所有信息,只要原样转发就可以达到目的</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>27、函数式编程的理解?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数式编程中的函数这个术语不是指计算机中的函数,而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>28、JavaScript数字精度丢失问题</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当计算机计算 0.1+0.2 的时候,实际上计算的是这两个数字在计算机里所存储的二进制,0.1 和 0.2 在转换为二进制表示的时候会出现位数无限循环的情况。js 中是以 64 位双精度格式来存储数字的,只有 53 位的有效数字,超过这个长度的位数会被截取掉这样就造成了精度丢失的问题。这是第一个会造成精度丢失的地方。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在对两个以 64 位双精度格式的数据进行计算的时候,首先会进行对阶的处理,对阶指的是将阶码对齐,也就是将小数点的位置对齐后,再进行计算,一般是小阶向大阶对齐,因此小阶的数在对齐的过程中,有效数字会向右移动,移动后超过有效位数的位会被截取掉,这是第二个可能会出现精度丢失的地方。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当两个数据阶码对齐后,进行相加运算后,得到的结果可能会超过 53 位有效数字,因此超过的位数也会被截取掉,这是可能发生精度丢失的第三个地方。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>解决</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于这样的情况,我们可以将其转换为整数后再进行运算,运算后再转换为对应的小数,以这种方式来解决这个问题。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.使用bigInt()进行计算</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>29、面向过程和面向对象的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>面向过程 :</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">分析出解决问题所需要的步骤,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">强调的是解决问题的步骤,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/cf295a537fce4ae691b866e3ab0d6cb8.jpg" target="_blank"><img alt="前端高频面试题_第5张图片" height="306" src="http://img.e-com-net.com/image/info8/cf295a537fce4ae691b866e3ab0d6cb8.jpg" width="477" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>面向对象</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/48866fbada974e0ba713c26dfa492aba.jpg" target="_blank"><img alt="前端高频面试题_第6张图片" height="244" src="http://img.e-com-net.com/image/info8/48866fbada974e0ba713c26dfa492aba.jpg" width="488" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优缺点比较:</strong></span></span></strong></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向过程优点:</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果,具体步骤清楚,便于节点分析。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.效率高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向过程缺点:</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.需要深入的思考,耗费精力,代码重用性低,扩展能力差,后期维护难度比较大。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向对象优点:</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.结构清晰,程序是模块化和结构化,更加符合人类的思维方式;</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.易扩展,代码重用率高,可继承,可覆盖,可以设计出低耦合的系统;</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.易维护,系统低耦合的特点有利于减少程序的后期维护工作量。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向对象</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.开销大,当要修改对象内部时,对象的属性不允许外部直接存取,所以要增 加许多没有其他意义、只负责读或写的行为。这会为编程工作增加负担,增加运行开销,并且使程序显得臃肿。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.性能低,由于面向更高的逻辑抽象层,使得面向对象在实现的时候,不得不做出性能上面的牺牲,计算时间和空间存储大小都开销很大。</span></span></p> <p><a href="http://img.e-com-net.com/image/info8/941ed16cd0ff499482a6cb72b70f95ae.jpg" target="_blank"><img alt="前端高频面试题_第7张图片" height="176" src="http://img.e-com-net.com/image/info8/941ed16cd0ff499482a6cb72b70f95ae.jpg" width="519" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>得出结论</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向过程:用函数来定义解决问题的步骤</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向对象:用类和对象的方法来定义解决问题的行为或者说功能</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">面向过程性能比面向对象高。因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>30、如何实现函数缓存</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数缓存,就是将函数运算过的结果进行缓存</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">本质上就是用空间(缓存存储)换时间(计算过程)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实现函数缓存主要依靠闭包、柯里化、高阶函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>31、什么是防抖和节流?有什么区别?如何实现?</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。</span></span></p> <pre><code class="language-javascript"> function debounce(func, wait) { let timeout = null return function () { let context = this // 保存this指向 let args = arguments // 拿到event对象 if (timeout) clearTimeout(timeout) timeout = setTimeout(() => { func.apply(context, args) }, wait) } }</code></pre> <p style="margin-left:.0001pt;text-align:justify;"><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。</span></span></p> <pre><code class="language-javascript"> function throttle(func, wait) { let timeout = null return function () { let context = this let args = arguments if (!timeout) { timeout = setTimeout(() => { timeout = null func.apply(context, args) }, wait) } } }</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>32、说说var、let、const之间的区别</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>变量提升</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">var</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>暂时性死区</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">var不存在暂时性死区</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>块级作用域</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">var</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不存在块级作用域</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">let和const存在块级作用域</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>重复声明</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">var允许重复声明变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">let和const在同一作用域不允许重复声明变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>修改声明的变量</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">var和let可以</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">const声明一个只读的常量。一旦声明,常量的值就不能改变</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#2c3e50;"><strong>使用</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能用const</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的情况尽量使用const,其他情况下大多数使用let,避免使用var</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>33、Set和Map两种数据结构</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Set是一种叫做集合的数据结构,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">集合</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是由一堆无序的、相关联的,且不重复的内存结构【数学中称为元素】组成的组合</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Map是一种叫做字典的数据结构</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,字典</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是一些元素的集合。每个元素有一个称作key 的域,不同元素的key 各不相同</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Set是es6新增的数据结构,类似于数组,但是成员的值都是唯一的,没有重复的值,我们一般称为集合</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>new Set()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Set本身是一个构造函数,用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">new Set()来</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">生成 Set 数据结构</span></span></p> <pre><code class="language-javascript">const s = new Set();</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>add()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">添加某个值,返回 Set 结构本身</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当添加实例中已经存在的元素,set不会进行处理添加</span></span></p> <pre><code class="language-javascript">s.add(1).add(2).add(2); // 2只被添加了一次</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>delete()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">删除某个值,返回一个布尔值,表示删除是否成功</span></span></p> <pre><code class="language-javascript">s.delete(1)</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>has()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">返回一个布尔值,判断该值是否为Set的成员</span></span></p> <pre><code class="language-javascript">s.has(2)</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>clear()</strong></span></span></strong> </p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">清除所有成员,没有返回值</span></span></p> <pre><code class="language-javascript">s.clear()</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Map类型是键值对的有序列表,而键和值都可以是任意类型</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>new Map()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">m</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ap本身是一个构造函数,用来生成 Map 数据结构</span></span></p> <pre><code class="language-javascript"> const map = new Map()</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>size</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">size属性返回 Map 结构的成员总数。</span></span></p> <pre><code class="language-javascript"> const map = new Map() map.set('foo', true) map.set('bar', false) map.size // 2</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>set</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置键名key对应的键值为value,然后返回整个 Map 结构</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果key已经有值,则键值会被更新,否则就新生成该键</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同时返回的是当前Map对象,可采用链式写法</span></span></p> <pre><code class="language-javascript"> const map = new Map() map.set('edition', 6) // 键是字符串 map.set(262, 'standard') // 键是数值 map.set(undefined, 'test') // 键是undefined map.set(1, 'a').set(2, 'b').set(3, 'c') // 链是操作</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>get</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">get方法读取key对应的键值,如果找不到key,返回</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">undefined</span></span></p> <pre><code class="language-javascript"> const map = new Map(); const hello = function () { console.log('hello'); }; map.set(hello, 'Hello ES6!') //键是函数 map.get(hel1o) // Hello ES6!</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>delete</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">delete方法删除某个键,返回true。如果删除失败,返回false</span></span></p> <pre><code class="language-javascript"> const map = new Map(); map.set(undefined, 'nah'); map.has(undefined) // true map.delete(undefined) map.has(undefined) // false</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>clear()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">清除所有成员,没有返回值</span></span></p> <pre><code class="language-javascript"> let map = new Map(); map.set('foo', true); map.set('bar', false); map.size // 2 map.clear() map.size // 0</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>34、null和undefined的区别</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">undefined 在 js 中不是一个保留字,这意味着我们可以使用 undefined 来作为一个变量名,这样的做法是非常危险的,它会影响我们对 undefined 值的判断。但是我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当我们对两种类型使用 typeof 进行判断的时候,Null 类型化会返回 “object”,这是一个历史遗留的问题。当我们使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="margin-left:.0001pt;text-align:left;"><strong><strong>35、说几条写 JavaScript 的基本规范?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)一个函数作用域中所有的变量声明应该尽量提到函数首部</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)代码中出现地址、时间等字符串时需要使用常量代替。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)在进行比较的时候吧,尽量使用'===', '!=='代替'==', '!='。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)不要在内置对象的原型上添加方法,如 Array, Date。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(5)switch 语句必须带有 default 分支。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(6)for 循环必须使用大括号。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(7)if 语句必须使用大括号。</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(8)不要在同一行声明多个变量;</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(9)使用对象字面量替代new O</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">bject这种形式</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(10)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数不应该有时候有返回值,有时候没有返回值</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(11)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">命名规则中构造器函数首字母大写,如function Person(){}</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(12)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">写注释</span></span></p> <p style="text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>36、Es6代码转成es5的实现思路</strong></strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">说到 ES6 代码转成 ES5 代码,我们肯定会想到 Babel。那么 Babel 是如何把 ES6 转成 ES5 呢,其大致分为三步:</span></span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将代码字符串解析成抽象语法树,即所谓的 AST</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对 AST 进行处理,在这个阶段可以对 ES6 代码进行相应转换,即转成 ES5 代码</span></span></p> <p style="margin-left:.0001pt;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据处理后的 AST 再生成代码字符串</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>37、异步的发展历程?</strong></strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>1. 回调函数(callback)</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:回调地狱,不能用 try catch 捕获错误,不能 return</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺乏顺序性</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">回调地狱导致的调试困难,和大脑的思维方式不符</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身,即(控制反转)嵌套函数过多的多话,很难处理错误</span></span></span></p> <pre><code class="language-javascript"> ajax('xxx1', () => { // callback函数体 ajax('xxx2', () => { // callback 函数体 ajax('xxx3', () => { // callback函数体 }) }) })</code></pre> <p><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>2.</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise就是为了解决callback的问题而产生的。Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优点:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决了回调地狱的问题</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:无法取消 Promise ,错误需要通过回调函数来捕获</span></span></span></p> <pre><code class="language-javascript"> let promise = new Promise((resolve, reject) => { //在这里执行异步操作 if ( /*异步操作成功*/ ) { resolve(success) } else { reject(error) } })</code></pre> <p><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>3.Generator</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">特点:可以控制函数的执行,可以配合 co 函数库使用</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优点:函数体内外的数据交换、错误处理机制</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:流程管理不方便</span></span></span></p> <pre><code class="language-javascript"> function* fetch() { yield ajax('xxx1', () => {}) yield ajax('xxx2', () => {}) yield ajax('xxx3', () => {}) } let it = fetch() let result1 = it.next() let result2 = it.next() let result3 = it.next()</code></pre> <p><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>4.async/await</strong></span></span></strong></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">async、await 是异步的终极解决方案</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优点是:代码清晰,不用像Promise写一大堆 then 链,处理了回调地狱的问题</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。</span></span></span></p> <pre><code class="language-javascript"> async function test() { //以下代码没有依赖性的话,完全可以使用Promise.all的方式 //如果有依赖性的话,其实就是解决回调地狱的例子了 await fetch('XXX1') await fetch('XXX2 ') await fetch('XXX3') }</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>38、promise介绍</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>promise三种状态</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">pending:进行中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">fulfilled :已成功</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">rejected 已失败</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>promise缺点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.无法取消Promise,一旦新建它就会立即执行,无法中途取消</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果不设置回调函数(没有捕获错误),Promise内部抛出的错误,不会反应到外部</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>p</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>romise基本用法</strong></span></span></strong></p> <pre><code class="language-javascript"> let promise = new Promise((resolve, reject) => { //在这里执行异步操作 if ( /*异步操作成功*/ ) { resolve(success) } else { reject(error) } })</code></pre> <p><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.Promise接收一个函数作为参数,函数里有resolve和reject两个参数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.resolve方法的作用是将Promise的pending状态变为fulfilled,在异步操作成功之后调用,可以将异步返回的结果作为参数传递出去。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.reject方法的作用是将Promise的pending状态变为rejected,在异步操作失败之后调用,可以将异步返回的结果作为参数传递出去。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">他们之间只能有一个被执行,不会同时被执行,因为Promise只能保持一种状态。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise.prototype.then()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise实例确定后,可以用then方法分别指定fulfilled状态和rejected状态的回调函数。它的基本用法如下:</span></span></p> <pre><code class="language-javascript"> promise.then((success) => { //异步操作成功在这里执行 //对应于上面的resolve(success)方法 }, (error) => { //异步操作先败在这里执行 //对应于上面的reject(error)方法 }) //还可以写成这样(推荐使用这种写法) promise.then((success) => { //异步操作成功在这里执行 //对应于上面的resolve (success)方法 }).catch((error) => { //异步操作先败在这里执行 //对应于上面的reject(error)方法 })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise.prototype.catch()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">catch方法是.then(null,onrejected)的别名,用于指定发生错误时的回调函数。作用和then中的onrejected一样,不过它还可以捕获onfulfilled抛出的错,这是onrejected所无法做到的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise错误具有"冒泡"的性质,如果不被捕获会一直往外抛,直到被捕获为止;而无法捕获在他们后面的Promise抛出的错。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise.prototype.finally()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。finally方法不接受任何参数,故可知它跟Promise的状态无关,不依赖于Promise的执行结果</span></span></p> <pre><code class="language-javascript"> createPromise('p1', 0).then((success) => { console.log(success) }).catch((error) => { console.log(error) // p1 fail }).finally(() => { console.log('finally') // finally }) createPromise('p1', 1).then((success) => { console.log(success) // p1 ok }).catch((error) => { console.log(error) }).finally(() => { console.log('finally') // finally })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise.all()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise.all方法接受一个数组作为参数,但每个参数必须是一个Promise实例。Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作都执行完毕后才执行回调,只要其中一个异步操作返回的状态为rejected那么Promise.all()返回的Promise即为rejected状态,此时第一个被reject的实例的返回值,会传递给Promise.all的回调函数</span></span></p> <pre><code class="language-javascript"> function createPromise(p, arg) { return new Promise((resolve, reject) => { setTimeout(() => { if (arg === 0) { reject(p + 'fail') } else { resolve(p + 'ok') } }, 0); }) } // test: 两个Promise都成功 Promise.all([createPromise('p1', 1), createPromise('p2', 1)]), then((success) => { console.log(success) // ['p1 ok', 'p2 ok'] }).catch((error) => { console.log(error) }) // test: 其中一个Promise先败 Promise.all([createPromise('p1', 0), createPromise('p2', 1)]), then((success) => { console.log(success) }).catch((error) => { console.log(error) // p1 fail }) // test: 两个Promise都失败 Promise.all([createPromise('p1', 0), createPromise('p2', 0)]) .then((success) => { console.log(success) }).catch((error) => { console.log(error) // p1 fail 只打印第一个失败的异步操作信息 })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Promise.race()</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise的race方法和all方法类似,都提供了并行执行异步操作的能力。顾名思义,race就是赛跑的意思,意思就是说Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态,以下就是race的执行过程</span></span></p> <pre><code class="language-javascript"> let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('failed') }, 500) }) Promise.race([p1, p2]).then((success) => { console.log(success) }).catch((error) => { console.log(error) // failed })</code></pre> <p></p> <h4><span style="background-color:#ffffff;"><strong><strong><strong>39、promise.all()和promise.race的区别?</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">promise.all 是数组里面所有的 promise对象执行结束之后会返回一个存储所有 promise对象的结果 </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">promise.race 顾名思义 race就是比赛的意思  只会返回一个执行速度最快的那个promise对象返回的结果 </span></span></p> <pre><code class="language-javascript"> let runA = new Promise((resolve, reject) => { setTimeout(() => { console.log('runA') resolve('a') }, 3000) }) let runB = new Promise((resolve, reject) => { setTimeout(() => { console.log('runB') resolve('b'); }, 4000) }) // Promise.all([runA, runB]).then((res) => { console.log(res) }); //输出了["a", "b"],打印了runA和runB // Promise.race([runA, runB]).then((res) => { console.log(res) }); //输出了a,打印了runA和runB // Promise.race()其他的异步函数照样还是会执行的,只是不会再执行resolve和reject,也不会返回结果了,但函数还是会执行的 //上面代码还是会打印console.log('runB') 只会不会执行下面的resolve('b') </code></pre> <p></p> <h4 style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>40、promise.all中,其中一个promise出错,如何确保执行到最后?</strong></span></span></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在promise.all队列中,使用map过滤每一个promise任务,其中任意一个报错后,return一个返回值,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">p.catch方法返回值会被promise.reslove()包裹,这样传进promise.all的数据全都是resolved状态的,确保promise能正常执行走到.then中</span></span></p> <pre><code class="language-javascript"> let p1 = new Promise((resolve, reject) => { resolve({ code: 200, list: [] }); }); let p2 = new Promise((resolve, reject) => { resoLve({ code: 200, list: [] }); }); let p3 = new Promise((resolve, reject) => { reject({ code: 500, msg: "服务异常" }); }); Promise.all([p1, p2, p3].map(p => p.catch(e => e))) .then(res => { console.log(res); /* 打印结果: {code: 200, list: Array(0)} {code: 200, list: Array(0)} {code: 500, msg:”服务异常”} */ }).catch(err => { console.log(err); })</code></pre> <p></p> <h4><span style="background-color:#ffffff;"><strong><strong><strong>41、普通函数和箭头函数的区别?</strong></strong></strong></span></h4> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">语法更加简洁、清晰</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数没有 prototype (原型),所以箭头函数本身没有this</span></span></span></p> <pre><code class="language-javascript"> //箭头函教 let a = () => {}; console.log(a.prototype); // undefined //普通函数 function a() {}; console.log(a.prototype); // {constructor:f}</code></pre> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数不会创建自己的this</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数没有自己的this,箭头函数的this指向在定义(注意:是定义时,不是调用时)的时候继承自外层第一个普通函数的this。所以,箭头函数中 this 的指向在它被定义的时候就已经确定了,之后永远不会改变。</span></span></span></p> <pre><code class="language-javascript"> let obj = { a: 10, b: () => { console.log(this.a); // undefined console.log(this); // Window {postMessage: f, blur: f, focus: f, close: f, frames: Window, ...} }, c: function () { console.log(this.a); // 10 console.log(this); // {a: 10, b: f, c: f} } } obj.b(); obj.c();</code></pre> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">call | apply | bind 无法改变箭头函数中this的指向</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">call | apply | bind方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向。</span></span></span></p> <pre><code class="language-javascript"> var id = 10; let fun = () => { console.log(this.id) }; fun(); // 10 fun.call({ id: 20 }); // 10 fun.apply({ id: 20 }); // 10 fun.bind({ id: 20 })(); // 10</code></pre> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数不能作为构造函数使用</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们先了解一下构造函数的new都做了些什么?简单来说,分为四步: ① JS内部首先会先生成一个对象; ② 再把函数中的this指向该对象; ③ 然后执行构造函数中的语句; ④ 最终返回该对象实例。</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!</span></span></span></p> <pre><code class="language-javascript"> let Fun = (name, age) => { this.name = name; this.age = age; }; //报错 let p = new Fun('dingFY', 24);</code></pre> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数不绑定arguments,取而代之用rest参数...代替arguments对象,来访问箭头函数的参数列表</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。</span></span></span></p> <pre><code class="language-javascript"> // 普通函数 function A(a) { console.log(arguments); } A(1, 2, 3, 4, 5, 8); // [1, 2, 3, 4, 5, 8, callee: f, Symbol (Symbol. iterator): f] // 箭头函数 let B = (b) => { console.log(arguments); } B(2, 92, 32, 32); // Uncaught ReferenceError: arguments is not def ined // rest参效... let C = (...c) => { console.log(c); } C(3, 82, 32, 11323); // [3, 82, 32, 11323]</code></pre> <p></p> <h4><span style="background-color:#ffffff;"><strong><strong><strong>42、JavaScript中的装箱和拆箱操作</strong></strong></strong></span></h4> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">装箱操作:</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把基本数据类型转换为对应的引用类型的操作</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">拆箱操作: 把引用类型转换为基本数据类型的操</span></span></span></p> <p style="margin-left:0pt;text-align:left;"></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">基本类型:Number,String,Boolean,Null,Undefined,Symbol、BigInt</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">访问:基本数据类型的值是按值访问的。</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">存储:基本类型的变量是存放在栈内存(Stack)里的。</span></span></span></p> <p style="margin-left:0pt;text-align:left;"></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">引用类型:Object</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">访问:引用类型的值是按引用访问的。</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">存储:引用类型的值是保存在堆内存(Heap)中的对象(Object)</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">js中的三个基本包装类型:Number、String、Boolean</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">typeof: 经常用来检测一个变量是不是最基本的数据类型</span></span></span></p> <p style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">instanceof: 用来判断某个构造函数的 prototype 属性所指向的对象是否存在于另外一个要检测对象的原型链上。简单说就是判断一个引用类型的变量具体是不是某种类型的对象</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>装箱</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">每当读取一个基本类型的时候,后台就会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法来操作这些数据。</span></span></p> <pre><code class="language-javascript"> var str = "hello world"; var strRes = str.split(" "); console.log(strRes) //["hello", "world"]</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如上面代码所示,变量str是一个基本类型值,不是一个对象,就不存在方法,但上面代码却显示可以正常调用方法。实际上这一切都是js内部做了以下处理</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(装箱操作),</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使得它能够调用方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建String类型的一个实例;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在实例上调用指定的方法;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">销毁这个实例;</span></span></p> <pre><code class="language-javascript"> var str = "hello world"; var strRes = str.split(" "); str = null</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>拆箱</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">拆箱操作中主要有两个方法,valueOf()方法和toString()方法。这两个方法主要用来检测你返回的是不是一个基本类型的值。一般是先用valueOf()来检测,如果返回的不是一个基本类型的值,是对象自身,则会继续用toString()来检测,如果检测结果不是一个基本类型的值,则会报错(Uncaught SyntaxError: Invalid or unexpected token)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>valueOf</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.valueOf() 方法返回指定对象的原始值。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.JavaScript调用valueOf方法将对象转换为原始值。你很少需要自己调用valueOf方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.默认情况下,valueOf方法由Object后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf将返回对象本身。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>toSting</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.toString() 方法返回一个表示该对象的字符串。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中 type 是对象的类型。</span></span></p> <pre><code class="language-javascript"> [] + [] // "" {} + {} // "[object Object][object Object]" [] + {} // "[object Object]"</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.[]+[],[]自身是一个空数组,即是一个对象,[]会先被valueOf()检测返回自身,还是[],然后使用toString()检测返回空字符"",实际最终是""+"",所以最终结果还是一个""</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.{}+{},在js中{}可以表示一个代码块,也可以表示一个对象。在此处作为一个对象来运算,({}).valueOf()检测结果为自身,继续检测,({}).toString()检测结果为"[object Object]",所以{}+{}相当于"[object Object]"+"[object Object]",故结果为"[object Object][object Object]"</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.[]+{},从上面分析可以知道,这个相当于""+"[object Object]",所以结果为"[object Object]"</span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>43、Object.defineProperty()</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>语法</strong></span></span></strong></p> <pre><code class="language-javascript">Object.defineProperty(obj, prop, descriptor)</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>参数</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">obj:必需,目标对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">prop:必需,需定义或修改的属性的名字</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">descriptor:必需,将被定义或修改的属性的描述符</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,是一个对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>d</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>escriptor</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>参数解析</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符和存取描述符</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据描述:当修改或定义对象的某个属性的时候,给这个属性添加一些特性,数据描述中的属性都是可选的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">存取描述:当使用存取器描述属性的特性的时候,允许设置以下特性属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>数据描述:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">value:属性对应的值,可以使任意类型的值,默认为undefined</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">writable:属性的值是否可以被重写。设置为true可以被重写;设置为false,不能被重写。默认为false</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">enumerable:此属性是否可以被枚举(使用for...in或Object.keys())。设置为true可以被枚举;设置为false,不能被枚举。默认为false</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">configurable:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。这个属性起到两个作用:1、目标属性是否可以使用delete删除  2、目标属性是否可以再次设置特性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>存取描述:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>44、await后面跟的对象</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">await 后面可以跟任何js表达式都不会报错,但是,只有当后面跟的是promise对象时,才会解决异步问题,实现同步</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>后面跟普通js表达式</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于非promise对象,比如箭头函数,同步表达式等等,会立即执行,而不是等待其执行结果</span></span></p> <pre><code class="language-javascript"> function waitme() { setTimeout(() => { console.log(111111); }, 3000) } async function go() { await waitme(); console.log(222222); } go(); // 输出结果为22222 111111</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>后面跟promise对象</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于promise对象,await会阻塞函数执行,等待promise的resolve返回值,作为await的结果,然后再执行下下一个表达式</span></span></p> <pre><code class="language-javascript"> function waitme() { return new Promise((resolve, reject) => { setTimeout(() => { console.log(111111); resolve() }, 3000) }) } async function go() { await waitme(); console.log(222222); } go() //输出结果为111111 22222</code></pre> <p></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>45、异步和同步的区别? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。</span></span><br><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>同步任务:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">指的是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>异步任务:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">指的是不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>46、图片懒加载实现原理? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">先将</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">img标签的src链接设为同一张图片(比如空白图片),然后给img标签设置自定义属性(比如 data-src),然后将真正的图片地址存储在data-src中,当JS监听到该图片元素进入可视窗口时,将自定义属性中的地址存储到src属性中。达到懒加载的效果。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>47、js请求,一般会有哪些地方有缓存处理? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.DNS缓存:短时间内多次访问某个网站,在限定时间内,不用多次访问DNS服务器。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.CDN缓存:内容分发网络(人们可以在就近的代售点取火车票了,不用非得到火车站去排队)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.浏览器缓存:浏览器在用户磁盘上,对最新请求过的文档进行了存储。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.服务器缓存:将需要频繁访问的Web页面和对象保存在离用户更近的系统中,当再次访问这些对象的时候加快了速度。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>48、typeScript的优势有哪些? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.类型检测:在Typescript中为变量指定具体类型时,IDE会做出类型检测,这个特性减少在开发阶段犯错几率。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.语法提示:在IDE里编写Typescript代码时, IDE会根据你当前的上下文,把你能用的类、变量、方法和关键字都给你提示出来。直接选择,这个特性提高开发效率。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.便于重构:重构是说你可以很方便的去修改你的变量或者方法的名字或者是文件的名字,当你做出这些修改的时候, IDE会帮你自动引用这个变量或者调用这个方法地方的代码自动帮你修改掉</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.活跃社区:Typescript拥抱es6的规范,也支持部分ESNext草案规范,大部分的第三方库提供Typescript类型定义的文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">TypeScript的最大特点是静态类型,不同于javascript的动态类型,静态类型有以下优势:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.其一,静态类型检查可以做到early fail ,即你编写的代码即使没有被执行到,一旦你编写代码时发生类型不匹配,语言在编译阶段(解释执行也一样,可以在运行前)即可发现。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.其二,静态类型对阅读代码是友好的,针对大型应用,方法众多,调用关系复杂,不可能每个函数都有人编写细致的文档,所以静态类型就是非常重要的提示和约束。此外TS还实现了类,接口,枚举,泛型,方法重载等语法糖,方便了前端开发;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>49、jQuery特点? </strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>jQuery:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">它是轻量级的js库 ,它兼容</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS3</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,还兼容各种浏览器,jQuery使用户能更方便地处理</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTML</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需要定义id即可。</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>jQuery特点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.jQ是在js基础上进行的封装,可以相互转换,不是全新的语言;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.jQ最核心的理念就是“用最少的代码,做最多的事情”“write less do more”;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.jQ最大特点就是具有强大的兼容性,不在为各种浏览器兼容性问题而费神费力;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.jQ使用的是链式写法,可以把多行代码写在一行,方便简洁;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.jQ还简化了js操作css的代码,并且代码的可读性也比js要强;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.jQ简化了AJAX操作,后台只需返回一个JSON格式的字符串就能完成与前台的通信。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.jQuery提供了扩展接口:JQuery.extend(object),可以在JQuery的命名空间上增加新函数。JQuery的所有插件都是基于这个扩展接口开发的;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.jQuery有着丰富的第三方的插件,例如:树形菜单、日期控件、图片切换插件、弹出窗口等等基本前台页面上的组件都有对应插件,并且用JQuery插件做出来的效果很炫,并且可以根据自己需要去改写和封装插件,简单实用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>50、前后端分离? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>开发模式</strong></span></span></strong></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/3871588285e0408ca7787f6642dada20.jpg" target="_blank"><img alt="前端高频面试题_第8张图片" height="353" src="http://img.e-com-net.com/image/info8/3871588285e0408ca7787f6642dada20.jpg" width="554" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>请求方式</strong></span></span></strong></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/128319638a3a40a1bdb6ad116fca4f53.jpg" target="_blank"><img alt="前端高频面试题_第9张图片" height="246" src="http://img.e-com-net.com/image/info8/128319638a3a40a1bdb6ad116fca4f53.jpg" width="554" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>前后端分离优势</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.可以实现真正的前后端解耦,前端服务器使用nginx。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.在大并发情况下,可以同时水平扩展前后端服务器。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.减少后端服务器的并发/负载压力</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.多端应用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.页面显示的东西再多也不怕,因为是异步加载。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.nginx支持页面热部署,不用重启服务器,前端升级更无缝。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9.增加代码的维护性&易读性(前后端耦在一起的代码读起来相当费劲)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">10提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">11.在nginx中部署证书,外网使用https访问,并且只开放443和80端口,其他端口一律关闭(防止黑客端口扫描),内网使用http,性能和安全都有保障。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">12.前端大量的组件代码得以复用,组件化,提升开发效率,抽出来!</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>开发人员分离</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后端工程师:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把精力放在java基础,设计模式,jvm原理,spring+springmvc原理及源码,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构,弹性计算架构,微服务架构,java性能优化,以及相关的项目管理等等。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后端追求的是:三高(高并发,高可用,高性能),安全,存储,业务等等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端工程师:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把精力放在html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8引擎,javascript多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等等。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端追求的是:页面表现,速度流畅,兼容性,用户体验等等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>总结:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前后端分离并非仅仅只是一种开发模式,而是一种架构模式(前后端分离架构)。千万不要以为只有在撸代码的时候把前端和后端分开就是前后端分离了,需要区分前后端项目。前端项目与后端项目是两个项目,放在两个不同的服务器,需要独立部署,两个不同的工程,两个不同的代码库,不同的开发人员。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前后端工程师需要约定交互接口,实现并行开发,开发结束后需要进行独立部署,前端通过ajax来调用http请求调用后端的restful api。前端只需要关注页面的样式与动态数据的解析&渲染,而后端专注于具体业务逻辑。</span></span></p> <p></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>Vue</strong></strong></h2> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、对MVVM 的理解? </strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVVM 是 Model-View-ViewModel 的缩写。MVVM 是一种设计思想。Model 层代表数据模型,可以在 Model 中定义数据修改和操作的业务逻辑;View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来,ViewModel 是一个同步 View 和 Model 的对象(桥梁)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在 MVVM 架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行交互,Model 和 ViewModel 之间的交互是双向的, 因此 View 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、MVC MVVM 的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>MVC</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVC是应用最广泛的软件架构之一,一般MVC分为:Model(模型),View(视图),Controller(控制器)。 这主要是基于分层的目的,让彼此的职责分开。View一般用Controller来和Model进行联系。Controller是Model和View的协调者,View和Model不直接联系。基本都是单向联系。M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>MVVM</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在MVVM框架下视图和模型是不能直接通信的,只能通过ViewModel进行交互,它能够监听到数据的变化,然后通知视图进行自动更新,而当用户操作视图时,VM也能监听到视图的变化,然后通知数据做相应改动,这实际上就实现了数据的双向绑定。并且V和VM可以进行通信。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVC和MVVM的区别并不是VM完全取代了C,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。也就是说MVVM实现的是业务逻辑组件的重用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVC中Controller演变成MVVM中的ViewModel</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVVM通过数据来显示视图层而不是节点操作</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">MVVM主要解决了MVC中大量的dom操作使页面渲染性能降低,加载速度变慢,影响用户体验</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、说说你对vue的理解?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue 是一套用于构建用户界面的渐进式MVVM框架。那怎么理解渐进式呢?渐进式含义:强制主张最少。Vue.js包含了声明式渲染、组件化系统、客户端路由、大规模状态管理、构建工具、数据持久化、跨平台支持等,但在实际开发中,并没有强制要求开发者</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用所有</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">功能,而是根据需求逐渐扩展。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue.js的核心库只关心视图渲染,且由于渐进式的特性,Vue.js便于与第三方库或既有项目整合。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、说说你对单页应用SPA的理解?有什么优缺点?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>单页应用</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">单页应用又称 SPA(Single Page Application)指的是使用单个 HTML 完成多个页面切换和功能的应用。这些应用只有一个 html 文件作为入口,一开始只需加载一次 js,css 等相关资源。使用 js 完成页面的布局和渲染。页面展示和功能室</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据路由完成的。单页应用跳转,就是切换相</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">关组件,仅刷新局部资源。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>多页应用</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">多页应用又称 MPA(Multi Page Application)指有多个独立的页面的应用,每个页面必须重复加载 js,css 等相关资源。多页应用跳转,需要整页资源刷新。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>区别</strong></span></span></strong></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/0ac138bfbe674a46aa6e531b754fd51a.jpg" target="_blank"><img alt="前端高频面试题_第10张图片" height="559" src="http://img.e-com-net.com/image/info8/0ac138bfbe674a46aa6e531b754fd51a.jpg" width="650" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>单页应用</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优点:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">具有桌面应用的即时性、网站的可移植性和可访问性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用户体验好、快,内容的改变不需要重新加载整个页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">良好的前后端分离,分工更明确</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>单页应用</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>缺点:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">首次渲染速度相对较慢</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、Watch和computed的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>watch、computed、methods作用机制</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.侦听属性watch和计算属性computed都是以Vue的依赖追踪机制为基础的,它们都试图处理这样一件事情:当某一个数据(称它为依赖数据)发生变化的时候,所有依赖这个数据的“相关”数据“自动”发生变化,也就是自动调用相关的函数去实现数据的变动。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.对methods里面是用来定义函数的,很显然,它需要手动调用才能执行。而不像watch和computed那样,“自动执行”预先定义的函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>watch、computed区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">computed支持缓存,只有依赖数据发生改变,才会重新进行计算;而watch不支持缓存,数据变,直接会触发相应的操作。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">computed不支持异步,当computed内有异步操作时无效,无法监听数据的变化;而watch支持异步。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">computed属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值;而watch监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>compu</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>ted使用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个属性是由其它属性计算而来的,这个属性依赖其它属性,是一个多对一或者一对一,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用computed</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当存在复杂逻辑、需要用到缓存时</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>watch使用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当一个属性发生变化时,需要执行对应的操作;一对多一般用watch</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当需要在数据变化时执行异步或开销较大的操作时</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、v-show和v-if的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue中显隐方法常用两种,v-show和v-if,但这两种是有区别的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>实现本质方法区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-show本质就是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置元素</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">display为none,控制隐藏</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-if是动态的向DOM树内添加或者删除DOM元素</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>编译的区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-show其实就是在控制css</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>编译的条件</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-show都会编译,初始值为false,只是将display设为none,但它也编译了</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-if初始值为false,就不会编译了</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>性能</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>用法</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-if更灵活,还可以配合v-else一起使用</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、Vue实例挂载过程</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">new Vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的时候调用会调用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">_init方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义 $set、$get 、$delete、$watch 等方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义 $on、$off、$emit、$off等事件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义 _update、$forceUpdate、$destroy生命周期</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">调用$mount进行页面的挂载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">挂载的时候主要是通过mountComponent方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义updateComponent更新函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">执行render生成虚拟DOM</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">_update将虚拟DOM生成真实DOM结构,并且渲染到页面中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、$route和$router的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">$router</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> VueRouter </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例,包含了一些路由的跳转方法,钩子函数</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">想要导航到不同 URL,则使用 $router.push 方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">$route对象表示当前的路由信息,包含了当前url解析得到的信息,包含当前</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">路由</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> name、path</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">、</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">query、params等</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、vue的生命周期</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue实例从创建到销毁的整个过程就是生命周期。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>beforeCreate</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:组件实例被创建之初</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">执行时组件实例还未创建,通常用于插件开发中执行一些初始化任务</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>create</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>d:组件实例已经完全创建</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件初始化完毕,各种数据可以使用,常用于异步数据获取</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>beforeM</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>ount:组件挂载之前</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在挂载开始之前被调用:相关的 render 函数首次被调用。(该钩子在服务器端渲染期间不被调用)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">未执行渲染、更新,dom未创建</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>mounted:组件挂载到实例上去之后</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">初始化结束,dom已创建,可用于获取访问数据和dom元素</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>beforeUpdat</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>e:组件数据发生变化,更新之前</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。(该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">更新前,可用于获取更新前各种状态</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>u</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>pdate</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>d:组件数据更新之后</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">更新后,所有状态已是最新</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>beforeDest</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>ory:组件实例销毁之前</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">实例销毁之前调用。在这一步,实例仍然完全可用。(该钩子在服务器端渲染期间不被调用)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">销毁前,可用于一些定时器或订阅的取消</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>destr</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>oyed:组件实例销毁之后</strong></span></span></strong><strong> </strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。(该钩子在服务器端渲染期间不被调用)</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件已销毁</span></span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/8071c3a329134c8da785080f3abb0f21.jpg" target="_blank"><img alt="前端高频面试题_第11张图片" height="602" src="http://img.e-com-net.com/image/info8/8071c3a329134c8da785080f3abb0f21.jpg" width="634" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、v-if和v-for为什么不建议一起用?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">永远不要把</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">v-if</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 和 v-for 同时用在同一个元素上,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为v-for优先级比v-if高,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">每次渲染都会先循环</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一遍所有的节点,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">再进行条件判断</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">带来性能方面的浪费</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">为</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">避免出现这种情况,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可以</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、SPA首屏加速慢怎么解决</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减小入口文件积</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加</span></span></p> <pre><code class="language-javascript"> routes: [ path: 'Blogs', name: 'ShowBlogs', component: () => import('./components/ShowBlogs.vue') ]</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>静态资源本地缓存</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后端返回资源采用HTTP缓存,设置Cache-Control,Last-Modified,Etag等响应头</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端合理利用localStorage</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>UI框架按需加载</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在日常使用UI框架,例如element-UI</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们经常性直接饮用整个UI库</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">但实际上我用到的组件只有按钮,分页,表格,输入与警告 所以我们要按需引用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <pre><code class="language-javascript">import { Button, Input, Pagination, Table, TableColumn, MessageBox } from "element-ui " Vue.use(Button) Vue.use(Input) Vue.use(Pagination)</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>图片资源的压缩</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">图片资源虽然不在编码过程中,但它却是对页面性能影响最大的因素</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于所有的图片资源,我们可以进行适当的压缩</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>组件重复打包</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">假设A.js文件是一个常用的库,现在有多个路由使用了A.js文件,这就造成了重复下载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:在webpack的config文件中,修改CommonsChunkPlugin的配置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。设置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">minChunks为3表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件</span></span></p> <pre><code class="language-javascript">minChunks: 3</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>开启GZip压缩</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">拆完包之后,我们再用gzip做一下压缩 安装compression-webpack-plugin</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用SSR</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从头搭建一个服务端渲染是很复杂的,vue应用建议使用Nuxt.js实现服务端渲染</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、data属性为何是函数而不是一个对象</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根实例对象data可以是对象也可以是函数(根实例是单例),不会产生数据污染情况</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>13、Vue给对象添加新属性界面不刷新</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原因是一开始</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">data所有的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">属性</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Object.defineProperty设置成</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">了</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">响应式数据</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是后面新增的属性,并没有通过Object.defineProperty设置成响应式数据</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,所有新增属性数据更新了,但是页面不刷新</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>解决方法</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue.set()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:使用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue.set( target, propertyName/index, value )</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">给对象添加新属性,这个方法再次调用了</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Object.defineProperty</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">方法,实现新增属性的的响应式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Object.assign()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建一个新的对象,合并原对象和混入对象的属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">$forceUpdated()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:强制刷新</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>14、Vue组件和插件的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>组件</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念(组件)来实现开发的模式,在Vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中每一个.vue文件都可以视为一个组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>插件</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件通常用来为</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 添加全局功能。插件的功能范围没有严格的限制</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>编写形式不同</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件:编写一个组件,常见的就是vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">单文件的这种格式,每一个.vue文件我们都可以看成是一个组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件:vue插件的实现应该暴露一个</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>注册形式</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>不同</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件: vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件注册主要分为全局注册与局部注册</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">全局注册通过Vue.component方法,第一个参数为组件的名称,第二个参数为传入的配置项</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,局部注册只需在用到的地方通过components</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">属性注册一个组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件的注册通过Vue.use()的方式进行注册(安装),第一个参数为插件的名字,第二个参数是可选择的配置项</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用场景</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>不同</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件 (Component) 是用来构成 App 的业务模块,它的目标是 App.vue</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">插件 (Plugin) 是用来增强你的技术栈的功能模块,它的目标是 Vue 本身</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">简单来说,插件就是指对Vue的功能的增强或补充</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>15、Vue组件通信方式</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>vue中8种通信方案</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过 props 传递</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过 $emit 触发自定义事件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用 ref</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">EventBus</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">$parent 或$root</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">attrs 与 listeners</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Provide 与 Inject</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vuex</span></span></p> <p></p> <h4 style="margin-left:0pt;text-align:left;"><span style="background-color:#ffffff;"><strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>16、props传递数据</strong></span></span></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适用场景:父组件传递数据给子组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子组件设置props属性,定义接收父组件传递过来的参数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父组件在使用子组件标签中通过字面量来传递值</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>$emit 触发自定义事件</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适用场景:子组件传递数据给父组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父组件绑定监听器获取到子组件传递过来的参数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>ref</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父组件在使用子组件的时候设置ref</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父组件通过设置子组件ref来获取</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子组件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>EventBus</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用场景:兄弟组件传值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建一个中央</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">总线EventBus</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">兄弟组件通过$emit触发自定义事件,$emit第二个参数为传递的数值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">另一个兄弟组件通过$on监听自定义事件</span></span></p> <p style="margin-left:0;text-align:left;"></p> <pre><code class="language-javascript"> //创建一个中央事件总线类 Bus.js class Bus { constructor() { this.callbacks = {}; // 存放事件的名字 } $on(name, fn) { this.callbacks[name] = this.callbacks[name] || []; this.callbacks[name].push(fn); } $emit(name, args) { if (this.callbacks[name]) { this.callbacks[name].forEach((cb) => cb(args)); } } } // main.js Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上 //另一种方式 Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能 </code></pre> <pre><code class="language-javascript">// Children1.vue this.$bus.$emit('foo')</code></pre> <pre><code class="language-javascript">// Children2.vue this.$bus.$on('foo', this.handle)</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>$parent 或$ root</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过共同祖辈$parent或者$root搭建通信侨联</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">兄弟组件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">this.$parent.on('add',this.add)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">另一个兄弟组件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">this.$parent.emit('add')</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>$attrs 与$ listeners</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适用场景:祖先传递数据给子孙</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置批量向下传属性$attrs和 $listeners</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">包含了父级作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可以通过 v-bind="$attrs" 传⼊内部组件</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>provide 与 inject</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在祖先组件定义provide属性,返回传递的值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在后代组件通过inject接收组件传递过来的值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>vuex</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适用场景: 复杂关系的组件数据传递</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vuex作用相当于一个用来存储共享变量的容器 </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>小结</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父子关系的组件数据传递选择 props  与 $emit进行传递,也可选择ref</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">兄弟关系的组件数据传递可选择$bus,其次可以选择$parent进行传递</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">祖先与后代组件数据传递可选择attrs与listeners或者 Provide与 Inject</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">复杂关系的组件数据传递可以通过vuex存放共享的变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>17、Vuex介绍</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/9b11c297d00744d3b73e11e0e5cd09e1.jpg" target="_blank"><img alt="前端高频面试题_第12张图片" height="315" src="http://img.e-com-net.com/image/info8/9b11c297d00744d3b73e11e0e5cd09e1.jpg" width="401" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vuex是-个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,, 并以相应的规则保证状态以一种可预测的方式发生变化。vuex用于组件之间的传值。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>核心流程中的主要功能</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1. Vue Components是我们的vue组件,组件会触发( dispatch)一些事件或动作,也就是图中的Actions</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.我们在组件中发出的动作,肯定是想获取或者改变数据的,但是在vuex中,数据是集中管理的,我们不能直接去更改数据,所以会把这个动作提交( Commit )到Mutations中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.然后Mutations就去改变 State中的数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.当State中的数据被改变之后,就会重新渲染( Render )到Vue Components中去,组件展示更新后的数据,完成一个流程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>各模块在核心流程中的主要功能</strong></span></span></strong></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.Vue Components: Vue组件,HTML页面上,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.dispatch:操作行为触发方法,是唯一能执行action的方法</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.actions: 操作行为处理模块,负责处理VueComponents接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以歧持action的链式触发</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.state:页面状态管理容器对象。集中存储Vuecomponents中data对象的零散数据,全局唯一, 以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.getters: state对象读取方法。图中没有单独列出该模块,应该被包含在了render中, Vue Components通过该方法读取全局state对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>store拆分</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在项目比较复杂的时候,数据全部写在一个state 方法全部集中一个mutations中,将会使我们的文件显得太过于臃肿,而且不易维护,那怎么办呢?还是那句话办法总比问题多,vuex为我们提供了module这样一个模块的概念。我们可以利用它来根据我们个个组件或者页面所需要的数据</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">分割成不同的模块</span></span></p> <pre><code class="language-javascript"> const moduleA = { state: {}, mutations: {}, actions: {}, getters: {} } const moduleB = { state: {}, mutations: {}, actions: {}, getters: {} } export default new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) // 在各自的模块内部使用 state.price // 这种使用方式和单个使用方式-样,直接使用就行 // 在组件中使用 store.state.a.price // 先找到模块的名字,再去调用厢性 store.state.b.price // 先找到模块的名字,再去调用属性</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>vuex的原理</strong></span></span></strong></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Vuex是通过全局注入store对象,来实现组件间的状态共享</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。store注入 vue的实例组件的方式,是通过vue的 mixin机制,借助vue组件的生命周期 钩子 beforeCreate 完成的。即 每个vue组件实例化过程中,会在 beforeCreate 钩子前调用 vuexInit 方法。</span></span></span></p> <pre><code class="language-javascript"> Vue.mixin({ beforeCreate() { if (this.$options && this.$options.store) { // 找到根组件main上面挂一个$store this.$store = this.$options.store // console.log(this.$store); } else { // 非根组件指向其父组件的$store this.$store = this.$parent && this.$parent.$store } } })</code></pre> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在大型复杂的项目中(多级组件嵌套),需要实现一个组件更改某个数据,多个组件自动获取更改后的数据进行业务逻辑处理,这时候使用vuex比较合适。假如只是多个组件间传递数据,使用vuex未免有点大材小用,其实只用使用组件间常用的通信方法即可。</span></span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>18、vuex的action和mutation的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Mutation</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在vuex的严格模式下, Mutaion是vuex中改变State的唯一途径</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Mutation 中只能是同步操作</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过store.commit()调用Mutation</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Action</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一些对State的异步操作可放在Action中,并通过在Action中commit调用 Mutation变更状态</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过store.dispatch() 方法触发,或者通过mapActions辅助函数将vue组件的methods映射成store.dispatch()调用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>总结</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">mutations 可以直接修改state ,但只能包含同步操作,同时,只能通过提交commit调用。actions是用来触发mutations的,它无法直接改变state ,它可以包含异步操作,它只能通过store.dispatch触发</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>19、双向绑定原理</strong></strong></span></h4> <p></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/903d78116a3c4f338f302c9607e583aa.jpg" target="_blank"><img alt="前端高频面试题_第13张图片" height="334" src="http://img.e-com-net.com/image/info8/903d78116a3c4f338f302c9607e583aa.jpg" width="625" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue是通过数据劫持结合发布者-订阅者模式的方式来实现数据双向绑定的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,通过Object.defineProperty()方法来劫持对象属性的setter和getter,在数据变动时发布消息给订阅者,触发相应的监听回调。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>v</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>iewModel主要职责</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据变化后更新视图</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">视图变化后更新数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>v</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>iewModel两个主要部分组成</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">监听器(Observer):对所有数据的属性进行监听</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解析器(Compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>具体步骤:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第一步:对需要observe的数据对象data进行递归遍历,包括子属性对象的属性,都加上 setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.在自身实例化时往属性订阅器(dep)里面添加自己</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.自身必须有一个update()方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>总结</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.new Vue()首先执行初始化,对</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">data执行响应化处理,这个过程发生Observe中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同时对模板执行编译,找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在Compile中</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同时定义⼀个更新函数和Watcher,将来对应数据变化时Watcher会调用更新函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>20、vue2. x中如何监测数组变化</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过Object.defineProperty()劫持数组为其设置getter和setter后,调用的数组的push、splice、pop等方法改变数组元素时并不会触发数组的setter,这就会造成使用上述方法改变</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数组后,页面上并不能及时体现这些变化,也就是数组数据变化不是响应式的,那么vue中是如何实现的呢?</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">重写了数组的push、pop、shift、unshift、splice、sort、reverse七种方法,重写方法在实现时除了将数组方法名对应的原始方法调用一遍并将执行结果返回外,还通过执行ob.dep.notify()将当前数组的变更通知给其订阅者,这样当使用重写后方法改变数组后,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数组订阅者会将这边变化更新到页面中。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>21、对nextTick的理解?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们可以理解成,Vue</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,如果想要在修改数据后立刻得到更新后的DOM</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">结构,可以使用Vue.nextTick()</span></span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>22、对mixin混入的理解</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">本质其实就是一个</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">js</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对象,它可以包含我们组件中任意功能选项,如data、components、methods、created、computed等等</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>合并策略</strong></span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">替换型</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:同名的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">props、methods、inject、computed会被后来者代替</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">合并型</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:data,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过set方法进行合并和重新赋值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">队列型</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">生命周期钩子和watch被合并为一个数组,然后正序遍历</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">依</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">次执行</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">叠加型</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">component、directives、filters,通过原型链进行层层的叠加</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>23、对slot的理解?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通俗易懂的讲,slot具有“占坑”的作用,在子组件占好了位置,那父组件使用该子组件标签时,新添加的DOM元素就会自动填到这个坑里面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>默认插槽:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子组件用<slot>标签来确定渲染的位置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父组件在使用的时候,直接在子组件的标签内写入内容即可</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>具名插槽:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">给子组件占的每一个坑<slot</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> name=“xxx”</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">>取名,将父组件添加的HTML元素添加到指定名字的坑,就实现了分发内容在不同位置显示</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>作用域插槽:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子组件在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件v-slot接受的对象上</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>24、v-for为何要加key关键字</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>25、说说对keep-alive缓存组件的理解</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">keep-alive是vue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">, </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">它自身不会渲染一个DOM元素,也不会出现在父组件链中</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>keep-alive可以设置以下props属性:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">include </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">字符串或正则表达式</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">只有名称匹配的组件会被缓存</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">E</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">xclude</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">字符串或正则表达式</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">任何名称匹配的组件都不会被缓存</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">max </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数字</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">最多可以缓存多少组件实例</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>activated和deactivated两个生命周期函数</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">activated:当组件激活时,钩子触发的顺序是created->mounted->activated</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">deactivated: 组件停用时会触发deactivated,当再次前进或者后退的时候只触发activated</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>26、Vue常用修饰符</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>表单修饰符</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">lazy</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:在我们填完信息,光标离开标签的时候,才会将值赋予给value</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,也就是在change事件之后再进行信息同步</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">trim</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">: 自动过滤用户输入的首尾空格字符,而中间的空格不会过滤</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">number</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:自动将用户的输入值转为数值类型,但如果这个值无法被parseFloat</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解析,则会返回原来的值</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>事件修饰符</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">stop</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">阻止了事件冒泡,相当于调用了event.stopPropagation方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">prevent</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">阻止了事件的默认行为,相当于调用了event.preventDefault方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">self</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">只当在 event.target 是当前元素自身时触发处理函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">once</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">绑定了事件以后只能触发一次,第二次就不会触发</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">capture</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使事件触发从包含这个元素的顶层开始往下触发</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">passive</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">native</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用 v-on 只会监听自定义事件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>鼠标按键修饰符</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">left</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">左键点击</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">right</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">右键点击</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">middle</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中键点击</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>键值修饰符</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">普通键</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(enter、tab、delete、space、esc、up...)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">系统修饰键</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(ctrl、alt、meta、shift...)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>v-bind修饰符</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">async</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能对props进行一个双向绑定</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">prop</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置自定义标签属性,避免暴露数据,防止污染HTML结构</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">camel</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将命名变为驼峰命名法,如将view-Box属性名转换为 viewBox</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>27、项目中有用过自定义指令吗?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">项目中</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">定义一个auth</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自定义</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">指令来显示隐藏页面元素,从而实现按钮权限</span></span></p> <pre><code class="language-javascript"> // util/auth.js import store from "@/store"; export default { bind(el, binding, vnode) { let auths = store.state.loginInfo.roleBtns; // 后台返回的按钮权限列表 let hasAuth = auths.includes(binding.value); if (hasAuth) { delete el.style.display; } else { el.style.display = "none"; } } }</code></pre> <p style="margin-left:0;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">全局注册</span></span></p> <pre><code class="language-javascript"> import Vue from 'vue' import App from './App.vue' import router from './router ' import store from './store' import iview from 'iview' import 'iview/dist/styles/iview.css' import auth from '@/util/auth'; // 引入 Vue.config.productionTip = false Vue.use(iview) Vue.directive("auth", auth); // 注册 new Vue({ router, store, render: h => h(App) }).$mount('#app')</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过自定义指令v-auth绑定字段,当绑定的字段包含在后端返回的roleBtns列表里,那么该按钮会显示,否则隐藏</span></span></p> <p style="margin-left:0;text-align:left;"><a href="http://img.e-com-net.com/image/info8/b0a423191d1c4e17a1366da44a9edbf3.jpg" target="_blank"><img alt="前端高频面试题_第14张图片" height="118" src="http://img.e-com-net.com/image/info8/b0a423191d1c4e17a1366da44a9edbf3.jpg" width="515" style="border:1px solid black;"></a></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>28、过滤器filter的应用场景</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在Vue中使用过滤器(Filters)来渲染数据是一种很有趣的方式。过滤器不改变真正的data,而只是改变渲染的结果,并返回过滤后的版本。局部过滤器优先于全局过滤器被调用。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件内定义局部过滤器</span></span></p> <pre><code class="language-javascript"> filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase + value.slice(1) } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue全局过滤器</span></span></p> <pre><code class="language-javascript"> Vue.filter('capitalize', function (value) { if (!value) return value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) }) new Vue({ //... })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用</strong></span></span></strong></span></p> <pre><code class="language-html"><!--在双花括号中--> {{message| capitalize}} <!--在`v-bind` 中--> <div v-bind:id="rawId| formatId"></div></code></pre> <p><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>应用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">单位转换、数字打点、文本格式化、时间格式化之类的等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>29、什么是虚拟dom,如何实现一个虚拟dom</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">它只是一层对真实</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DOM</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在Javascript对象中,虚拟DOM 表现为一个 Object对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,不同框架对这三个属性的名命可能会有差别</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/8dd9f08716c94a5cb596ff5c0b7df18d.jpg" target="_blank"><img alt="前端高频面试题_第15张图片" height="311" src="http://img.e-com-net.com/image/info8/8dd9f08716c94a5cb596ff5c0b7df18d.jpg" width="554" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为何需要虚拟DOM</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">真正的 DOM 元素非常庞大,由此可以得知DOM是很慢的。而且操作它们的时候你要小心翼翼,轻微的触碰可能就会导致页面重排。浏览器里一遍又一遍的渲染DOM是非常非常消耗性能的,常常会出现页面卡死的情况,影响用户的体验</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">得益于V8引擎的出现,让JavaScript可以高效地运行,在性能上有了极大的提高。相对于 DOM 对象,原生的 JavaScript 对象处理起来更快,而且更简单。DOM 树上的结构、属性信息我们都可以很容易地用 JavaScript 对象表示出来,为Virtual DOM的产生提供了大前提。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>虚拟DOM的优势</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">很多人认为虚拟 DOM 最大的优势是 diff 算法,减少 JavaScript 操作真实 DOM 的带来的性能消耗。虽然这一个虚拟 DOM 带来的一个优势,但并不是全部。虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>30、你了解vue的diff算法吗</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">diff 算法是一种通过同层的树节点进行比较的高效算法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">diff整体策略为</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">深度优先,同层比较</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>两个特点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">比较只会在同层级进行, 不会跨层级比较</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在diff比较的过程中,循环从两边向中间比较</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">V</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ue中当数据发生改变时,订阅者</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">watcher就会调用patch给真实的DOM打补丁</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过isSameVnode进行判断,相同则调用patchVnode方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>patchVnode做了以下操作:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">找到对应的真实dom,称为el</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果oldVnode有子节点而VNode没有,则删除el子节点</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果两者都有子节点,则执行updateChildren函数比较子节点</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>updateChildren主要做了以下操作:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置新旧VNode的头尾指针</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>30、Axios是什么?有封装过axios吗?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Axios</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>特点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">支持从浏览器中创建 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">XMLHttpRequests</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">支持从 node.js 创建 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">http</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">支持 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Promise</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> API</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能拦截请求和响应</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能转换请求数据和响应数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">能取消请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自动转换 JSON 数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">客户端支持防御 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">C</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">SRF</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为什么要封装</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">axios</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 的 API 很友好,你完全可以很轻松地在项目中直接使用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不过随着项目规模增大,如果每发起一次HTTP请求,就要把这些比如设置超时时间、设置请求头、根据项目环境判断使用哪个请求地址、错误处理等等操作,都需要写一遍</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">这种重复劳动不仅浪费时间,而且让代码变得冗余不堪,难以维护。为了提高我们的代码质量,我们应该在项目中二次封装一下 axios 再使用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>如何封装</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">封装的同时</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">需要和后端协商好一些约定,请求头,状态码,请求超时时间...</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置接口请求前缀:根据开发、测试、生产环境的不同,前缀需要加以区分</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">请求头</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">来实现一些具体的业务,必须携带一些参数才可以请求(例如:会员业务)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">状态码</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据接口返回的不同</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">status</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> ,来执行不同的业务,这块需要和后端约定好</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">请求方法</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据get、post等方法进行一个再次封装,使用起来更为方便</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">请求拦截器</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据请求的请求头设定,来决定哪些请求可以访问</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">响应拦截器</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">这块就是根据 后端返回来的状态码判定执行不同业务</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>31、Vue权限管理</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>接口权限</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">登录页面进行登录</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">登录完拿到token,将token存起来,通过axios请求拦截器进行拦截,每次请求的时候头部携带token</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,如果token失效,后端返回约定好的状态码,前端在axios响应拦截进行拦截,重新跳转到登录页进行登录</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>菜单权限</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端定义路由信息,路由的</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">name字段都不为空</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">路由name</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">字段与后端返回菜单</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">列表</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">做关联,后端返回的菜单信息中必须要</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">包含</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">name对应的字段</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">才</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">展示对应菜单项</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>32、Vue项目是如何解决跨域的</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果是通过vue-cli脚手架工具搭建项目,我们可以通过webpack为我们起一个本地服务器</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">devServer</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">作为请求的代理对象</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过该服务器转发请求至目标服务器,得到结果再转发给前端,但是最终发布上线时如果web应用和接口服务器不在一起仍会跨域在vue.config.js文件,新增以下代码</span></span></span></p> <pre><code class="language-javascript"> module.exports = { devServer: { host: '127.0.0.1', port: 8084, open: true, // vue项目启动时自动打开浏览器 proxy: { '/api': { // '/api'是代理标识,用于告诉node, url前面是/api的就是使用代理的 target: "http://xxx.xxx.xxx:8080", // 目标地址,一般是指后台服务器地址 changeOrigin: true, // 是否跨域 pathRewrite: { // pathRewrite 的作用是把实际Request Url中的"/api" 用''代替 '^/api': '' } } } } }</code></pre> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过axios发送请求中,配置请求的根路径</span></span></span></p> <pre><code class="language-javascript">axios.defaults.baseURL = '/api'</code></pre> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>33、Vue3有了解吗?说说跟vue2的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优化</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">利用新的语言特性(es6)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决架构问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>更小</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue2采用面向对象编程的思想,vue3则采用函数式编程的思想。充分利用函数式编程组合大于继承的优势,采用函数式编程更利于逻辑功能的复用,webpack打包时更有利于tree-shaking,更利于代码的压缩,更利于返回值类型校验,压缩后的文件体积更小。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>更快</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue2需要diff所有的虚拟dom节点,而vue3参考了SVELTE框架的思想,先分层次,然后找不变化的层,针对变化的层进行diff,更新速度不会再受template大小的影响,而是仅由可变的内容决定。经过尤雨溪自己的测试,大概有6倍的速度提升。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>加强typescript支持</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue3的源码开始采用了ts进行编写,给开发者也提供了支持ts的开发模式。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Api一致性</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue3最开始的版本可以完美兼容vue2的api。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>提高可维护能力</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从源码的层面上提供了更多的可维护能力。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>开放更多底层功能</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把更多的底层功能开放出来,比如render、依赖收集功能,我们可以更好的进行自定义化开发,可以写更多的高阶组件。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>数据双向绑定方面的区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue2 采用了defineProperty,而vue3则采用了proxy。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.使用proxy不污染源对象,会返回一个新对象,defineProperty是注入型的,会破坏源对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用proxy只需要监听整个源对象的属性,不需要循环使用Object.defineProperty监听对象的属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用proxy可以获取到对象属性的更多参数,使用defineProperty只能获取到监听属性的新值newvalue</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>34、Vue3为什么用proxy代替defineProperty</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>defineProperty缺点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">检测不到对象属性的添加和删除</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数组API方法无法监听到</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Proxy优点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Proxy直接可以劫持整个对象,并返回一个新对象,我们可以只操作新的对象达到响应式目的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Proxy可以直接监听数组的变化(push、shift、splice)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Proxy有多达13种拦截方法</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>35、Vue中错误处理</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>后端接口错误</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过axios的interceptor实现网络请求的response先进行一层拦截</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>代码逻辑错误</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置全局错误处理函数,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">errorHandler为全局钩子,使用Vue.config.errorHandler配置,2.6</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">版本</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">后可捕捉v-on与promise链的错误,可用于统一错误处理与错误兜底</span><span style="color:#121212;">。</span></span></p> <pre><code class="language-javascript"> Vue.config.errorHandler = function (err, Vm, info) { // handle error // `info` 是Vue 特定的错误信息,比如错误所在的生命周期钩子 //只在2.2.0+ 可用 }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">生命周期钩</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子,errorCaptured是组件内部钩子,可捕捉本组件与子孙组件抛出的错误,接收error、vm、info三个参数,return false后可以阻止错误继续向上抛出。</span></span></p> <pre><code class="language-javascript"> errorCaptured(err, vm, info) { console.log(`cat EC: ${err.toString()}\n info:${info}`); return false; }</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>36、react和vue有哪些不同,说说你对这两个框架的看法</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>相同点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都有组件化思想</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都支持服务器端渲染</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都有Virtual DOM(虚拟dom)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据驱动视图</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都支持props进行父子组件间数据通信</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都有支持native的方案:Vue的weex、React的React native</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">都有自己的构建工具:Vue的vue-cli、React的Create React App</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>区别</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据流向的不同</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">react从诞生开始就推崇单向数据流,而Vue是双向数据流</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.组件写法不同:组件写法React推荐JSX,就是把HTML和css全都写进JavaScript中,Vue推荐是webpack+vue+loader单文件组件格式,就是HTML、css、JavaScript都写进一个文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">数据变化的实现原理不同</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">react使用的是不可变数据,而Vue使用的是可变的数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">组件化通信的不同</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">react中我们通过使用回调函数来进行通信的,而Vue中子组件向父组件传递消息有两种方式:事件和回调函数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">diff算法不同</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">react主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。Vue 使用双向指针,边对比,边更新DO</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">M</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>37、父组件和子组件生命周期钩子执行顺序</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>加载渲染过程</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父beforeCreate</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父created</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父beforeMount</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子beforeCreate</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子created</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子beforeMount</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子mounted</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父mounted</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>子组件更新过程</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><strong> </strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父beforeUpdate</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子beforeUpdate</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子updated</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父updated</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>父组件更新过程</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父beforeUpdate</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父updated</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>销毁过程:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父beforeDestroy</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子beforeDestroy</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">子destroyed</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-></span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">父destroyed</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>38、Router-link和a标签的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Router-link做了三件事:</strong></span></span></strong></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.有onclick那就执行onclick</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.click的时候阻止a标签默认事件(这样子点击<a href="/abc">123</a>就不会跳转和刷新页面)</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.再取得跳转href(即是to),用history(前端路由两种方式之一,history & hash)跳转,此时只是链接变了,并没有刷新页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>39、Router路由</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>完整的导航解析流程</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.触发进入其它路由</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.调用要离开路由的组件守卫beforeRouteLeave</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.调用全局的前置守卫beforeEach</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.在重用的组件里调用 beforeRouteUpdate</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.在路由配置里调用 beforeEnter</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.解析异步路由组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.在将要进入的路由组件中调用beforeRouteEnter</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.调用全局的解析守卫beforeResolve</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9.导航被确认</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">10.调用全局的后置钩子afterEach。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">11.触发 DOM 更新mounted。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">12.执行beforeRouteEnter守卫中传给 next的回调函数。</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/f09a4b3591c24ce792ae7816d7c65642.jpg" target="_blank"><img alt="前端高频面试题_第16张图片" height="725" src="http://img.e-com-net.com/image/info8/f09a4b3591c24ce792ae7816d7c65642.jpg" width="623" style="border:1px solid black;"></a></p> <p></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>40、vue-router的两种模式histroy和hash的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为什么要有hash 和history?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于Vue这类渐进式前端开发框架,为了构建SPA(单页面应用),需要引入前端路由系统,这也就是Vue-Router存在的意义。前端路由的核心,就在于改变视图的同时不会向后端发出请求。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为了达到这一目的,浏览器当前提供了以下两种支持:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.hash: 即地址栏URL中的 # 符号(此hash不是密码学里的散列运算)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">比如这个URL:http://www.abc.com/#/hello, hash的值为#/hello.它的特点在于hash虽然出现在URL中,但不会被包括在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.history:利用了HTML5 History API中新增的pushState()和replaceState()方法。(需要特定浏览器支持)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">这两个方法应用于浏览器的历史记录栈,在当前已有的back、forward、go的基础上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的URL,但浏览器不会即向后端发送请求。因此可以说,hash模式和histoury模式都是属于浏览器自身的特性,Vue-Router只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一般情景下,hash和history都可以,除非你更在意颜值,#符号夹杂在URL里看起来确实有些不太美丽。如果不想要很丑的hash,我们可以用路由的history模式,这种模式充分利用history pushState API来完成URL跳转,无须重新加载页面。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">调用history.pushState()相比于直接修改hash ,存在以下优势:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.pushState()设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,因此只能设置与当前URL同文档的URL;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.pushState()设置的新URL可以与当前URL一模一样,这样也会把记录添加到栈中;而hash设置的新值必须与原来不一样才会触发动作将记录添加到栈中;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.pushState()通过stateObject参数可以添加任意类型的数据到记录中;而hash只可添加短字符串;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.pushState()可额外设置title属性供后续使用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当然history也不是样样都好。SPA虽然在浏览器里游刃有余,单真要通过URL向后端发起HTTP请求时,两者的差异就来了。尤其在用户手动输入URL后回车,或者刷新(重启)浏览器的时候。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.hash 模式下,仅hash符号之前的内容会被包含在请求中,如http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回404错误。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.history模式下,前端的URL必须和实际向后端发起请求的URL一致。如htttp://www.abc.com/book/id。如果后端缺少对/book/id 的路由处理,将返回404错误</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>浏览器</strong></strong></h2> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、从输入URL到返回页面是怎样一个过程?</strong></strong></span></h4> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/1cc58be3452e4ad59135089bc97cab9d.jpg" target="_blank"><img alt="前端高频面试题_第17张图片" height="424" src="http://img.e-com-net.com/image/info8/1cc58be3452e4ad59135089bc97cab9d.jpg" width="588" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.用户输入ur|并回车</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.浏览器进程检查url,组装协议,构成完整的url</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.浏览器进程通过进程问通信(IPC) 把url请求发送给网络进程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1)进行DNS解析,获取服务器ip地址</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">利用ip地址和服务器建立tcp连接</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">构建请求头信息</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">发送请求头信息</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">服务器响应后,网络进程接收响应头和响应信息,并解析响应内容</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.网络进程解析响应流程:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新进行第4步</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 200响应处理,检查响应类型Content- Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行。后续的渲染,如果是htm则通知浏览器进程准备渲染进程准备进行道染。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.准备渲染进程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器进程检查当前url是否和之前打开的道染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.传输数据、更新状态</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">渲染进程准备好后,浏览器向渲染进程发起"提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道"</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">渲染进程接收完数据后,向浏览器发送“确认提交”</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">)</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、 前进后退的历史状态、更新web页面。</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、浏览器渲染HTML的步骤</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.HTML被HTML解析器解析成DOM Tree, CSS则被CSS解析器解析成CSSOM Tree</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.节点信息计算(重排),这个过程被叫做Layout(Webkit)或者Reflow(Mozilla)。即根据渲染树计算每个节点的几何信息生成布局</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.渲染绘制(重绘),这个过程被叫做(Painting 或者 Repaint)。即根据计算好的信息绘制整个页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.Display显示到屏幕上</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/748518dda30a403489f08e6138c4aeb0.jpg" target="_blank"><img alt="前端高频面试题_第18张图片" height="343" src="http://img.e-com-net.com/image/info8/748518dda30a403489f08e6138c4aeb0.jpg" width="631" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、什么是重绘和重排?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>重排</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当DOM的变化引发了元素几何属性的变化,比如改变元素的宽高,元素的位置,导致浏览器不得不重新计算元素的几何属性,并重新构建渲染树,这个过程称为“重排”</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>重绘:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DOM</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程称,这个过程就是“重绘”</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>会引起重排的操作:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">页面首次渲染。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器窗口大小发生改变——resize事件发生时。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">元素尺寸或位置发生改变——定位、边距、填充、边框、宽度和高度。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">元素内容变化(文字数量或图片大小等等)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">元素字体大小变化。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">添加或者删除可见的DOM元素。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">激活CSS伪类(例如::hover)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置style属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">查询某些属性或调用某些方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优化策略:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少DOM操作</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.最小化DOM访问次数,尽量缓存访问DOM的样式信息,避免过度触发回流。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.如果在一个局部方法中需要多次访问同一个dom,可以在第一次获取元素时用变量保存下来,减少遍历时间。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.用事件委托来减少事件处理器的数量。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.用querySelectorAll()替代getElementByXX()。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少重排</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.避免设置大量的style内联属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.不要使用table布局,因为table中某个元素一旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.尽量少使用display:none可以使用visibility:hidden代替,display:none会造成重排,visibility:hidden只会造成重绘。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.使用resize事件时,做防抖和节流处理。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>css及优化动画</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.少用css表达式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.动画实现的速度的选择。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.开启动画的GPU加速,把渲染计算交给GPU。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、介绍一下浏览器缓存策略?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>什么是浏览器缓存</strong></span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器的缓存机制指的是通过在一段时间内保留已接收到的 web 资源的一个副本,如果在资源的有效时间内,发起了对这个资源的再一次请求,那么浏览器会直接使用缓存的副本,而不是向服务器发起请求。使用 web 缓存可以有效地提高页面的打开速度,减少不必要的网络带宽的消耗。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">web 资源的缓存策略一般由服务器来指定,可以分为两种,分别是强缓存策略和协商缓存策略。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>强缓存</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用强缓存策略时,如果缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求。强缓存策略可以通过两种方式来设置,分别是 http </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">响应</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">头信息中的 Expires 属性和 Cache-Control 属性。其中Cache-Control优先级比Expires高。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">服务器通过在响应头中添加 Expires 属性,来指定资源的过期时间。在过期时间以内,该资源可以被缓存使用,不必再向服务器发送请求。这个时间是一个绝对时间,它是服务器的时间,因此可能存在这样的问题,就是客户端的时间和服务器端的时间不一致,或者用户可以对客户端时间进行修改的情况,这样就可能会影响缓存命中的结果。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Expires 是 http1.0 中的方式,因为它的一些缺点,在 http 1.1 中提出了一个新的头部属性就是 Cache-Control 属性,它提供了对资源的缓存的更精确的控制。它有很多不同的值,常用的比如我们可以通过设置 max-age 来指定资源能够被缓存的时间的大小,这是一个相对的时间,它会根据这个时间的大小和资源第一次请求时的时间来计算出资源过期的时间,因此相对于 Expires来说,这种方式更加有效一些。常用的还有比如 private ,用来规定资源只能被客户端缓存,不能够代理服务器所缓存。还有如 no-store ,用来指定资源不能够被缓存,no-cache 代表该资源能够被缓存,但是立即失效,每次都需要向服务器发起请求。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一般来说只需要设置其中一种方式就可以实现强缓存策略,当两种方式一起使用时,Cache-Control 的优先级要高于 Expires 。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>协商缓存</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用协商缓存策略时,会先向服务器发送一个请求,如果资源没有发生修改,则返回一个 304 状态,让浏览器使用本地的缓存副本。如果资源发生了修改,则返回修改后的资源。协商缓存也可以通过两种方式来设置,分别是 http 头信息中的 Etag 和 Last-Modified 属性。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">服务器通过在响应头中添加 Last-Modified 属性来指出资源最后一次修改的时间,当浏览器下一次发起请求时,会在请求头中添加一个 If-Modified-Since 的属性,属性值为上一次资源返回时的 Last-Modified 的值。当请求发送到服务器后服务器会通过这个属性来和资源的最后一次的修改时间来进行比较,以此来判断资源是否做了修改。如果资源没有修改,那么返回 304 状态,让客户端使用本地的缓存。如果资源已经被修改了,则返回修改后的资源。使用这种方法有一个缺点,就是 Last-Modified 标注的最后修改时间只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,那么文件已将改变了但是 Last-Modified 却没有改变,这样会造成缓存命中的不准确。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为 Last-Modified 的这种可能发生的不准确性,http 中提供了另外一种方式,那就是 Etag 属性。服务器在返回资源的时候,在头信息中添加了 Etag 属性,这个属性是资源生成的唯一标识符,当资源发生改变的时候,这个值也会发生改变。在下一次资源请求时,浏览器会在请求头中添加一个 If-None-Match 属性,这个属性的值就是上次返回的资源的 Etag 的值。服务接收到请求后会根据这个值来和资源当前的 Etag 的值来进行比较,以此来判断资源是否发生改变,是否需要返回资源。通过这种方式,比 Last-Modified 的方式更加精确。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当 Last-Modified 和 Etag 属性同时出现的时候,Etag 的优先级更高。使用协商缓存的时候,服务器需要考虑负载平衡的问题,因此多个服务器上资源的 Last-Modified 应该保持一致,因为每个服务器上 Etag 的值都不一样,因此在考虑负载平衡时,最好不要设置 Etag 属性。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>总结</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,若强制缓存(Expires和Cache-Control)生效则直接使用缓存</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">资源</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">和标识</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,再存入浏览器缓存中;生效则返回304,继续使用缓存</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/6043bcfdf73a4bbf8c918bb08ef4c917.jpg" target="_blank"><img alt="前端高频面试题_第19张图片" height="624" src="http://img.e-com-net.com/image/info8/6043bcfdf73a4bbf8c918bb08ef4c917.jpg" width="650" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、V8引擎如何执行一段js代码</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>预解析:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">检查语法错误但不生成AST</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>生成AST:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">经过词法/语法分析,生成抽象语法树</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>生成字节码:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">基线编译器(Ignition)将AST转换成字节码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>生成机器码:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优化编译器(Turbofan)将字节码转换成优化过的机器码,此外在逐行执行字节码的过程中,如果一段代码经常被执行,那么V8会将这段代码直接转换成机器码保存起来,下一次执行就不必经过字节码,优化了执行速度</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、介绍一下引用计数和标记清除</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>引用计数:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">给一个变量赋值引用类型,则该对象的引用次数+1,如果这个变量变成了其他值,那么该对象的引用次数-1,垃圾回收器会回收引用次数为0的对象。但是当对象循环引用时,会导致引用次数永远无法归零,造成内存无法释放。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>标记清除:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">垃圾收集器先给内存中所有对象加上标记,然后从根节点开始遍历,去掉被引用的对象和运行环境中对象的标记,剩下的被标记的对象就是无法访问的等待回收的对象。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、V8如何进行垃圾回收</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">栈内存调用栈上下文切换后就被回收,比较简单</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">V8的堆内存分为新生代内存和老生代内存,新生代内存是临时分配的内存,存在时间短,老生代内存存在时间长</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>新生代内存回收机制</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">新生代内存容量小,64位系统下仅有32M。新生代内存分为From、To两部分,进行垃圾回收时,先扫描From,将非存活对象回收,将存活对象顺序复制到To中,之后调换From/To,等待下一次回收</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>老生代内存回收机制</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">晋升:如果新生代的变量经过多次回收依然存在,那么就会被放入老生代内存中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">标记清除:老生代内存会先遍历所有对象并打上标记,然后对正在使用或被强引用的对象取消标记,回收被标记的对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">整理内存碎片:把对象挪到内存的一端</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、如何加快首屏速度</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少 HTTP 请求数</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">合并 JavaScript、CSS 等文件,将浏览器一次访问需要的javascript和CSS合并成一个文件,这样浏览器就只需要一次请求。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用CSS Sprite:将背景图片合并成一个文件,通过background-image 和 background-position 控制显示。逐步被 Icon Font 和 SVG Sprite 取代。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">内容分片,将请求划分到不同的域名上。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">LazyLoad Images (这条策略实际上并不一定能减少 HTTP请求数,但是却能在某些条件下或者页面刚加载时减少 HTTP请求数)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用浏览器缓存,将CSS、javascript、logo、图标这些更新频率较低的静态资源文件缓存在浏览器中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少 DNS 查询</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">首次访问、没有相应的 DNS 缓存时,域名越多,查询时间越长。所以应尽量减少域名数量。但基于并行下载考虑,把资源分布到 2 个域名上(最多不超过 4 个)。这是减少 DNS 查询同时保证并行下载的折衷方案。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>避免重定向</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">客户端收到服务器的重定向响应后,会根据响应头中 Location 的地址再次发送请求。重定向会影响用户体验,尤其是多次重定向时,用户在一段时间内看不到任何内容,只看到浏览器进度条一直在刷新。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>缓存 Ajax 请求</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">最重要的的优化方式是缓存响应结果</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>延迟加载 | 延迟渲染</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将首屏以外的 HTML 放在不渲染的元素中,如隐藏的 <textarea></span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,或者 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">type</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 属性为非执行脚本的 </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><script></span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 标签中,减少初始渲染的 DOM 元素数量,提高速度。等首屏加载完成或者用户操作时,再去渲染剩余的页面内容。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>预先加载</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">预先加载利用浏览器空闲时间请求将来要使用的资源,以便用户访问下一页面时更快地响应。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少 DOM 元素数量</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">复杂的页面不仅下载的字节更多,JavaScript DOM 操作也更慢。例如,同是添加一个事件处理器,500 个元素和 5000 个元素的页面速度上会有很大区别。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>划分内容到不同域名</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器一般会限制每个域的并行线程(一般为 6 个,甚至更少),使用不同的域名可以最大化下载线程,但注意保持在 2-4 个域名内,以避免 DNS 查询损耗。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>尽量减少 iframe 使用</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用 iframe 可以在页面中嵌入 HTML 文档,但有利有弊。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>避免 404 错误</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一些网站设计很酷炫、有提示信息的 404 页面,有助于提高用户体验,但还是浪费服务器资源。尤其糟糕的是外部脚本返回 404,不仅阻塞其他资源下载,浏览器还会尝试把 404 页面内容当作 JavaScript 解析,消耗更多资源。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用 CDN</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">相比分布式架构的复杂和巨大投入,静态内容分发网络(CDN)可以以较低的投入,获得加载速度有效提升。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>启用 Gzip</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Gzip 压缩通常可以减少 70% 的响应大小,对某些文件更可能高达 90%,比 Deflate 更高效。主流 Web 服务器都有相应模块,而且绝大多数浏览器支持 gzip 解码。所以,应该对 HTML、CSS、JS、XML、JSON 等文本类型的内容启用压缩。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>避免图片 src 为空</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">虽然 src</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 属性为空字符串,但浏览器仍然会向服务器发起一个 HTTP 请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少 Cookie 大小</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Cookie 被用于身份认证、个性化设置等诸多用途。Cookie 通过 HTTP 头在服务器和浏览器间来回传送,减少 Cookie 大小可以降低其对响应速度的影响。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>把样式表放在 head 中</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把样式表放在 <head> 中可以让页面渐进渲染,尽早呈现视觉反馈,给用户加载速度很快的感觉。这对内容比较多的页面尤为重要,用户可以先查看已经下载渲染的内容,而不是盯着白屏等待。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>不要使用 CSS 表达式</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS 表达式可以在 CSS 里执行 JavaScript,仅 IE5-IE7 支持,IE8 标准模式已经废弃。CSS 表达式超出预期的频繁执行,页面滚动、鼠标移动时都会不断执行,带来很大的性能损耗。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用 link标签替代 @import</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于 IE 某些版本,@import 的行为和 <link> 放在页面底部一样。所以,不要用它</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>把脚本放在页面底部</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器下载脚本时,会阻塞其他资源并行下载,即使是来自不同域名的资源。因此,最好将脚本放在底部,以提高页面加载速度。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用外部 JavaScript 和 CSS</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">外部 JavaScript 和 CSS 文件可以被浏览器缓存,在不同页面间重用,也能降低页面大小。当然,实际中也需要考虑代码的重用程度。如果仅仅是某个页面使用到的代码,可以考虑内嵌在页面中,减少 HTTP 请求数。另外,可以在首页加载完成以后,预先加载子页面的资源。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>移除重复脚本</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">重复的脚本不仅产生不必要的 HTTP 请求,而且重复解析执行浪费时间和计算资源。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>减少 DOM 操作</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">JavaScript 操作 DOM 很慢,尤其是 DOM 节点很多时。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、浏览器内核</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>定义</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器最重要或者说核心的部分是“Rendering Engine”,可大概译为“渲染引擎”,不过我们一般习惯将之称为“浏览器内核”。负责对网页语法的解释(如标准通用标记语言</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">下的一个应用HTML、JavaScript)并渲染网页。 所以,通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解释也有不同,因此同一网页在不同的内核的浏览器里的渲染效果也可能不同,这也是网页编写者需要在不同内核的浏览器中测试网页显示效果的原因。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>常见的浏览器内核</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE浏览器:Trident内核,也是俗称的IE内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Firefox浏览器:Gecko内核,俗称Firefox内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Safari浏览器:Webkit内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Opera浏览器:最初是自己的Presto内核,后来是Webkit,现在是Blink内核</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Chrome浏览器:以前是Webkit内核,现在是Blink内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">360浏览器、猎豹浏览器:IE+Chrome双内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">搜狗、遨游、QQ浏览器:Trident(兼容模式)+Webkit(高速模式);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">百度浏览器、世界之窗:IE内核;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2345浏览器:以前是IE内核,现在也是IE+Chrome双内核</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、浏览器兼容问题</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.不同浏览器的标签默认的margin和padding不同</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:css 里增加通配符 * { margin: 0; padding: 0; }</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.文字大小不一致字体大小在不同浏览上不一致。例如font-size:14px,在 IE 中的实际行高是16px,下面有3px留白;在 Firefox 中的实际行高是17px,下面有3px留白,上边1px留白;在 opera 中就更不一样了。</span></span></p> <pre><code class="language-css"> html { font-size: 14px; line-height: 14px; }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:设置display:inline;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.图片默认有间距</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:使用float 为img 布局(所有图片左浮)</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.IE9以下浏览器不能使用opacity</span></span></p> <pre><code class="language-css"> .box { /* 一点其他的样式... */ background-color: #000; opacity: 0.5; /* 兼容Firefox浏览器 */ -moz-opacity: 0.5; filter: alpha(opacity=50); /* IE6 */ filter: progid:DXImageTransform.Microsoft.Alpha(style=0, opacity=50);</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.边距重叠问题;当相邻两个元素都设置了margin 边距时,margin 将取最大值,舍弃最小值;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:为了不让边重叠,可以给子元素增加一个父级元素,并设置父级元素为overflow:hidden;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.cursor:hand 显示手型在safari 上不支持</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:统一使用 cursor:pointer</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9.两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:父级元素设置position:relative</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">10</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">.css3新属性,加浏览器前缀兼容早期浏览器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-moz-</span></span> <span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">火狐浏览器 </span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-webkit- </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> Safari, 谷歌浏览器等使用Webkit引擎的浏览器 </span></span> <br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-o- Opera</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器(早期) </span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">-ms- </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">11.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE8以下不支持CSS3的background-size属性。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用滤镜</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">filter</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">12.const问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Firefox下,可以使用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">const</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">关键字来定义常量;IE下,只能使用var关键字来定义常量。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">统一使用var关键字来定义常量。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">13.Firefox不支持innerText解决方案:使用</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">textContent:</span></span></p> <pre><code class="language-javascript"> if (navigator.appName.indexOf("Explorer") > -1) { document.getElementById('element').innerText = "text"; } else { document.getElementById('element').textContent = "text"; }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">14.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">事件绑定</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE: </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">dom.attachEvent()</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">标准浏览器: dom.addEventListener(‘click’,function(event){},false);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">15.event事件对象问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:var e = e||window.event</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">16.event事件源对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方案:va</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">r </span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">srcObj = event.srcElement?event.srcElement:event.target</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">17.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">IE浏览器div最小宽度和</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">最小</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">高度</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不生效</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">的问题IE不认得min-这个定义,但实际上它把正常的width和height当作有min的情况来使。这样问题就大了,如果只用宽度和高度,正常的浏览器里这两个值就不会变,如果只用min-width和min-height的话,IE下面根本等于没有设置宽度和高度。比如要设置背景图片,这个最小宽度是比较重要的。</span></span></p> <pre><code class="language-css"> #box { width: 80px; height: 35px; } html>body #body { width: auto; height: auto; min-width: 80px; min-height: 35px; }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">18</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">. 超链接访问过后hover样式就不出现的问题被点击访问过的超链接样式不在具有hover和active了,很多人应该都遇到过这个问题,解决技巧是改变CSS属性的排列顺序: L-V-H-A</span></span></p> <pre><code class="language-css">a:link {} a:visited {} a:hover {} a:active {}</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9. css hack解决浏览器兼容性不同浏览器,识别不同的样式,csshack本身就是处理浏览器兼容的</span></span></p> <pre><code class="language-css"> /* 0是留给ie8的 */ background-color: yellow0; /* + ie7定了 */ +background-color: pink; /* _专门留给神奇的ie6 */ _background-color: orange;</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">20.获取元素的非行间样式值</span></span></p> <pre><code class="language-javascript"> //获取元素属性值的兼容写去 function getStyle(obj, attr) { if (obj.currentStyle) { //兼容IE obj.currentStyle[attr]; return obj.currentstyle[attr]; } else { //IE return window.getComputedStyle(obj, null)[attr]; } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">21.阻止事件冒泡传播</span></span></p> <pre><code class="language-javascript"> // js阻止事件传播,这里使用click事件为例 document.onclick = function (e) { var e = e || Window.event; if (e.stopPropagation) { e.stopPropagation(); // W3C标准 } else { e.cancelBubble = true; // IE... . } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">22.阻止事件默认行为</span></span></p> <pre><code class="language-javascript"> // js阻止默认事件,一般阻止a链接href, form表单submit提交 document.onclick = function (e) { var e = e || Window.event; if (e.preventDefault) { e.preventDefault(); // W3C标准 } else { e.returnValue = false; // IE... . } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">23.ajax兼容问题</span></span></p> <pre><code class="language-javascript"> var oAjax = null; if (window.XMLHttpRequest) { oAjax = new XMLHttpRequest(); } else { //只支持E6浏览器 oAjax = new ActiveXObject("Microsoft.XMLHTTP"); }</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、同源策略,跨域</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>同源策略</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>同源限制</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">无法接触非同源网页的 DOM</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">无法向非同源地址发送 AJAX 请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>解决方案</strong></span></span></strong></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.设置相同的document.domain,两个页面就可以共享Cookie(此方案仅限主域相同,子域不同的跨域应用场景。)</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.调用postMessage方法实现父窗口http://test1.com向子窗口http://test2.com发消息(子窗口同样可以通过该方法发送消息给父窗口)</span></span></p> <pre><code class="language-javascript">// 父窗口打开一个子窗口 var openWindow = window.open('http://test2.com', 'title'); // 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url) openWindow.postMessage('Nice to meet you!', 'http://test2.com');</code></pre> <pre><code class="language-javascript">// 监听 message 消息 window.addEventListener('message', function (e) { console.log(e.source); // e.source 发送消息的窗口 console.log(e.origin); // e.origin 消息发向的网址 console.log(e.data); // e.data 发送的消息 },false);</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.jsonp</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">核心思想:网页通过添加一个<script>元素,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。原生ajax</span></span></p> <pre><code class="language-html"><script src="http://test.com/data.php?callback=dosomething"></script> // 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字 // 处理服务器返回回调函数的数据 <script type="text/javascript"> function dosomething(res){ // 处理获得的数据 console.log(res.data) } </script></code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">jQuery ajax</span></span></p> <pre><code class="language-javascript">$.ajax({ url: 'http://www.test.com:8080/login', type: 'get', dataType: 'jsonp', // 请求方式为jsonp jsonpCallback: "handleCallback", // 自定义回调函数名 data: {} });</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue-resource</span></span></p> <pre><code class="language-javascript">this.$http.jsonp('http://www.domain2.com:8080/login', { params: {}, jsonp: 'handleCallback' }).then((res) => { console.log(res); })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.cors</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2、带cookie跨域请求:前后端都需要进行设置</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端设置根据xhr.withCredentials字段判断是否带有cookie</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原生ajax</span></span></p> <pre><code class="language-javascript">var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容 // 前端设置是否带cookie xhr.withCredentials = true; xhr.open('post', 'http://www.domain2.com:8080/login', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('user=admin'); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } };</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">jQuery ajax</span></span></p> <pre><code class="language-javascript">$.ajax({ url: 'http://www.test.com:8080/login', type: 'get', data: {}, xhrFields: { withCredentials: true // 前端设置是否带cookie }, crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie }); </code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">vue-resource</span></span></p> <pre><code class="language-javascript">Vue.http.options.credentials = true</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">axios </span></span></p> <pre><code class="language-javascript">axios.defaults.withCredentials = true</code></pre> <p></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>网络</strong></strong></h2> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、网络七层模型</strong></strong></span></h4> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/e72ed443b2e44e9e9ba39f6f3a9470d5.jpg" target="_blank"><img alt="前端高频面试题_第20张图片" height="487" src="http://img.e-com-net.com/image/info8/e72ed443b2e44e9e9ba39f6f3a9470d5.jpg" width="649" style="border:1px solid black;"></a></p> <p></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、常见的http状态码</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>2xx 开头(请求成功)</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">200 OK:客户端发送给服务器的请求被正常处理并返回</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>3xx 开头(重定向)</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">301 Moved Permanently:永久重定向,请求的网页已永久移动到新位置。 服务器返回此响应时,会自动将请求者转到新位置</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">302 Moved Permanently:临时重定向,请求的网页已临时移动到新位置。服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">304 Not Modified:未修改,自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>4xx 开头(客户端错误)</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">400 Bad Request:错误请求,服务器不理解请求的语法,常见于客户端传参错误</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">401 Unauthorized:未授权,表示发送的请求需要有通过 HTTP 认证的认证信息,常见于客户端未登录</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">403 Forbidden:禁止,服务器拒绝请求,常见于客户端权限不足</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">404 Not Found:未找到,服务器找不到对应资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>5xx 开头(服务端错误)</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">500 Inter Server Error:服务器内部错误,服务器遇到错误,无法完成请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">501 Not Implemented:尚未实施,服务器不具备完成请求的功能</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">502 Bad Gateway:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">503 service unavailable:服务不可用,服务器目前无法使用(处于超载或停机维护状态)。通常是暂时状态。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、请求报文和响应报文介绍</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>请求报文</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个HTTP请求报文由请求行(request line)、请求头(header)、空行和请求体4个部分组成</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><a href="http://img.e-com-net.com/image/info8/4d05a32634c1407e8d206eed020413b1.jpg" target="_blank"><img alt="前端高频面试题_第21张图片" height="165" src="http://img.e-com-net.com/image/info8/4d05a32634c1407e8d206eed020413b1.jpg" width="466" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>响应报文</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个HTTP响应报文主要由状态行、响应头部、空行和响应正文4部分组成</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><a href="http://img.e-com-net.com/image/info8/7603c4677db8453f8c80f94a0c807227.jpg" target="_blank"><img alt="前端高频面试题_第22张图片" height="177" src="http://img.e-com-net.com/image/info8/7603c4677db8453f8c80f94a0c807227.jpg" width="480" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、http1.0和http1.1有什么区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>长连接:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTTP/1.1支持长连接和请求的流水线,在一个TCP连接上可以传送多个HTTP请求,避免了因为多次建立TCP连接的时间消耗和延时。在HTTP1.1中默认开启Connection : keep-alive ,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>缓存处理:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在HTTP1.0中主要使用header里的If-Modified-Since Expires来做为缓存判断的标准HTTP1.1则引入了更多的缓存控制策略例如Entity</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">tag , If-Unmodified-Since, If-Match, If-None Match等更多可供选择的缓存头来控制缓存策略。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>带宽优化及网络连接的使用:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能, HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206 ( Partial Content) , 这样就方便了开发者自由的选择以便于充分利用带宽和连接。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>错误通知的管理:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在HTTP1.1中新增了24个错误状态响应码,如409( Conflict )表示请求的资源与资源的当前状态发生冲突; 410 ( Gone )表示服务器上的某个资源被永久性的删除。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Host头处理:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址 ,因此,请求消息中的URL并没有传递主机名( hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机( Multi-homed Web Servers) , 并且它们共享一个IP地址。HTTP1.1的请 求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误 ( 400 Bad Request)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、介绍一下http2.0新特性</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>多路复用:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 即多个请求都通过一个TCP连接并发地完成,多路复用即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id ,这样一个连接上可以有多个request ,每个连接的request可以随机的混杂在一起,接收方可以根据request的id将request再归属到各自不同的服务端请求里面。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>服务端推送:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 在http2中,服务端可以在客户端的某个请求后,根据这个请求,主动推送其他的资源。比如一个html页面中还带上可一个css和js的资源请求,http1.x 时,要发送三次请求,在http2中,不用请求三次,服务器发现html中包含了Css和js资源,便会将三个资源都返回给客户端,这样只需要一次通信,就可以获得全部资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>新的二进制格式:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> HTTP/2采用二进制格式传输数据,相比于HTTP/1.1的文本格式,二进制格式具有更好的解析性和拓展性</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>header压缩:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> HTTP/2压缩消息头,减少了传输数据的大小。HTTP1 x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、HTTP2.0的多路复用和HTTP1.X中的长连接</strong></strong><strong><strong>复用有什么区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>HTTP/1.0:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一次请求/响应,建立一个tcp连接,用完关闭,每一个请求都要建立一个tcp连接,也就意味着每个请求都要进行三次握手,这会造成资源的浪费</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>HTTP/1.1长连接:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTTP/1.1支持长连接和请求的流水线,在一个TCP连接上可以传送多个HTTP请求,避免了因为多次建立TCP连接的时间消耗和延时。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>HTTP/1.1管道:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,无办法,也就是人们常说的线头阻塞</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>HTTP/2多路复用:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、http2.0多路复用基本原理以及解决的问题</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>TCP慢启动:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> TCP连接建立后,会经历一个先慢后快的发送过程,就像汽车启动一般,如果我们的网页文件(HTML/JS/CSS/icon)都经过一次慢启动,对性能是不小的损耗。另外慢启动是TCP为了减少网络拥塞的一种策略,我们是没有办法改变的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>多条TCP连接竞争带宽:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 如果同时建立多条TCP连接,当带宽不足时就会竞争带宽,影响关键资源的下载。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>HTTP/1.1队头阻塞:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 尽管HTTP/1.1长链接可以通过一个TCP连接传输多个请求,但同一时刻只能处理一个请求,当前请求未结束前,其他请求只能处于阻塞状态。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">为了解决以上几个问题,HTTP/2一个域名只使用一个TCP连接来传输数据,而且请求直接是并行的、非阻塞的,这就是多路复用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>实现原理:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> HTTP/2引入了一个二进制分帧层,客户端和服务端进行传输时,数据会先经过二进制分帧层处理,转化为一个个带有请求ID的帧,这些帧在传输完成后根据ID组合成对应的数据。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、http和https有何区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1. https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2. http是超文本传输协议,信息是明文传输, https则具有安全性的ssl/ tls加密传输协议</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80 ,后者是443</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4. http的连接很简单,是无状态的; HTTPS协议是由SSL TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.https</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">比</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">http</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">慢,因为</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">https</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">除了</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">tcp</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">握手的三个包,还要加上SSL握手的九个包</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、https是如何进行加密的</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTTP是应用层协议,位于HTTP协议之下是传输协议TCP。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">TCP负责传输,HTTP则定义了数据如何进行包装。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">HTTPS相对于HTTP有哪些不同呢?其实就是在HTTP跟TCP中间加多了一层加密层TLS/SSL。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>什么是TLS/SSL?</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通俗的讲,TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>传输加密的流程</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输,而不是任由数据在复杂而又充满危险的网络上明文裸奔</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>SSL/TLS协议的基本过程是这样的:</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)客户端向服务器端索要并验证公钥。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)双方协商生成"对话密钥"。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)双方采用"对话密钥"进行加密通信。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>非对称加密算法:</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)甲方获取乙方的公钥,然后用它对信息加密。</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)乙方得到加密后的信息,用私钥解密。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、TCP三次握手</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">TCP 协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在 TCP 连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第一次握手,客户端向服务器端发送一个带 SYN 标志的数据包,等待服务器确认</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第二次握手,服务器端向客户端回传一个带有 SYN/ACK 标志的数据包,通知客户端收到了连接请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第三次握手,客户端再次向服务器端回传一个带 ACK 标志的数据包,确认连接,“握手”结束。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>上述每一次握手的作用如下:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第一次握手:客户端发送网络包,服务端收到了</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第二次握手:服务端发包,客户端收到了 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过三次握手,就能确定双方的接收和发送能力是正常的。之后就可以正常通信了</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为什么不是两次握手?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果是两次握手,发送端可以确定自己发送的信息能对方能收到,也能确定对方发的包自己能收到,但接收端只能确定对方发的包自己能收到 无法确定自己发的包对方能收到</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">并且两次握手的话, 客户端有可能因为网络阻塞等原因会发送多个请求报文,延时到达的请求又会与服务器建立连接,浪费掉许多服务器的资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、TCP四次挥手</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1、客户端向服务器发送一个断开连接的请求(不早了,我该走了);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2、服务器接到请求后发送确认收到请求的信号(知道了);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3、服务器向客户端发送断开通知(我也该走了);</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4、客户端接到断开通知后断开连接并反馈一个确认信号(嗯,好的),服务器收到确认信号后断开连接;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第一次挥手:主动关闭方发送一个 FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在 fin 包之前发送出去的数据,如果没有收到对应的 ack 确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第二次挥手:被动关闭方收到 FIN 包后,发送一个 ACK 给对方,确认序号为收到序号+1(与 SYN 相同,一个 FIN 占用一个序号)。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第三次挥手:被动关闭方发送一个 FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第四次挥手:主动关闭方收到 FIN 后,发送一个 ACK 给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>四次挥手的原因</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">服务端在收到客户端断开连接Fin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">报文后,并不会立即关闭连接,而是先发送一个ACK包先告诉客户端收到关闭连接的请求,只有当服务器的所有报文发送完毕之后,才发送FIN报文断开连接,因此需要四次挥手</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、UDP和TCP的区别?应用场景?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1. TCP面向连接(如打电话要先拨号建立连接) ,UDP是无连接的,即发送数据之前不需要建立连接</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流:UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.每一条TCP连接只能是点到点的,UDP支持一对一, 一对多,多对一和多对多的交互通信</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5. TCP首部开销20字节;UDP的首部开销小,只有8个字节</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6. TCP的逻辑通信信道是全双工的可靠信道, UDP则是不可靠信道</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>应用场景</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">TCP 应用场景适用于对效率要求低,对准确性要求高或者要求有链接的场景,而UDP 适用场景为对效率要求高,对准确性要求低的场景</span></span></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/1b23483cd3bd4131950769d297a0de88.jpg" target="_blank"><img alt="前端高频面试题_第23张图片" height="300" src="http://img.e-com-net.com/image/info8/1b23483cd3bd4131950769d297a0de88.jpg" width="585" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>13、cookie 和 token 都存放在 header 中,为什么不会劫持 token?</strong></strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">原因是浏览器会自动带上cookie,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">而token需要设置header才可</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>xss: </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用户通过各种方式将恶意代码注入到其他用户的页面中。就可以通过脚本</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">劫持cookie或者localStorage</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">等</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">信息,发起请求,之类的操作。从而伪造用户身份相关信息。前端层面token会存在哪儿?不外乎cookie localStorage sessionStorage,这些东西都是通过js代码获取到的。解决方案:过滤标签<>,不信任用户输入, 对用户身份等cookie层面的信息进行http-only处理。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>csxf:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。csrf并不能够拿到用户的任何信息,它只是欺骗用户浏览器,让其以用户的名义进行操作。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。解决方案也很简单,对于cookie不信任,对每次请求都进行身份验证,比如token的处理。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">被xss攻击了,不管是token还是cookie,都能被拿到,所以对于xss攻击来说,cookie和token没有什么区别。但是对于csrf来说就有区别了。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">cookie:用户点击了链接,cookie未失效,导致发起请求后后端以为是用户正常操作,于是进行扣款操作。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">token:用户点击链接,由于浏览器不会自动带上token,所以即使发了请求,后端的token验证不会通过,所以不会进行扣款操作。</span></span></p> <p></p> <h4 style="margin-left:0px;text-align:left;"><strong><strong>14、http请求方法</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.GET方法:发送一个请求来取得服务器上的某一资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.POST方法:向URL指定的资源提交数据或附加新的数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.PUT方法:跟POST方法很像,也是想服务器提交数据。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.HEAD方法:只请求页面的首部</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.DELETE方法:删除服务器上的某资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.OPTIONS方法:它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.TRACE方法:TRACE方法被用于激发一个远程的,应用层的请求消息回路</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.CONNECT方法:把请求连接转换到透明的TCP/IP通道</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><strong><strong>15、get和post的区别</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET在浏览器回退时是无害的,而POST会再次提交请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET产生的URL地址可以被收藏,而POST不可以</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET请求会被浏览器主动缓存,而POST不会,除非手动设置</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET请求只能进行url编码,而POST支持多种编码方式</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET请求参数会被完整保留在浏览器历史记录里, 而PQST中的参数不会被保留</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET请求在URL中传送的参数是有长度限制的,而POST没有限制</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对参数的数据类型,GET只接受ASCII字符,而POST没有限制</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">GET参数通过URL传递,POST放在Request body中</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong><strong>16、WebSocket</strong></strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>WebSocket是什么?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">WebSocket 是一种网络通信协议。RFC6455定义了它的通信标准。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>为什么需要WebSocket?</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如 浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式 对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因此,随着HTML5的诞生,一种新的通信协议应运而生---WebSocket,他最大的特点就是服务端可以主动向客户端推送消息,客户端也可以主动向服务端发送消息,实现了真正的平等。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>WebSocket的特点</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)建立在 TCP 协议之上,服务器端的实现比较容易。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)数据格式比较轻量,性能开销小,通信高效。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)可以发送文本,也可以发送二进制数据。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(5)没有同源限制,客户端可以与任意服务器通信。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>在vue中创建websocket</strong></span></span></strong></p> <pre><code class="language-html"><template> <div> <el-input v-model="params" clearable/> <el-button type="primary" @click="send">发消息</el-button> </div> </template> <script> export default { data() { return { params: '', path: "ws://localhost:8080/websocket", socket: "" } }, mounted() { // 初始化 this.init() }, destroyed() { // 销毁监听 this.socket.onclose = this.close }, methods: { init: function () { if (typeof (WebSocket) === "undefined") { console.log("您的浏览器不支持socket") } else { // 实例化socket this.socket = new WebSocket(this.path) // 监听socket连接成功回调 this.socket.onopen = this.open // 监听socket连接失败回调 this.socket.onerror = this.error // 监听后台返回的socket消息 this.socket.onmessage = this.getMessage } }, open: function () { console.log("socket连接成功") }, error: function () { console.log("连接错误") }, getMessage: function (msg) { console.log(msg.data) }, send: function () { this.socket.send(params) }, close: function () { console.log("socket已经关闭") } } } </script></code></pre> <p></p> <p></p> <hr> <h2> <strong><strong>Webpack</strong></strong></h2> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、前端工程化?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>什么是工程化?</strong></span></span></strong></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">前端工程本质上是软件工程的一种。软件工程化关注的是性能、稳定性、可用性、可维护性等方面,注重基本的开发效率、运行效率的同时,思考维护效率。一切以这些为目标的工作都是“前端工程化”。工程化是一种思想而不是某种技术。</span></span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、web标准—可用性、可维护性、可访问性</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>可用性:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可用性指的是:产品是否容易上手,用户能否完成任务,效率如何,以及这过程中用户的主观感受可好,是从用户的角度来看产品的质量。可用性好意味着产品质量高,是企业的核心竞争力。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>可维护性:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可维护性一般包含两个层次,一是当系统出现问题时,快速定位并解决问题的成本,成本低则可维护性好。二是代码是否容易被人理解,是否容易修改和增强功能。可维护性和可复用性、可扩展性等有交叉的地方。构建可维护性好的代码,对企业的长期发展非常重要。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>可访问性:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Web内容对于残障用户的可阅读和可理解性。提高可访问性也能让普通用户更容易理解Web内容。具体而言,要考虑以下两方面:</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.无论用户是否残障,都得通过用户代理(User Agent)来访问Web内容。因此要提高可访问性,首先得考虑各种用户代理 :桌面浏览器、语音浏览器、移动电话、车载个人电脑等等。在Google, 专门聘请了一些残障雇员,来帮助提高产品的可访问性。</span></span></p> <p style="text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.还得考虑用户访问Web内容时的环境限制 。比如:嘈杂的环境、过暗或过亮的房间、或者是免提等各种情况。这是更高一层次的可访问性要求,做到了,能造就产品在特定领域的核心竞争力。</span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>3、什么是模块化</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">所谓的模块化开发就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能。模块化开发的基础就是函数</span></span> </p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、为什么模块很重要</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。 但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套</span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、模块化发展历程</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>全局</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>函数</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>模式</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将不同的功能封装成不同的全局函数,使用的时候,直接调用就行了。这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。</span></span> </p> <pre><code class="language-javascript">function func1() { // ... } function func2() { // ... }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用对象封装</strong></span></span></strong><strong> </strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把模块写成一个对象,所有的模块成员都放到这个对象里面。减少了全局变量,解决命名冲突,缺点是变量可以被外面随意改变而导致数据不安全</span></span></p> <pre><code class="language-javascript"> var obj = { age: 0, func1: function () { // ... }, func2: function () { // ... } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>IIFE模式:匿名函数自调用(闭包)</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用"立即执行函数"(Immediately-Invoked FunctionExpression,IIFE),可以达到不暴露私有成员的目的。这个也是闭包处理的一种方式。</span></span></p> <pre><code class="language-javascript"> var obj = (function () { var age = 0 var func1 = function () { // ... }; var func2 = function () { //... }; return { m1: func1, m2: func2 }; })(); // 使用 上面的写法,外部代码无法读取内部的age变量 console.info(obj.age); // undefined</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>放大模式</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。在原有的基础上扩展更多的方法。下面的代码为obj模块添加了一个新方法func3 (),然后返回新的obj模块,方便方法连续调用</span></span></p> <pre><code class="language-javascript"> var obj = (function (mod) { mod.func3 = function () { // ... } return mod; // 方便方法连续调用 })(obj); </code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>宽放大模式(Loose augmentation)</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上面的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"</span></span></p> <pre><code class="language-javascript"> var obj = (function (mod) { // ... return mod; })(window.obj||{}); // 确保对象不为空</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>输入全局变量</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。为了在模块内部调用全局变量,必须显式地将其他变量输入模块这是jQuery框架的源码,将window对象作为参数传入,这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显</span></span></p> <pre><code class="language-javascript"> (function (window, undefined) { // ... })(window); </code></pre> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">目前流行的js模块化规范有CommonJS、AMD、CMD以及ES6的模块系统</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>6、前端模块化规范</strong></strong><strong><strong>—Comm</strong></strong><strong><strong>onJS</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>CommonJS的出发点:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> JS没有完善的模块系统,标准库较少,缺少包管理工具。伴随着NodeJS的兴起,能让JS在任何地方运行,特别是服务端,也达到了具备开发大型项目的能力,所以CommonJS营运而生。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Node. js是commonJS规范的主要实践者,它有四个重要的环境变量为模块化的实现提供支持: module、exports、require、global。实际使用时,用module.exports定义当前模块对外输出的接口(不推荐直接用exports ) , 用require加载模块。</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">commonJS用同步的方式加载模块。在服务端,模块文件都存在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>暴露模块:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> module.exports = value或exports.XXX = value</span></span></p> <p style="margin-left:0;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>引入模块:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">require (xxx)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>CommonJS规范</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个文件就是一个模块,拥有单独的作用域</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">普通方式定义的变量、函数、对象都属于该模块内</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过require来加载模块</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过exports和module.exports来暴露块中的内容</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>注意</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.当exports和module.exports同时存在时,module.exports会覆盖exports</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.当模块内全是exports时,就等同于module.exports</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.exports就是module.exports的子集</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.所有代码都运行在模块作用域,不会污染全局作用域</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.模块可以多次加载,但只会在第一次加载时候运行,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.模块加载顺序,按照代码出现的顺序同步加载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.__dirname代表当前文件所在的文件夹路径</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.__ filename代表当前模 块文件所在的文件夹路径+文件名</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>7、</strong></strong><strong><strong>前端模块化规范—</strong></strong><strong><strong>ES6模块化</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6在语言标准的层面上,实现了模块功能,而且实现得相当简单,旨在成为浏览器和服务器通用的模块解决方案。其模块功能主要由两个命令构成: export和</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">import。export 命令于规定模块的对外接口,import命令用于输入其他模块提供的功能。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">其实ES6还提供了export default命令,为模块指定默认输出,对应的import语句不需要使用大括号。这也更趋近于AMD的引用写法。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6的模块不是对象,import命令会被JavaScript引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>export</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">export可以导出的是一个对象中包含的多个属性、方法。export default只能导出一个可以不具名的函数。我们可以通过import进行引用。同时,我们也可以直接使用require使用,原因是webpack起了server相关。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>import</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1. import {fn} from 'xxxxxx ( export导出方式的引用方式)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2. import fn from '/xxx /xxx1' ( export default导出方式的引用方式)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>8、</strong></strong><strong><strong>前端模块化规范—</strong></strong><strong><strong>AMD</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Asynchronous Module Definition,异步加载模块。它是一个在浏览器端模块化开发的规范,不是原生js的规范,使用AMD规范进行页面开发需要用到对应的函数库,RequireJS.</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用requirejs实现AMD规范的模块化,用require.config()指定引用路径等用define()定义模块,用require ()加载模块。</span></span></p> <pre><code class="language-javascript"> // 定义模块 define('moduleName', ['a', 'b'], function (ma, mb) { return someExportValue; }) // 引入模块 require(['a', 'b'], function (ma, mb) { // code })</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>RequireJS主要解决的问题</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">js加载的时候浏览器会停止页面渲染,加载文件愈多,页面响应事件就越长</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">异步前置加载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>语法</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">define (id, dependencies, factory)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">id可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名( 去掉拓展名)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">dependencies 是一个当前模块用来的模块名称数组</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">f</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">actory工厂方法,模块初始化要执行的函数或对象,如果为函数,它应该只被执行一次,如果是对象,此对象应该为模块的输出值。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>9、前端模块化规范—CMD</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CMD是另一种js模块化方案,它与AMD很类似,不同点在于AMD推崇依赖前置、提前执行 , CMD推崇依赖就近、延迟执行。此规范其实是在seajs推广过程中产生的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因为CMD推崇一个文件一 个模块,所以经常就用文件名作为模块id; CMD推祟依赖就近,所以一般不在define的参数中写依赖,而是在factory中写。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">define(id, deps, factory)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">factory有三个参数:function(require,exports,module) {}</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">require 是factory函数的第一个参数,require是-个方法,接受模块标识作为唯一参数,用来获取其他模块提供的接口;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">exports 是一个对象,用来向外提供模块接口;module module是一个对象 ,上面存储了与当前模块相关联的一-些属性和方法。</span></span></p> <pre><code class="language-javascript"> //定义没有依赖的模块 define(function (require, exports, module) { exports.xxx = vaule; module.exports = value; }) //定义有依赖的模块 define(function (require, exports, module) { //同步引入模块 var module1 = require("./module1.js"); //异步引入模块 require.async("./module2.js", function (m2) {}) // 暴露接口 exports.xxx = value; }) //引入模块 define(function (require) { const m1 = require("./module1.js"); m1.show(); })</code></pre> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>10、前端模块化规范—UMD</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一种整合了CommonJS和AMD规范的方法,希望能解决跨平台模块方案</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>运行原理</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">UMD先判断是否支持Node.js的模块( exports)是否存在,存在则使用Nodejs模块模式再判断是否支持AMD ( define是否存在),存在则使用AMD方式加载模块</span></span></p> <pre><code class="language-javascript"> (function (window, factory) { if (typeof exports === 'object') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define(factory); } else { window.eventUtil = factory(); } })(this, function () { //module ... });</code></pre> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>11、前端模块化规范—总结</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">commonjs是同步加载的。主要是在nodejs也就是服务端应用的模块化机制,通过module.export导出声明,通过require('') 加载。每个文件都是一个模块。他有自己的作用域,文件内的变量,属性函数等不能被外界访问。node会将模块缓存, 第二次加载会直接在缓存中获取。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">AMD是异步加载的。主要应用在浏览器环境下。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">requireJS是遵循AMD规范的模块化工具。他是通过define ()定义声明通过</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">require('', function(){})加载。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6的模块化加载时通过export 导出,用import导入可通过{}对导出的内容进行解构。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6的模块的运行机制与common不-样, js引擎对脚本静态分析的时候,遇到模块加载指令后会生成一个只读引用,等到脚本真正执行的时候才会通过引用去模块中获取值,在引用到执行的过程中模块中的值发生了变化,导入的这里也会跟着变, ES6模块是动态引用,并不会缓存值,模块里总是绑定其所在的模块。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>12、什么是webpack? 解决了什么问题?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">webpack是一个打包工具,他的宗旨是一切静态资源皆可打包。有人就会问为什么要webpack?webpack是现代前端技术的基石,常规的开发方式,比如jquery,html,css静态网页开发已经落后了。现在是MVVM的时代,数据驱动界面。webpack它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>模块化工具的出现原因</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">模块化开发会划分出很多的模块文件,前端应用运行在浏览器中,所有文件都需要从服务器请求回来,因此必然会导致浏览器频繁发送网络请求,影响应用的工作效率。 前端项目中的 HTML CSS 这些资源文件也需要被模块化处理。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>工具需要具备的能力</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把 ES6 代码编译成浏览器能解析的 ES5 代码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">把各种文件HTML、CSS、JS 图片等分别打包到一起,这样就不用频繁发送网络请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">模块化只在开发阶段需要,能更好地组织我们的代码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>Webpack 解决的问题</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在前端项目中高效地管理和维护项目中的每一个资源</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>13、Webpack 四个核心概念</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">entry(入口):入口起点(可以有多个),webpack会从该起点出发,找出哪些文件是入口文件所依赖的,从而构建内部依赖关系图,并处理后输出到称之为bundles的文件中</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">output(输出):指定经入口起点处理后的bundles文件的输出路径(path)和名字(filename)</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">loader(加载器):webpack 自身只能识别js文件,但是开发中会有css,图片等静态文件,webpack虽然自身不能识别,但是可以通过loader来处理;实现css、图片等文件的打包。</span></span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">plugins(插件):从打包优化和压缩,一直到重新定义环境中的变量</span></span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>14、Webpack原理(执行流程)</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">webpack启动后会在entry里配置的module开始递归解析entry所依赖的所有module,每找到一个module, 就会根据配置的loader去找相应的转换规则,对module进行转换后在解析当前module所依赖的module,这些模块会以entry为分组,一个entry和所有相依赖的module也就是一个chunk,最后webpack会把所有chunk转换成文件输出,在整个流程中webpack会在恰当的时机执行plugin的逻辑</span></span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>1)初始化参数</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从配置文件和Shell语句中读取与合并参数,得出最终的参数</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>2)开始编译</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>3)确定入口</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据配置中的entry找出所有的入口文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>4)编译模板</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从入口文件出发,调用所有配置的Loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>5)模块编译完成</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在经过第4步使用Loader翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>6)输出资源</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk ,再把每个Chunk转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>7)输出完成</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>8)其它</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">整个过程中特定的时间点广播事件,插件可以进行监听和处理</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>15、什么是loader</strong></strong><strong><strong>?解决了什么问题?</strong></strong></span></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">webpack</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">内部中,任何文件都是模块,不仅仅只是js文件</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">默认情况下,在遇到import或者load加载模块的时候,webpack只支持对js文件打包</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">像css、sass、png等这些类型的文件的时候,webpack则无能为力,这时候就需要配置对应的loader进行文件内容的解析</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">loader是文件加载器,能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">处理一个文件可以使用多个loader,loader的执行顺序和配置中的顺序是相反的,即最后一个loader最先执行,第一个loader最后执行</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">第一个执行的loader接收源文件内容作为参数,其它loader接收前一个执行的loader的返回值作为参数,最后执行的loader会返回此模块的JavaScript源码</span></span></p> <p></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>16、常见的loader</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.file-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文件加载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.url-loader:文件加载,可以设置阈值,小于时把文件base64编码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.image-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">加载并压缩图片</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.json-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">webpack默认包含了</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.babel-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ES6+转成ES5</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.ts-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将ts转成js </span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.awesome-typescript-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">比上面那个性能好</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.css-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">处理@import和url这样的外部资源</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9.style-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在head创建style标签把样式插入</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">10.postcss-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">扩展css语法,使用postcss各种插件autoprefixer , cssnext , cssnano</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">11.eslint-loadertslint-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过这两种检查代码,tslint不再维护,用的eslint</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">12.vue-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">加载vue单文件组件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">13.i18n-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">国际化</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">14.cache-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">性能开销大的1oader前添加,将结果缓存到磁盘</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">15.svg-inline-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">压缩后的svg注入代码;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">16.source-map-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">加载source Map文件,方便调试</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">17.expose-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">暴露对象为全局变量</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">18.imports-loader、exports-loader等可以向模块注入变或者提供导出模块功能</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">19.raw-loader</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可以将文件已字符串的形式返回</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">20.校验测试</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">mocha-loader、jshint-loader 、eslint-loader等</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>17、css-loader和style-loader的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">css-loader处理css文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">style-loader把js中import导入的样式文件代码,打包到js文件中,运行js文件时,将样式自动插入到<style> 标签中</span></span></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>18、file-loader和url-loader的区别</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">file-loader返回的是图片的url</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">url-loader可以通过limit属性对图片分情况处理,当图片小于limit(单位: byte )大小时转base64 ,大于limit时调用file-loader对图片进行处理。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">url-loader封装了file-loader,但url-loader 并不依赖于file-loader</span></span></p> <p></p> <h4><strong><strong><strong>19、什么是plugin</strong></strong><strong><strong>?</strong></strong><strong><strong>解决了什么问题?</strong></strong></strong></h4> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">plugin赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的API改变输出结果。</span></span></p> <p></p> <h4><strong><strong><strong>20、常见的plugin</strong></strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.ignore-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">忽略文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.uglifyjs-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不支持ES6压缩(Webpack4以前使用)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.terser-webpack plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">支持压缩ES6 (Webpack4)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.webpack-parallel-uglify-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">多进程执行代码压缩,提升构建速度</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.mini-css-extract-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">分离样式文件, CSS提取为独立文件,支持按需加载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.serviceworker-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">为网页应用增加离线缓存功能</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">7.clean-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">目录清理</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">8.speed-measure-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">可以看到每个Loader和Plugin执行耗时</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">9.webpack内置UglifyJsPlugin ,压缩和混淆代码。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">10.webpack内置CommonsChunkPlugin,提高打包效率,将第三方库和业务代码分开打包。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">11.ProvidePlugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">自动加载模块,代替require和import</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">12.html-webpack-plugin:可以根据模板自动生成html代码,并自动引用css和js文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">13.extract-tex-webpack-plugin:将js文件中引用的样式单独抽离成css文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">14.DefinePlugin:编译时配置全局变量,这对开发模式和发布模式的构建允许不同的行为非常有用。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">15.HotModuleReplacementPlugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">热更新</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">16.DIPlugin和DIlReferencePluin相互配合,前者第三包的构建,只构建业务代码,同时能解决Externals多次引用问题。DIIRefrencePlugin引用DIPlugin配置生成的manifest.json文件,manifest.json包含了依赖模块和module id的映射关系</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">17.optimize-css-assets-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">不同组件中重复的css可以快速去重</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">18.W</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ebpack-bundle-analyzer</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个webpack的bundle文件分析工具,将bundle文件以可交互缩放的treemap的形式展示。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">19.compression-webpack-plugin</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">铲环境可采用gzip压缩JS和CSS</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">20.happypack</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过多进程模型,来加速代码构建</span></span></p> <p></p> <h4><strong><strong><strong>21、loader和plugin的区别</strong></strong></strong></h4> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/3d75dfcee8e14a38bb9270f321cf556b.jpg" target="_blank"><img alt="前端高频面试题_第24张图片" height="278" src="http://img.e-com-net.com/image/info8/3d75dfcee8e14a38bb9270f321cf556b.jpg" width="578" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对于loader,它是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A. scss转换为A. css,单纯的文件转换过程</span></span></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务</span></span></p> <p></p> <h4><strong><strong><strong>22、webpack编译生命周期钩子</strong></strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">entry-option:初始化 option</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">run</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">compile</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">真正开始的编译,在创建 compilation 对象之前</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">compilation</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">生成好了 compilation 对象</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">make</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">从 entry 开始递归分析依赖,准备对每个模块进行 build</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">after-compile</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">编译 build 过程结束</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">emit</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在将内存中 assets 内容写到磁盘文件夹之前</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">after-emit</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在将内存中 assets 内容写到磁盘文件夹之后</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">done</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">完成所有的编译过程</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">failed</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">编译失败的时候</span></span></p> <p></p> <h4 style="text-align:left;"><strong><strong><strong>23、webpack热更新</strong></strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过webpack-dev-server创建两个服务器:提供静态资源的服务(express)和Socket服务</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">express server 负责直接提供静态资源的服务(打包后的资源直接被浏览器请求和解析)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">socket server 是一个 websocket 的长连接,双方可以通信</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当 socket server 监听到对应的模块发生变化时,会生成两个文件.json(manifest文件)和.js文件(update chunk)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过长连接,socket server 可以直接将这两个文件主动发送给客户端(浏览器)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">6.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">浏览器拿到两个新的文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong><strong>24、Webpack proxy工作原理?为何能实现跨域?</strong></strong></strong></h4> <p style="text-align:left;"></p> <h4 style="text-align:left;"></h4> <p style="margin-left:.0001pt;text-align:left;"><a href="http://img.e-com-net.com/image/info8/82e43aff6545415197477a905adc8f6b.jpg" target="_blank"><img alt="前端高频面试题_第25张图片" height="120" src="http://img.e-com-net.com/image/info8/82e43aff6545415197477a905adc8f6b.jpg" width="332" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在开发阶段, webpack-dev-server 会启动一个本地开发服务器,所以我们的应用在开发阶段是独立运行在 localhost的一个端口上,而后端服务又是运行在另外一个地址上</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">所以在开发阶段中,由于浏览器同源策略的原因,当本地访问后端就会出现跨域请求的问题</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过设置webpack proxy实现代理请求后,相当于浏览器与服务端中添加一个代理者</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常接收数据</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>注意:服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制</strong></span></span></strong></p> <p></p> <h4 style="text-align:left;"><strong><strong><strong>25、如何借助webpack来优化前端性能</strong></strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">关于webpack对前端性能的优化,可以通过文件体积大小入手,其次还可通过分包的形式、减少http请求次数等方式,实现对前端性能的优化</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">JS代码压缩</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSS代码压缩</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Html文件代码压缩</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">文件大小压缩</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">图片压缩</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Tree Shaking</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">代码分离</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">内联 chunk</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong><strong>26、如何提高webpack构建速度</strong></strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">优化webpack构建的方式有很多,主要可以从优化搜索时间、缩小文件搜索范围、减少不必要的编译等方面入手</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优化 loader 配置</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在使用loader时,可以通过配置include、exclude、test属性来匹配文件,接触include、exclude规定哪些匹配应用loader</span></span></p> <pre><code class="language-javascript"> module.exports = { module: { rules: [{ //如果项目源码中只有js文件就不要写成/\.jsx?$/,提升正则表达式性能 test: /\.js$/, // babel-loader 支持缓存转换出的结果,通过cacheDirectory 选项开启 use: ['babel-loader?cacheDirectory'], //只对项目根目录下的src目录中的文件采用babel-loader include: path.resolve(__dirname, 'src'), }, ] }, };</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>合理使用 resolve.extensions</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在开发中我们会有各种各样的模块依赖,这些模块可能来自于自己编写的代码,也可能来自第三方库, resolve可以帮助webpack从每个 require/import 语句中,找到需要引入到合适的模块代码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过resolve.extensions是解析到文件时自动添加拓展名</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当我们引入文件的时候,若没有文件后缀名,则会根据数组内的值依次查找</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">当我们配置的时候,不要随便把所有后缀都写在里面,这会调用多次文件的查找,这样就会减慢打包速度</span></span></p> <pre><code class="language-javascript"> module.exports = { extensions: [".warm", ".mjs", ".js", ".json"] }</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优化 resolve.modules</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">resolve.modules 用于配置 webpack 去哪些目录下寻找第三方模块。默认值为['node_modules'],所以默认会从node_modules中查找文件 当安装的第三方模块都放在项目根目录下的 ./node_modules目录下时,所以可以指明存放第三方模块的绝对路径,以减少寻找</span></span></p> <pre><code class="language-javascript"> module.exports = { resolve: { //使用绝对路径指明第三方模块存放的位置,以减少搜索步骤 //其中__dirname表示当前工作目录,也就是项目根目录 modules: [path.resolve(__dirname, ' node_ modules')] }, };</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>优化 resolve.alias</strong></span></span></strong></p> <p style="margin-left:0;text-align:left;"><span style="background-color:#ffffff;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">alias给一些常用的路径起一个别名,特别当我们的项目目录结构比较深的时候,一个文件的路径可能是./../../的形式</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">通过配置alias以减少查找过程</span></span></span></p> <pre><code class="language-javascript"> module.exports = { ... resolve: { alias: { "@": path.resolve(__dirname, ' ./src') } } }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用 DLLPlugin 插件</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DLL全称是 动态链接库,是为软件在winodw种实现共享函数库的一种实现方式,而Webpack也内置了DLL的功能,为的就是可以共享,不经常改变的代码,抽成一个共享的库。这个库在之后的编译过程中,会被引入到其他项目的代码中</span></span></p> <p><span style="background-color:#ffffff;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">打包一个 DLL 库</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">webpack内置了一个DllPlugin可以帮助我们打包一个DLL的库文件</span></span></strong></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <pre><code class="language-javascript"> module.exports = { ... new webpack.DllPlugin({ name: 'dll_[name]', path: path.resolve(__dirname, "./dll/[name].mainfest.json") }) }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">引入 DLL 库:</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用 webpack 自带的 DllReferencePlugin 插件对 mainfest.json 映射文件进行分析,获取要使用的DLL库</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,然后再通过AddAssetHtmlPlugin插件,将我们打包的DLL库引入到Html模块中</span></span></p> <pre><code class="language-javascript"> module.exports = { ... new webpack.DllReferencePlugin({ context: path.resolve(__dirname, "./dll/dll_react.js"), mainfest: path.resolve(__dirname, "./dll/react.mainfest.json") }), new AddAssetHtmlPlugin({ outputPath: "./auto", filepath: path.resolve(__dirname, "./dll/dll react.js") }) }</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>使用 cache-loader</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">在一些性能开销较大的 loader之前添加 cache-loader,以将结果缓存到磁盘里,显著提升二次构建速度保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用此loader</span></span></p> <pre><code class="language-javascript"> module.exports = { module: { rules: [{ test: /\.ext$/, use: ['cache-loader', ...loaders], include: path.resolve('src'), }, ], }, };</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>terser 启动多线程</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">使用多进程并行运行来提高构建速度</span></span></p> <pre><code class="language-javascript"> module.exports = { optimization: { minimizer: [ new TerserPlugin({ parallel: true, }), ], }, };</code></pre> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>合理使用 sourceMap</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">打包生成 sourceMap 的时候,如果信息越详细,打包速度就会越慢</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">。</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对应属性取值如下所示:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/33b41e1f6c8e46ae9ecc430c43ecab3b.jpg" target="_blank"><img alt="前端高频面试题_第26张图片" height="529" src="http://img.e-com-net.com/image/info8/33b41e1f6c8e46ae9ecc430c43ecab3b.jpg" width="535" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>前端安全</strong></strong></h2> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/1f5ea36799994185b9ca8da003b87c7a.jpg" target="_blank"><img alt="前端高频面试题_第27张图片" height="439" src="http://img.e-com-net.com/image/info8/1f5ea36799994185b9ca8da003b87c7a.jpg" width="640" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>1、什么是CSRF攻击?如何防御CSRF攻击?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>CSRF攻击</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">CSRF即Cross-site request forgery(跨站请求伪造),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">假如黑客在自己的站点上放置了其他网站的外链,例如"www.weibo.com/api,默认情况下,浏览器会带着weibo.com的cookie访问这个网址,如果用户已登录过该网站且网站没有对CSRF攻击进行防御,那么服务器就会认为是用户本人在调用此接口并执行相关操作,致使账号被劫持。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>如何防御CSRF攻击</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">验证Token:浏览器请求服务器时,服务器返回一个token,每个请求都需要同时带上token和cookie才会被认为是合法请求</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">验证Referer:通过验证请求头的Referer来验证来源站点,但请求头很容易伪造</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置SameSite:设置cookie的SameSite,可以让cookie不随跨域请求发出,但浏览器兼容不一</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、什么是XSS攻击?XSS攻击有哪些类型?如何防御XSS攻击?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>xss攻击</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">XSS即Cross Site Scripting(跨站脚本</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">攻击</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">),指的是通过利用网页开发时留下的漏洞,注入</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。常见的例如在评论区植入JS代码,用户进入评论页时代码被执行,造成页面被植入广告、账号信息被窃取</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>XSS攻击有哪些类型</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">存储型:即攻击被存储在服务端,常见的是在评论区插入攻击脚本,如果脚本被储存到服务端,那</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">么所有看见</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">对应评论的用户都会受到攻击。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">反射型:攻击者将脚本混在URL里,服务端接收到URL将恶意代码当做参数取出并拼接在HTML里返回,浏览器解析此HTML后即执行恶意代码</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">DOM型:将攻击脚本写在URL中,诱导用户点击该URL,如果URL被解析,那么攻击脚本就会被运行。和前两者的差别主要在于DOM型攻击不经过服务端</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>如何防御XSS攻击</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">输入检查:对输入内容中的<script><iframe>等标签进行转义或者过滤</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置httpOnly:很多XSS攻击目标都是窃取用户cookie伪造身份认证,设置此属性可防止JS获取cookie</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">开启CSP,即开启白名单,可阻止白名单以外的资源加载和运行</span></span></p> <p></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>设计模式</strong></strong></h2> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/6483ca835d0e460988c17a6985fde9a3.jpg" target="_blank"><img alt="前端高频面试题_第28张图片" height="280" src="http://img.e-com-net.com/image/info8/6483ca835d0e460988c17a6985fde9a3.jpg" width="645" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:justify;"><strong><strong>1、介绍一下单一职责原则和开放封闭原则</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>单一职责原则</strong></span></span></strong><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>开放封闭原则:</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">核心的思想是软件实体(类、模块、函数等)是可扩展的、但不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:justify;"><strong><strong>2、单例模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">单例模式即一个类只能构造出唯一实例,单例模式的意义在于共享、唯一,Redux/Vuex中的store、JQ的$或者业务场景中的购物车、登录框都是单例模式的应用</span></span></p> <pre><code class="language-javascript"> class SingletonLogin { constructor(name, password) { this.name = name this.password = password } static getInstance(name, password) { //判断对象是否已经被创建,若创建则返回旧对象 if (!this.instance) this.instance = new SingletonLogin(name, password) return this.instance } } let obj1 = SingletonLogin.getInstance('Demi', '123') let obj2 = SingletonLogin.getInstance('Demi', '321') console.log(obj1 === obj2) // true console.log(obj1) // {name:Demi,password:123} console.log(obj2) // 输出的依然是{name:Demi,password:123}</code></pre> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:justify;"><strong><strong>3、工厂模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">工厂模式即对创建对象逻辑的封装,或者可以简单理解为对new的封装,这种封装就像创建对象的工厂,故名工厂模式。工厂模式常见于大型项目,比如JQ的$对象,我们创建选择器对象时之所以没有new selector就是因为$()已经是一个工厂方法,其他例子例如React.createElement()、Vue.component()都是工厂模式的实现。工厂模式有多种:简单工厂模式、工厂方法模式、抽象工厂模式,这里只以简单工厂模式为例</span></span></p> <pre><code class="language-javascript"> class User { constructor(name, auth) { this.name = name this.auth = auth } } class UserFactory { static createUser(name, auth) { //工厂内部封装了创建对象的逻辑: //权限为admin时,auth=1, 权限为user时, auth为2 //使用者在外部创建对象时,不需要知道各个权限对应哪个字段, 不需要知道赋权的逻辑,只需要知道创建了一个管理员和用户 if (auth === 'admin') new User(name, 1) if (auth === 'user') new User(name, 2) } } const admin = UserFactory.createUser('Demi', 'admin'); const user = UserFactory.createUser('Demi', 'user');</code></pre> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:justify;"><strong><strong>4、观察者模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">观察者模式算是前端最常用的设计模式了,观察者模式概念很简单:观察者监听被观察者的变化,被观察者发生改变时,通知所有的观察者。观察者模式被广泛用于监听事件的实现,有关观察者模式的详细应用</span></span></p> <pre><code class="language-javascript"> //观察者 class Observer { constructor(fn) { this.update = fn } } //被观察者 class Subject { constructor() { this.observers = [] //观察者队列 } addObserver(observer) { this.observers.push(observer) //往观察者队列添加观察者 } notify() { //通知所有观察者,实际上是把观察者的update()都执行了一遍 this.observers.forEach(observer => { observer.update() //依次取出观察者,并执行观察者的update方法 }) } } var subject = new Subject() //被观察者 const update = () => { console.log('被观察者发出通知') } //收到广播时要执行的方法 var ob1 = new Observer(update) //观察者1 var ob2 = new Observer(update) //观察者2 subject.addObserver(ob1) //观察者1订阅subject的通知 subject.addObserver(ob2) //观察者2订阅subject的通知 subject.notify() //发出广播,执行所有观察者的update方法</code></pre> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:justify;"><strong><strong>5、装饰器模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">装饰器模式,可以理解为对类的一个包装,动态地拓展类的功能,ES7的装饰器语法以及React中的高阶组件(HoC)都是这一模式的实现。react-redux的connect()也运用了装饰器模式,这里以ES7的装饰器为例</span></span></p> <pre><code class="language-javascript"> function info(target) { target.prototype.name = 'Demi' target.prototype.age = 10 } @info class Man {} let man = new Man() man.name // Demi</code></pre> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:justify;"><strong><strong>6、适配器模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">适配器模式,将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。我们在生活中就常常有使用适配器的场景,例如出境旅游插头插座不匹配,这时我们就需要使用转换插头,也就是适配器来帮我们解决问题。</span></span></p> <pre><code class="language-javascript"> class Adaptee { test() { return '旧接口' } } class Target { constructor() { this.adaptee = new Adaptee() } test() { let info = this.adaptee.test() return `适配${info}` } } let target = new Target() console.log(target.test())</code></pre> <p style="margin-left:.0001pt;text-align:justify;"></p> <h4 style="text-align:justify;"><strong><strong>7、代理模式</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">代理模式,为一个对象找一个替代对象,以便对原对象进行访问。即在访问者与目标对象之间加一层代理,通过代理做授权和控制。最常见的例子是经纪人代理明星业务,假设你作为一个投资者,想联系明星打广告,那么你就需要先经过代理经纪人,经纪人对你的资质进行考察,并通知你明星排期,替明星本人过滤不必要的信息。事件代理、JQuery的$.proxy、ES6的proxy都是这一模式的实现,下面以ES6的proxy为例</span></span></p> <pre><code class="language-javascript"> const idol = { name: 'Demi', phone: 10086, price: 1000000 //报价 } const agent = new Proxy(idol, { get: function (target) { //拦截明星电话的请求,只提供经纪人电话 return '经纪人电话:10010' }, set: function (target, key, value) { if (key === 'price') { //经纪人过滤资质 if (value < target.price) throw new Error('报价过低') target.price = value } } }) agent.phone //经纪人电话:10010 agent.price = 100 //Uncaught Error: 报价过低</code></pre> <p style="margin-left:.0001pt;text-align:left;"></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>NPM</strong></strong></h2> <h4 style="text-align:left;"><strong><strong>1、npm是什么?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm是JavaScript世界的包管理工具,并且是Node.js平台的默认包管理工具。通过npm可以安装、共享、分发代码,管理项目依赖关系。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>2、介绍下npm模块安装机制,为什么输入npm install 就可以自动安装对应模块?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.发出npm install命令</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.查询node_ modules 目录之中是否已经存在指定模块</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">若存在,不再重新安装</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">若不存在</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm向registry查询模块压缩地址</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">下载压缩包,存放在根目录下的.npm里</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">解压压缩包到当前项目的node_ modules录</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>3、npm2和npm3区别</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm2所有项目依赖是嵌套关系,</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm3为了改进嵌套过多套路过深的情况,会将所有依赖放在第二层依赖中(所有依赖只嵌套</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">次 ,彼此平行,也就是平铺的结构)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm2依赖安装的时候比较简单直接,直接按照包依赖的树形结构下载填充本地目录结构,也就是说每个包都会将该包的依赖组织到当前包所在的node. modules目录中。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm3则对依赖安装进行了改造,采用"扁平结构"的思路来组织依赖包的目录结构。具体的就是npm install时:按照package</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">json里依赖的顺序依次解析,遇到新的包就把它放在第一级目录,后面如果遇到</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">级目录已经存在的包,会先判断版本,如果版本</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">一</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">样则忽略,否则会按照npm2的方式依次挂在依赖包目录下。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/77006e9e96c34b1b9ca12c33af79c060.jpg" target="_blank"><img alt="前端高频面试题_第29张图片" height="263" src="http://img.e-com-net.com/image/info8/77006e9e96c34b1b9ca12c33af79c060.jpg" width="487" style="border:1px solid black;"></a></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>4、npm发包流程</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.在npm官网</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">注册npm账号(已有可忽略)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">新建文件夹,进入该文件夹,运行npm init,生成package.json文件</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">将需要发布的代码放入该文件夹</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">4.在终端</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">执行npm login 命令登录</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">,按照提示填写对应的内容</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(账号、密码、邮箱)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">5.</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">运行 npm publish 发布</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>5、npm和yarn的区别?</strong></strong></span></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>npm:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">基于node.js的包管理工具;常用命令 npm install 包名;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">缺点:因服务器在国外,所以下载包的速度超级慢,所以出现了cnpm和yarn</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>cnpm:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">跟npm是一样的,这是淘宝出的下载工具,服务器在国内,所以下载速度比npm快很多,但是安装有点乱,并且容易出错;cnpm install 包名</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">安装cnpm</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm install -g cnpm --registry=</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">https://registry.npm.taobao.org</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>yarn:</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">“Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">官方文档</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">速度对比</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>耗时从少到多:</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">cnpm:cnpm install vue-cli --save</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用时:41600ms,包数量:1508</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">yarn:yarn add vue-cli</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用时:181200ms,包数量:742</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">npm:npm install vue-cli --save</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用时:362400.5ms,包数量:727</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">结论:</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">cnpm虽然是最快的,不过有很多同行吐槽它的包文件过多和凌乱,包括其他一些问题(安装会出错等),因此国内有一些大的团队在内部并不使用cnpm。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>npm的未来:npm5.0</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">有了yarn的压力之后,npm做了一些类似的改进。默认新增了类似yarn.lock的 package-lock.json;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.git 依赖支持优化:这个特性在需要安装大量内部项目(例如在没有自建源的内网开发),或需要使用某些依赖的未发布版本时很有用。在这之前可能需要使用指定 commit_id 的方式来控制版本。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.文件依赖优化:在之前的版本,如果将本地目录作为依赖来安装,将会把文件目录作为副本拷贝到 node_modules 中。而在 npm5 中,将改为使用创建 symlinks 的方式来实现(使用本地 tarball 包除外),而不再执行文件拷贝。这将会提升安装速度。目前yarn还不支持。</span></span></p> <p></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>小程序</strong></strong></h2> <h4 style="text-align:left;"><strong><strong>1、微信小程序架构</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">微信小程序视图层是WebView ,逻辑层是JS引擎。三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>运行环境</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Android</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">iOS</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">小程序开发者工具</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>逻辑层</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">V8</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">JavaScriptCore</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">NWJS</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>渲染层</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Chromium定制内核</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">WKWebview</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">Chrome Webview</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>2、小程序打开页面数量</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">最多可以打开10层,但是可以通过类似的redirectTo方法来在最后一层进行无限的跳转,但是这样做会无法返回上一个页面,只能返回路由栈中的上一层级</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>3、组件生命周期</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">created创建</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">att</span></span><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ached挂载</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">ready挂载完毕</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">moved移动</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">detached移除</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">error组件错误</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>4、页面生命周期</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onLoad初始化注册执行-次</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onShow前台展示的时候,即执行多次</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onReady初次渲染完成,执行-次</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onHide页面隐藏</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onUnload页面销毁</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>5、App生命周期</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onLaunch小程序注册,只会执行一 次</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onShow小程序唤起的前台展示</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onHide小程序前台隐藏</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onError小程序出现错误</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>6、常用API</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>1.路由跳转</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.switchTab: 只能跳转到导航页,并关闭其他的导航页</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.reLaunch: 关闭所有页面,打开到应用内的某个页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.redirectTo: 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到导航页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.navigateTo: 只保留当前页面,跳转到应用内的某个页面。但是不能跳到tabbar页面(最多10层)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx navigateBack: 返回上一页,可以返回多级页面</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>2.弹窗提示</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.showToast</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.showModal</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx .showLoading</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>3.分享</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.showShareMenu</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">onShareAppMessage</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>4.数据缓存</strong></span></span></strong></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.setStorageSync</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx.getStorageSync</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="text-align:left;"><strong><strong>7、简单描述下微信小程序的相关文件类型</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>WXML(WeiXin Markup Language)</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是框架设计的一套标签语言,结合基础组件、事件系统,可以构建出页面的结构。内部主要是微信自己定义的一套组件。与html差不多。</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>WXSS (WeiXin Style Sheets)</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">是一套样式语言,用于描述 WXML 的组件样式,与css差不多</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>js </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">逻辑处理,网络请求</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>json </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">小程序设置,如页面注册,页面标题及tabBar。</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>project.config.json </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">项目配置文件,用得最多的就是配置是否开启https校验;</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>App.js </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">设置一些全局的基础数据等;</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>App.json</strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"> 底部tab, 标题栏和路由等设置;</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>App.wxss </strong></span></span></strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">公共样式,引入iconfont等;</span></span></p> <h4 style="margin-left:.0001pt;text-align:left;"></h4> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>8、有哪些参数传值的方法?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">1.给HTML元素添加data-*属性来传递我们需要的值,然后通过e.currentTarget.dataset或onload的param参数获取。但data-名称不能有大写字母和不可以存放对象</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">2.设置id 的方法标识来传值通过e.currentTarget.id获取设置的id的值,然后通过设置全局对象的方式来传递数值</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">3.在navigator中添加参数传值(传的值的名称=所传的值在onLoad(option)用option来接收并获取)</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>9、使用过哪些方法来提高微信小程序的应用速度?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)提高页面加载速度</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)用户行为预测</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)减少默认data的大小</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)组件化方案</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>10、你是怎么封装微信小程序的数据请求的?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)在根目录下创建utils目录及api.js文件和apiConfig.js文件;</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)在apiConfig.js 封装基础的get, post 和 put, upload等请求方法,设置请求体,带上token和异常处理等;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)在api中引入apiConfig.js封装好的请求方法,根据页面数据请求的urls, 设置对应的方法并导出;</span></span></p> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)在具体的页面中导入;</span></span></p> <p></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>11、请谈谈小程序的双向绑定和vue的异同?</strong></strong></h4> <p style="margin-left:.0001pt;text-align:left;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">大体相同,但小程序直接this.data的属性是不可以同步到视图的,必须调用this.setData()方法</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>12、如何实现下拉刷新?</strong></strong></h4> <p style="margin-left:0px;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">用view代替scroll-view,,设置onPullDownRefresh函数实现</span></span></p> <p style="margin-left:0;text-align:justify;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>13、使用webview直接加载要注意哪些事项?</strong></strong></h4> <p style="margin-left:0px;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(1)必须要在小程序后台使用管理员添加业务域名;</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(2)h5页面跳转至小程序的脚本必须是1.3.1以上;</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(3)微信分享只可以都是小程序的主名称了,如果要自定义分享的内容,需小程序版本在1.7.1以上;</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">(4)h5的支付不可以是微信公众号的appid,必须是小程序的appid,而且用户的openid也必须是用户和小程序</span></span></p> <p></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>14、小程序简单介绍下三种事件对象的属性列表?</strong></strong></h4> <p style="margin-left:0px;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>基础事件(BaseEvent)</strong></span></span></strong></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">type: 事件类型</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">timeStamp:事件生成时的时间戳</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">target:触发事件的组件的属性值集合</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">currentTarget:当前组件的一些属性集合</span></span></p> <p style="margin-left:0;text-align:justify;"><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>自定义事件(CustomEvent)</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">detail</span></span><br><strong><span style="background-color:#ffffff;"><span style="color:#4d4d4d;"><strong>触摸事件(TouchEvent)</strong></span></span></strong><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">touches</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">changedTouches</span></span></p> <p style="margin-left:0;text-align:justify;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>15、小程序还有哪些功能?</strong></strong></h4> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">客服功能,录音,视频,音频,地图,定位,拍照,动画,canvas</span></span></p> <p style="margin-left:0;text-align:justify;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>16、小程序对wx:if 和 hidden使用的理解?</strong></strong></h4> <p style="margin-left:0px;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">wx:if 有更高的切换消耗</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">hidden 有更高的初始渲染消耗</span></span><br><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">因此,如果需要频繁切换的情景下用hidden更好,如果在运行时条件不大可能改变则 wx:if 较好</span></span></p> <p style="margin-left:0;text-align:justify;"></p> <h4 style="margin-left:0px;text-align:justify;"><strong><strong>17、请谈谈原生开发小程序、wepy、mpvue 的对比?</strong></strong></h4> <p style="margin-left:0px;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">如果是新项目,且没有旧的 h5 项目迁移,则考虑用小程序原生开发,好处是相比于第三方框架,坑少。 而如果有老的 h5 项目是 vue 开发 或者 也有 h5 项目也需要小程序开发,则比较适合 wepy 或者 mpvue 来做迁移或者开发,近期看wepy几乎不更新了,所以推荐美团的mpvue</span></span></p> <p style="margin-left:0;text-align:left;"></p> <p></p> <hr> <h2 style="margin-left:.0001pt;text-align:justify;"><strong><strong>Git</strong></strong></h2> <h4 style="text-align:left;"><strong><strong>1、图解git仓库</strong></strong></h4> <p style="text-align:center;"><a href="http://img.e-com-net.com/image/info8/2ad3a444cf8841a5b43559758b3fd4fc.jpg" target="_blank"><img alt="前端高频面试题_第30张图片" height="267" src="http://img.e-com-net.com/image/info8/2ad3a444cf8841a5b43559758b3fd4fc.jpg" width="640" style="border:1px solid black;"></a></p> <p style="margin-left:0;text-align:left;"></p> <h4 style="margin-left:0px;text-align:left;"><span style="background-color:#ffffff;"><strong><strong>2、常用git命令</strong></strong></span></h4> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git add .    将工作区所有文件添加到暂存区</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git add <file-name>  将指定文件添加到暂存区</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git commit -m '备注'  将暂存区的文件提交到本地仓库</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git status   查看仓库当前的状态,文件是否有被修改过</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git log   显示从最近到最远的提交日志历史记录</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git reflog   查看所以操作记录(包括commit 和reset操作以及已经被删除的commit记录)</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git reste -hard HEAD^   回退到上一个版本(HEAD代码当前版本,HEAD^代表上一个版本,HEAD^^代表上上个版本,HEAD^100代表上100个版本)</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git reset -hard <commit id>   回退到指定版本号的版本</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git diff   查看工作区域内容和暂存区域内容之间的差异</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git diff --cached   比较暂存区和本地仓库之间的差异</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git diff HEAD   比较工作区和本地仓库最新版本的区别</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git diff <commit id>  比较工作区和指定版本的之间的差异</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git diff <commit id> <commit id>  比较两个版本之间的差异</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git rm <file-name>   从版本库删除指定文件</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git branch <branch-name>    创建新分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git checkout <branch-name>   切换到指定分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git checkout -b <branch-name>   创建并切换分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git branch   列出所有分支,当前分支前面会标有一个*号</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git merge <branch-name>  合并指定分支的内容到当前分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git merge --no--ff  <branch-name>    --no-ff 表示禁用fast forward合并,用普通模式进行分支合并,fast forward合并看不出曾经做过合并,普通模式可以。</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git branch -d <branch-name>  删除合并后的分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git branch -D <branch-name>  强制删除分支</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git remote   查看远程仓库的信息</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git remote -v   查看远程仓库的详细信息</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git push origin <branch-name>  推送分支到远程仓库</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git pull   拉取远程仓库的代码</span></span></p> <p style="margin-left:0;text-align:justify;"><span style="background-color:#ffffff;"><span style="color:#4d4d4d;">git config --global alias.sta  status   配置status的别名为sta</span></span></p> <p style="margin-left:.0001pt;text-align:left;"></p> <p></p> <blockquote> <p> 文章每周持续更新,可以微信搜索「 <strong>前端大集锦</strong> 」第一时间阅读,回复【<strong>视频</strong>】【<strong>书籍</strong>】领取200G视频资料和30本PDF书籍资料</p> </blockquote> <p> </p> <p></p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1712647923893874688"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(面试,面试)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835495517774245888.htm" title="python八股文面试题分享及解析(1)" target="_blank">python八股文面试题分享及解析(1)</a> <span class="text-muted">Shawn________</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>#1.'''a=1b=2不用中间变量交换a和b'''#1.a=1b=2a,b=b,aprint(a)print(b)结果:21#2.ll=[]foriinrange(3):ll.append({'num':i})print(11)结果:#[{'num':0},{'num':1},{'num':2}]#3.kk=[]a={'num':0}foriinrange(3):#0,12#可变类型,不仅仅改变</div> </li> <li><a href="/article/1835494257746604032.htm" title="MYSQL面试系列-04" target="_blank">MYSQL面试系列-04</a> <span class="text-muted">king01299</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>MYSQL面试系列-0417.关于redolog和binlog的刷盘机制、redolog、undolog作用、GTID是做什么的?innodb_flush_log_at_trx_commit及sync_binlog参数意义双117.1innodb_flush_log_at_trx_commit该变量定义了InnoDB在每次事务提交时,如何处理未刷入(flush)的重做日志信息(redolog)。它</div> </li> <li><a href="/article/1835493753083752448.htm" title="Kafka 消息丢失如何处理?" target="_blank">Kafka 消息丢失如何处理?</a> <span class="text-muted">架构文摘JGWZ</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a> <div>今天给大家分享一个在面试中经常遇到的问题:Kafka消息丢失该如何处理?这个问题啊,看似简单,其实里面藏着很多“套路”。来,咱们先讲一个面试的“真实”案例。面试官问:“Kafka消息丢失如何处理?”小明一听,反问:“你是怎么发现消息丢失了?”面试官顿时一愣,沉默了片刻后,可能有点不耐烦,说道:“这个你不用管,反正现在发现消息丢失了,你就说如何处理。”小明一头雾水:“问题是都不知道怎么丢的,处理起来</div> </li> <li><a href="/article/1835493753557708800.htm" title="每日算法&面试题,大厂特训二十八天——第二十天(树)" target="_blank">每日算法&面试题,大厂特训二十八天——第二十天(树)</a> <span class="text-muted">肥学</span> <a class="tag" taget="_blank" href="/search/%E2%9A%A1%E7%AE%97%E6%B3%95%E9%A2%98%E2%9A%A1%E9%9D%A2%E8%AF%95%E9%A2%98%E6%AF%8F%E6%97%A5%E7%B2%BE%E8%BF%9B/1.htm">⚡算法题⚡面试题每日精进</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a> <div>目录标题导读算法特训二十八天面试题点击直接资料领取导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进行二十八天的一个小总结。还在等什么快来一起肥学进行二十八天挑战吧!!特别介绍小白练手专栏,适合刚入手的新人欢迎订阅编程小白进阶python有趣练手项目里面包括了像《机器人尬聊》《恶搞程序》这样的有趣文章</div> </li> <li><a href="/article/1835491353451130880.htm" title="【华为OD技术面试真题 - 技术面】- python八股文真题题库(4)" target="_blank">【华为OD技术面试真题 - 技术面】- python八股文真题题库(4)</a> <span class="text-muted">算法大师</span> <a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BAod/1.htm">华为od</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>华为OD面试真题精选专栏:华为OD面试真题精选目录:2024华为OD面试手撕代码真题目录以及八股文真题目录文章目录华为OD面试真题精选**1.Python中的`with`**用途和功能自动资源管理示例:文件操作上下文管理协议示例代码工作流程解析优点2.\_\_new\_\_和**\_\_init\_\_**区别__new____init__区别总结3.**切片(Slicing)操作**基本切片语法</div> </li> <li><a href="/article/1835491354004779008.htm" title="【华为OD技术面试真题 - 技术面】-测试八股文真题题库(1)" target="_blank">【华为OD技术面试真题 - 技术面】-测试八股文真题题库(1)</a> <span class="text-muted">算法大师</span> <a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BAod/1.htm">华为od</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>华为OD面试真题精选专栏:华为OD面试真题精选目录:2024华为OD面试手撕代码真题目录以及八股文真题目录文章目录华为OD面试真题精选1.黑盒测试和白盒测试的区别2.假设我们公司现在开发一个类似于微信的软件1.0版本,现在要你测试这个功能:打开聊天窗口,输入文本,限制字数在200字以内。问你怎么提取测试点。功能测试性能测试安全性测试可用性测试跨平台兼容性测试网络环境测试3.接口测试的工具你了解哪些</div> </li> <li><a href="/article/1835485681187647488.htm" title="【华为OD技术面试真题精选 - 非技术题】 -HR面,综合面_华为od hr面" target="_blank">【华为OD技术面试真题精选 - 非技术题】 -HR面,综合面_华为od hr面</a> <span class="text-muted">一个射手座的程序媛</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BAod/1.htm">华为od</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a> <div>最后的话最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!资料预览给大家整理的视频资料:给大家整理的电子书资料:如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以点击这里获</div> </li> <li><a href="/article/1835483915071090688.htm" title="【华为OD技术面试真题 - 技术面】- python八股文真题题库(1)" target="_blank">【华为OD技术面试真题 - 技术面】- python八股文真题题库(1)</a> <span class="text-muted">算法大师</span> <a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BAod/1.htm">华为od</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>华为OD面试真题精选专栏:华为OD面试真题精选目录:2024华为OD面试手撕代码真题目录以及八股文真题目录文章目录华为OD面试真题精选1.数据预处理流程数据预处理的主要步骤工具和库2.介绍线性回归、逻辑回归模型线性回归(LinearRegression)模型形式:关键点:逻辑回归(LogisticRegression)模型形式:关键点:参数估计与评估:3.python浅拷贝及深拷贝浅拷贝(Shal</div> </li> <li><a href="/article/1835469672334585856.htm" title="Java企业面试题3" target="_blank">Java企业面试题3</a> <span class="text-muted">马龙强_</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>1.break和continue的作用(智*图)break:用于完全退出一个循环(如for,while)或一个switch语句。当在循环体内遇到break语句时,程序会立即跳出当前循环体,继续执行循环之后的代码。continue:用于跳过当前循环体中剩余的部分,并开始下一次循环。如果是在for循环中使用continue,则会直接进行条件判断以决定是否执行下一轮循环。2.if分支语句和switch分</div> </li> <li><a href="/article/1835464504918503424.htm" title="Java面试题精选:消息队列(二)" target="_blank">Java面试题精选:消息队列(二)</a> <span class="text-muted">芒果不是芒</span> <a class="tag" taget="_blank" href="/search/Java%E9%9D%A2%E8%AF%95%E9%A2%98%E7%B2%BE%E9%80%89/1.htm">Java面试题精选</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>一、Kafka的特性1.消息持久化:消息存储在磁盘,所以消息不会丢失2.高吞吐量:可以轻松实现单机百万级别的并发3.扩展性:扩展性强,还是动态扩展4.多客户端支持:支持多种语言(Java、C、C++、GO、)5.KafkaStreams(一个天生的流处理):在双十一或者销售大屏就会用到这种流处理。使用KafkaStreams可以快速的把销售额统计出来6.安全机制:Kafka进行生产或者消费的时候会</div> </li> <li><a href="/article/1835460785443270656.htm" title="2019考研 | 西交大软件工程" target="_blank">2019考研 | 西交大软件工程</a> <span class="text-muted">笔者阿蓉</span> <div>本科背景:某北京211学校电子信息工程互联网开发工作两年录取结果:全日制软件工程学院分数:初试350+复试笔试80+面试85+总排名:100+从五月份开始脱产学习,我主要说一下专业课和复试还有我对非全的一些看法。【数学100+】张宇,张宇,张宇。跟着张宇学习,入门视频刷一遍,真题刷两遍,错题刷三遍。书刷N多遍。从视频开始学习,是最快的学习方法。5-7月份把主要是数学学好,8-9月份开始给自己每个周</div> </li> <li><a href="/article/1835413064636264448.htm" title="Day_11" target="_blank">Day_11</a> <span class="text-muted">ROC_bird..</span> <a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>面试题16.15.珠玑妙算-力扣(LeetCode)/***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*///下标和对应位置的值都一样,answer[0]+1,对应位置的值猜对了,但是下标不对,answer[1]+1int*masterMind(char*solution,char*guess,int*returnSiz</div> </li> <li><a href="/article/1835411044768509952.htm" title="字节二面" target="_blank">字节二面</a> <span class="text-muted">Redstone Monstrosity</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>1.假设你是正在面试前端开发工程师的候选人,面试官让你详细说出你上一段实习过程的收获和感悟。在上一段实习过程中,我获得了宝贵的实践经验和深刻的行业洞察,以下是我的主要收获和感悟:一、专业技能提升框架应用熟练度:通过实际项目,我深入掌握了React、Vue等前端框架的使用,不仅提升了编码效率,还学会了如何根据项目需求选择合适的框架。问题解决能力:在实习期间,我遇到了许多预料之外的技术难题。通过查阅文</div> </li> <li><a href="/article/1835379662918873088.htm" title="【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(二十八)" target="_blank">【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(二十八)</a> <span class="text-muted">向往风的男子</span> <a class="tag" taget="_blank" href="/search/k8s/1.htm">k8s</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/kubernetes/1.htm">kubernetes</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a> <div>本站以分享各种运维经验和运维所需要的技能为主《python零基础入门》:python零基础入门学习《python运维脚本》:python运维脚本实践《shell》:shell学习《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战《k8》从问题中去学习k8s《docker学习》暂未更新《ceph学习》ceph日常问题解决分享《日志收集》ELK+各种中间件《运维日常》</div> </li> <li><a href="/article/1835373226490949632.htm" title="Java -jar 如何在后台运行项目" target="_blank">Java -jar 如何在后台运行项目</a> <span class="text-muted">vincent_hahaha</span> <div>撸了今年阿里、头条和美团的面试,我有一个重要发现.......>>>说到运行jar包通常我们都会以下面的方式运行:java-jarspringboot-0.0.1-SNAPSHOT.jar这样运行的话会有一个问题,就是我们一关闭当前窗口就会停止运行项目,要想解决这个问题,就需要在后台运行。nohupjava-jarbabyshark-0.0.1-SNAPSHOT.jar >log.file 2>&</div> </li> <li><a href="/article/1835357347615174656.htm" title="【Death Note】网吧战神之7天爆肝渗透测试死亡笔记_sqlmap在默认情况下除了使用 char() 函数防止出现单引号" target="_blank">【Death Note】网吧战神之7天爆肝渗透测试死亡笔记_sqlmap在默认情况下除了使用 char() 函数防止出现单引号</a> <span class="text-muted">2401_84561374</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以戳这里获取一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!特殊服务端口2181zookeeper服务未授权访问</div> </li> <li><a href="/article/1835353689854930944.htm" title="【Kubernetes】常见面试题汇总(十一)" target="_blank">【Kubernetes】常见面试题汇总(十一)</a> <span class="text-muted">summer.335</span> <a class="tag" taget="_blank" href="/search/Kubernetes/1.htm">Kubernetes</a><a class="tag" taget="_blank" href="/search/kubernetes/1.htm">kubernetes</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E5%8E%9F%E7%94%9F/1.htm">云原生</a> <div>目录33.简述Kubernetes外部如何访问集群内的服务?34.简述Kubernetesingress?35.简述Kubernetes镜像的下载策略?33.简述Kubernetes外部如何访问集群内的服务?(1)对于Kubernetes,集群外的客户端默认情况,无法通过Pod的IP地址或者Service的虚拟IP地址:虚拟端口号进行访问。(2)通常可以通过以下方式进行访问Kubernetes集群</div> </li> <li><a href="/article/1835350917352878080.htm" title="华雁智科前端面试题" target="_blank">华雁智科前端面试题</a> <span class="text-muted">因为奋斗超太帅啦</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E7%AC%94%E8%AF%95%E9%9D%A2%E8%AF%95%E9%97%AE%E9%A2%98%E6%95%B4%E7%90%86/1.htm">前端笔试面试问题整理</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a> <div>1.var变量的提升题目:vara=1functionfun(){console.log(b)varb=2}fun()console.log(a)正确输出结果:undefined、1答错了,给一个大嘴巴子,错误答案输出结果为:2,1此题主要考察var定义的变量,作用域提升的问题,相当于varaa=1functionfun(){varbconsole.log(b)b=2}fun()console.l</div> </li> <li><a href="/article/1835348897355100160.htm" title="保研日记--哈工大威海计算机学院" target="_blank">保研日记--哈工大威海计算机学院</a> <span class="text-muted">faaarii</span> <a class="tag" taget="_blank" href="/search/%E4%BF%9D%E7%A0%94/1.htm">保研</a> <div>传送门保研日记--中国海洋大学计算机系保研日记--中国人民大学信息学院(人大信院)保研日记--北京交通大学计算机学院保研材料模板(自我介绍,个人简历,个人陈述,推荐信)哈工大威海计算机学院这次夏令营给我的感觉非常的朴素,哈哈哈哈营员就有四个群,985/211、双一流、双非、四非??没有宣讲会、见面会,在面试开始之前放了一个简短的宣传片。(傲娇,绝对不整那些花里胡哨的哈哈哈)面试有三组老师,分别问你</div> </li> <li><a href="/article/1835344483210850304.htm" title="自动化测试工程师面试,常问的问题有哪些?" target="_blank">自动化测试工程师面试,常问的问题有哪些?</a> <span class="text-muted">自动化测试 老司机</span> <a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/1.htm">软件测试</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E7%A8%8B%E5%B8%88/1.htm">测试工程师</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95/1.htm">自动化测试</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a><a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/1.htm">软件测试</a><a class="tag" taget="_blank" href="/search/selenium/1.htm">selenium</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/1.htm">测试工具</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E7%A8%8B%E5%B8%88/1.htm">测试工程师</a> <div>自动化测试工程师面试是非常重要的环节,面试官会通过一系列的问题来评估候选人的技能和经验。下面是一些常见的问题,以及如何详细而规范地回答这些问题的建议。1.请介绍一下你的自动化测试经验。回答这个问题时,可以从项目经验、使用的自动化测试工具、编写的测试脚本等方面来介绍自己的经验。重点强调你在自动化测试领域的技能和擅长的领域。2.你在自动化测试中使用的编程语言是什么?为什么选择这种语言?回答这个问题时,</div> </li> <li><a href="/article/1835340618100994048.htm" title="中年女人的危机" target="_blank">中年女人的危机</a> <span class="text-muted">南溪_e428</span> <div>今天看了篇文章,就是说女人过了四十,还要换工作吗?确实是现实,有很多的单位公司在面试的时候,都会问你有几个孩子,还会打算生二胎吗?有的还会直接要求你说,希望入职的最近一年里,不要生孩子,单位也有单位的难处啊!尽管说,面试官也同样会是女人,这个话题是不可避免的啊!后来有的单位就变得聪明了,不在招收年龄偏大的员工,一般都是招年龄相对小的,而且还是以男性员工为主的,除非没办法才会招极个别的女工,这就是现</div> </li> <li><a href="/article/1835340577596600320.htm" title="前端CSS面试常见题" target="_blank">前端CSS面试常见题</a> <span class="text-muted">剑亦未配妥</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95/1.htm">前端面试</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>边界塌陷盒模型有两种:W3C盒模型和IE盒模型,区别在于宽度是否包含边框定义:同时给兄弟/父子盒模型设置上下边距,理论上边距值是两者之和,实际上不是注意:浮动和定位不会产生边界塌陷;只有块级元素垂直方向才会产生margin合并margin计算方案margin同为正负:取绝对值大的值一正一负:求和父子元素边界塌陷解决父元素可以通过调整padding处理;设置overflowhidden,触发BFC子</div> </li> <li><a href="/article/1835332133149831168.htm" title="2024年最全Flutter如何和Native通信-Android视角,Electron开发Android界面" target="_blank">2024年最全Flutter如何和Native通信-Android视角,Electron开发Android界面</a> <span class="text-muted">2401_84544531</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a> <div>总结【Android详细知识点思维脑图(技能树)】其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。虽然Android没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明Android中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪</div> </li> <li><a href="/article/1835319487742701568.htm" title="音视频知识图谱 2022.04" target="_blank">音视频知识图谱 2022.04</a> <span class="text-muted">关键帧Keyframe</span> <div>前些时间,我在知识星球上创建了一个音视频技术社群:关键帧的音视频开发圈,在这里群友们会一起做一些打卡任务。比如:周期性地整理音视频相关的面试题,汇集一份音视频面试题集锦,你可以看看《音视频面试题集锦2022.04》。再比如:循序渐进地归纳总结音视频技术知识,绘制一幅音视频知识图谱。下面是2022.04月知识图谱新增的内容节选:1)图谱路径:**采集/音频采集/声音三要素/响度******主观计量响</div> </li> <li><a href="/article/1835312144145543168.htm" title="【华为OD技术面】 - 考到的Lettcode手撕算法代码真题目录" target="_blank">【华为OD技术面】 - 考到的Lettcode手撕算法代码真题目录</a> <span class="text-muted">算法大师</span> <a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BAod/1.htm">华为od</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>华为OD面试真题精选专栏:华为OD面试真题精选目录:2024华为OD面试手撕代码真题目录以及八股文真题目录文章目录华为OD面试真题精选目录目录题目备注1052.爱生气的书店老板2024-4LCR058.我的日程安排表I技术二面</div> </li> <li><a href="/article/1835310380474265600.htm" title="Java面试笔记记录6" target="_blank">Java面试笔记记录6</a> <span class="text-muted">今天背八股了吗</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>1.Spring是什么?特性?有哪些模块?Spring是一个轻量级、非入侵式的控制反转Ioc和面向切面AOP的框架。特性:1.Ioc和DISpring的核心就是一个大的工厂容器,可以维护所有对象的创建和依赖关系,Spring工厂用于生成Bean,并且管理Bean的生命周期,实现高内聚低耦合的设计理念。2.AOP编程Spring提供面向切面编程,可以方便实现对程序进行权限拦截、运行监控等切面功能。3</div> </li> <li><a href="/article/1835292618146279424.htm" title="小米嵌入式面试题目RTOS面试题目 嵌入式面试题目" target="_blank">小米嵌入式面试题目RTOS面试题目 嵌入式面试题目</a> <span class="text-muted">好家伙VCC</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E6%9D%82%E8%B0%88%E6%9D%82%E8%B0%88/1.htm">杂谈杂谈</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a> <div>第一章-非RTOSbootloader工作流程MCU启动流程通信协议,SPIIICMCU怎么选型,STM32F1和F4有什么区别外部RAM和内部RAM区别,怎么分配外部总线和内部总线区别MCU上的固件,数据是怎么分配的MCU启动流程IAP是怎么升级的,突然断电怎么办挑了麦轮项目(因为大疆RM也是麦轮,面试官看样子比较感兴趣)为什么用的CAN总线你说一下spi和i2c和UART的各自的工作方式优缺点</div> </li> <li><a href="/article/1835285812716072960.htm" title="[面试高频问题]关于多线程的单例模式" target="_blank">[面试高频问题]关于多线程的单例模式</a> <span class="text-muted">朱玥玥要每天学习</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>单例模式什么是设计模式?设计模式可以看做为框架或者是围棋中的”棋谱”,红方当头炮,黑方马来跳.根据一些固定的套路下,能保证局势不会吃亏.在日常的程序设计中,往往有许多业务场景,根据这些场景,大佬们总结出了一些固定的套路.按照这个套路来实现代码,也不会吃亏.什么是单例模式,保证某类在程序中只有一个实例,而不会创建多份实例.单例模式具体的实现方式:可分为”懒汉模式”,”饿汉模式”.饿汉模式类加载的同时</div> </li> <li><a href="/article/1835261105010733056.htm" title="题解 | #完全数计算#不知道为什么没超时的暴力解法" target="_blank">题解 | #完全数计算#不知道为什么没超时的暴力解法</a> <span class="text-muted">huaxinjiayou</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>兄弟们,坚持就是胜利啊,找工作从去年秋招就开始找,到五月底才收到第一个offer星环的,然后六月初t咋六月了还有面试啊,有兄弟了解这个部门吗面完了家人们,纯纯kpi啊,上来就是一道题是打印多个字符串的华为接头人话术指南:欲投华为,必看此贴!引流华为招聘提前批【奖】这个夏天,和牛牛一起打卡刷题~Java面试实战项目25届本科找暑期实习的历程飞猪旅行运营岗面经百度视觉算法一面面经感谢牛友们,腾子pcg</div> </li> <li><a href="/article/1835247497774198784.htm" title="【Java】面试题31:栈的压入,弹出序列" target="_blank">【Java】面试题31:栈的压入,弹出序列</a> <span class="text-muted">小小核桃</span> <a class="tag" taget="_blank" href="/search/%E5%89%91%E6%8C%87offer/1.htm">剑指offer</a><a class="tag" taget="_blank" href="/search/java%E7%89%88/1.htm">java版</a> <div>~~题目:~~输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列{1,2,3,4,5}是某栈的压栈序列,序列{4,5,3,2,1}是该压栈序列对应的一个弹出序列,但{4,3,5,1,2}就不可能是该栈序列的弹出序列。思路:首先借助一个辅助栈,把输入的第一个序列中的数字依次压入该辅助栈,并按照第二个序列的顺序依次从该栈中弹出数</div> </li> <li><a href="/article/56.htm" title="多线程编程之存钱与取钱" target="_blank">多线程编程之存钱与取钱</a> <span class="text-muted">周凡杨</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E9%92%B1/1.htm">存钱</a><a class="tag" taget="_blank" href="/search/%E5%8F%96%E9%92%B1/1.htm">取钱</a> <div>  生活费问题是这样的:学生每月都需要生活费,家长一次预存一段时间的生活费,家长和学生使用统一的一个帐号,在学生每次取帐号中一部分钱,直到帐号中没钱时 通知家长存钱,而家长看到帐户还有钱则不存钱,直到帐户没钱时才存钱。   问题分析:首先问题中有三个实体,学生、家长、银行账户,所以设计程序时就要设计三个类。其中银行账户只有一个,学生和家长操作的是同一个银行账户,学生的行为是</div> </li> <li><a href="/article/183.htm" title="java中数组与List相互转换的方法" target="_blank">java中数组与List相互转换的方法</a> <span class="text-muted">征客丶</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jsonp/1.htm">jsonp</a> <div>1.List转换成为数组。(这里的List是实体是ArrayList)   调用ArrayList的toArray方法。   toArray   public T[] toArray(T[] a)返回一个按照正确的顺序包含此列表中所有元素的数组;返回数组的运行时类型就是指定数组的运行时类型。如果列表能放入指定的数组,则返回放入此列表元素的数组。否则,将根据指定数组的运行时类型和此列表的大小分</div> </li> <li><a href="/article/310.htm" title="Shell 流程控制" target="_blank">Shell 流程控制</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6/1.htm">流程控制</a><a class="tag" taget="_blank" href="/search/if+else/1.htm">if else</a><a class="tag" taget="_blank" href="/search/while/1.htm">while</a><a class="tag" taget="_blank" href="/search/case/1.htm">case</a><a class="tag" taget="_blank" href="/search/shell/1.htm">shell</a> <div>Shell 流程控制 和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法): <?php if(isset($_GET["q"])){ search(q);}else{// 不做任何事情} 在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else,就像这样 if else if if 语句语</div> </li> <li><a href="/article/437.htm" title="Linux服务器新手操作之二" target="_blank">Linux服务器新手操作之二</a> <span class="text-muted">周凡杨</span> <a class="tag" taget="_blank" href="/search/Linux+%E7%AE%80%E5%8D%95+%E6%93%8D%E4%BD%9C/1.htm">Linux 简单 操作</a> <div>1.利用关键字搜寻Man Pages    man -k keyword  其中-k 是选项,keyword是要搜寻的关键字 如果现在想使用whoami命令,但是只记住了前3个字符who,就可以使用 man -k who来搜寻关键字who的man命令       [haself@HA5-DZ26 ~]$ man -k </div> </li> <li><a href="/article/564.htm" title="socket聊天室之服务器搭建" target="_blank">socket聊天室之服务器搭建</a> <span class="text-muted">朱辉辉33</span> <a class="tag" taget="_blank" href="/search/socket/1.htm">socket</a> <div>因为我们做的是聊天室,所以会有多个客户端,每个客户端我们用一个线程去实现,通过搭建一个服务器来实现从每个客户端来读取信息和发送信息。    我们先写客户端的线程。 public class ChatSocket extends Thread{ Socket socket; public ChatSocket(Socket socket){ this.sock</div> </li> <li><a href="/article/691.htm" title="利用finereport建设保险公司决策分析系统的思路和方法" target="_blank">利用finereport建设保险公司决策分析系统的思路和方法</a> <span class="text-muted">老A不折腾</span> <a class="tag" taget="_blank" href="/search/finereport/1.htm">finereport</a><a class="tag" taget="_blank" href="/search/%E9%87%91%E8%9E%8D%E4%BF%9D%E9%99%A9/1.htm">金融保险</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E6%9E%90%E7%B3%BB%E7%BB%9F/1.htm">分析系统</a><a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E7%B3%BB%E7%BB%9F/1.htm">报表系统</a><a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91/1.htm">项目开发</a> <div>决策分析系统呈现的是数据页面,也就是俗称的报表,报表与报表间、数据与数据间都按照一定的逻辑设定,是业务人员查看、分析数据的平台,更是辅助领导们运营决策的平台。底层数据决定上层分析,所以建设决策分析系统一般包括数据层处理(数据仓库建设)。   项目背景介绍 通常,保险公司信息化程度很高,基本上都有业务处理系统(像集团业务处理系统、老业务处理系统、个人代理人系统等)、数据服务系统(通过</div> </li> <li><a href="/article/818.htm" title="始终要页面在ifream的最顶层" target="_blank">始终要页面在ifream的最顶层</a> <span class="text-muted">林鹤霄</span> <div>index.jsp中有ifream,但是session消失后要让login.jsp始终显示到ifream的最顶层。。。始终没搞定,后来反复琢磨之后,得到了解决办法,在这儿给大家分享下。。 index.jsp--->主要是加了颜色的那一句 <html> <iframe name="top" ></iframe> <ifram</div> </li> <li><a href="/article/945.htm" title="MySQL binlog恢复数据" target="_blank">MySQL binlog恢复数据</a> <span class="text-muted">aigo</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>1,先确保my.ini已经配置了binlog:   # binlog log_bin = D:/mysql-5.6.21-winx64/log/binlog/mysql-bin.log log_bin_index = D:/mysql-5.6.21-winx64/log/binlog/mysql-bin.index log_error = D:/mysql-5.6.21-win</div> </li> <li><a href="/article/1072.htm" title="OCX打成CBA包并实现自动安装与自动升级" target="_blank">OCX打成CBA包并实现自动安装与自动升级</a> <span class="text-muted">alxw4616</span> <a class="tag" taget="_blank" href="/search/ocx/1.htm">ocx</a><a class="tag" taget="_blank" href="/search/cab/1.htm">cab</a> <div>近来手上有个项目,需要使用ocx控件 (ocx是什么? http://baike.baidu.com/view/393671.htm) 在生产过程中我遇到了如下问题. 1. 如何让 ocx 自动安装?     a) 如何签名?     b) 如何打包?     c) 如何安装到指定目录? 2.</div> </li> <li><a href="/article/1199.htm" title="Hashmap队列和PriorityQueue队列的应用" target="_blank">Hashmap队列和PriorityQueue队列的应用</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/Hashmap%E9%98%9F%E5%88%97/1.htm">Hashmap队列</a><a class="tag" taget="_blank" href="/search/PriorityQueue%E9%98%9F%E5%88%97/1.htm">PriorityQueue队列</a> <div>  HashMap队列已经是学过了的,但是最近在用的时候不是很熟悉,刚刚重新看以一次,   HashMap是K,v键 ,值     put()添加元素      //下面试HashMap去掉重复的 package com.hashMapandPriorityQueue; import java.util.H</div> </li> <li><a href="/article/1326.htm" title="JDK1.5 returnvalue实例" target="_blank">JDK1.5 returnvalue实例</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/java%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">java多线程</a><a class="tag" taget="_blank" href="/search/returnvalue/1.htm">returnvalue</a> <div>Callable接口: 返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。 Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。        ExecutorService接口方</div> </li> <li><a href="/article/1453.htm" title="angularjs指令中动态编译的方法(适用于有异步请求的情况) 内嵌指令无效" target="_blank">angularjs指令中动态编译的方法(适用于有异步请求的情况) 内嵌指令无效</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a> <div>        在directive的link中有一个$http请求,当请求完成后根据返回的值动态做element.append('......');这个操作,能显示没问题,可问题是我动态组的HTML里面有ng-click,发现显示出来的内容根本不执行ng-click绑定的方法!     </div> </li> <li><a href="/article/1580.htm" title="【Java范型二】Java范型详解之extend限定范型参数的类型" target="_blank">【Java范型二】Java范型详解之extend限定范型参数的类型</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/extend/1.htm">extend</a> <div>在第一篇中,定义范型类时,使用如下的方式:   public class Generics<M, S, N> { //M,S,N是范型参数 }  这种方式定义的范型类有两个基本的问题:   1. 范型参数定义的实例字段,如private M m = null;由于M的类型在运行时才能确定,那么我们在类的方法中,无法使用m,这跟定义pri</div> </li> <li><a href="/article/1707.htm" title="【HBase十三】HBase知识点总结" target="_blank">【HBase十三】HBase知识点总结</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/hbase/1.htm">hbase</a> <div>1. 数据从MemStore flush到磁盘的触发条件有哪些?    a.显式调用flush,比如flush 'mytable'    b.MemStore中的数据容量超过flush的指定容量,hbase.hregion.memstore.flush.size,默认值是64M 2. Region的构成是怎么样? 1个Region由若干个Store组成</div> </li> <li><a href="/article/1834.htm" title="服务器被DDOS攻击防御的SHELL脚本" target="_blank">服务器被DDOS攻击防御的SHELL脚本</a> <span class="text-muted">ronin47</span> <div>mkdir /root/bin vi /root/bin/dropip.sh #!/bin/bash/bin/netstat -na|grep ESTABLISHED|awk ‘{print $5}’|awk -F:‘{print $1}’|sort|uniq -c|sort -rn|head -10|grep -v -E ’192.168|127.0′|awk ‘{if($2!=null&a</div> </li> <li><a href="/article/1961.htm" title="java程序员生存手册-craps 游戏-一个简单的游戏" target="_blank">java程序员生存手册-craps 游戏-一个简单的游戏</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> import java.util.Random; public class CrapsGame { /** * *一个简单的赌*博游戏,游戏规则如下: *玩家掷两个骰子,点数为1到6,如果第一次点数和为7或11,则玩家胜, *如果点数和为2、3或12,则玩家输, *如果和为其它点数,则记录第一次的点数和,然后继续掷骰,直至点数和等于第一次掷出的点</div> </li> <li><a href="/article/2088.htm" title="TOMCAT启动提示NB: JAVA_HOME should point to a JDK not a JRE解决" target="_blank">TOMCAT启动提示NB: JAVA_HOME should point to a JDK not a JRE解决</a> <span class="text-muted">开窍的石头</span> <a class="tag" taget="_blank" href="/search/JAVA_HOME/1.htm">JAVA_HOME</a> <div>当tomcat是解压的时候,用eclipse启动正常,点击startup.bat的时候启动报错; 报错如下:   The JAVA_HOME environment variable is not defined correctly This environment variable is needed to run this program NB: JAVA_HOME shou</div> </li> <li><a href="/article/2215.htm" title="[操作系统内核]操作系统与互联网" target="_blank">[操作系统内核]操作系统与互联网</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/1.htm">操作系统</a> <div>      我首先申明:我这里所说的问题并不是针对哪个厂商的,仅仅是描述我对操作系统技术的一些看法       操作系统是一种与硬件层关系非常密切的系统软件,按理说,这种系统软件应该是由设计CPU和硬件板卡的厂商开发的,和软件公司没有直接的关系,也就是说,操作系统应该由做硬件的厂商来设计和开发</div> </li> <li><a href="/article/2342.htm" title="富文本框ckeditor_4.4.7 文本框的简单使用 支持IE11" target="_blank">富文本框ckeditor_4.4.7 文本框的简单使用 支持IE11</a> <span class="text-muted">cuityang</span> <a class="tag" taget="_blank" href="/search/%E5%AF%8C%E6%96%87%E6%9C%AC%E6%A1%86/1.htm">富文本框</a> <div><html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>知识库内容编辑</tit</div> </li> <li><a href="/article/2469.htm" title="Property null not found" target="_blank">Property null not found</a> <span class="text-muted">darrenzhu</span> <a class="tag" taget="_blank" href="/search/datagrid/1.htm">datagrid</a><a class="tag" taget="_blank" href="/search/Flex/1.htm">Flex</a><a class="tag" taget="_blank" href="/search/Advanced/1.htm">Advanced</a><a class="tag" taget="_blank" href="/search/propery+null/1.htm">propery null</a> <div>When you got error message like "Property null not found ***", try to fix it by the following way: 1)if you are using AdvancedDatagrid, make sure you only update the data in the data prov</div> </li> <li><a href="/article/2596.htm" title="MySQl数据库字符串替换函数使用" target="_blank">MySQl数据库字符串替换函数使用</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E5%87%BD%E6%95%B0/1.htm">函数</a><a class="tag" taget="_blank" href="/search/%E6%9B%BF%E6%8D%A2/1.htm">替换</a> <div>需求:需要将数据表中一个字段的值里面的所有的  .   替换成  _   原来的数据是  site.title  site.keywords  .... 替换后要为     site_title  site_keywords   使用的SQL语句如下:   updat</div> </li> <li><a href="/article/2723.htm" title="mac上终端起动MySQL的方法" target="_blank">mac上终端起动MySQL的方法</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/mac/1.htm">mac</a> <div>首先去官网下载: http://www.mysql.com/downloads/ 我下载了5.6.11的dmg然后安装,安装完成之后..如果要用终端去玩SQL.那么一开始要输入很长的:/usr/local/mysql/bin/mysql 这不方便啊,好想像windows下的cmd里面一样输入mysql -uroot -p1这样...上网查了下..可以实现滴. 打开终端,输入: 1</div> </li> <li><a href="/article/2850.htm" title="Gson使用一(Gson)" target="_blank">Gson使用一(Gson)</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/gson/1.htm">gson</a> <div>转载请出自出处:http://eksliang.iteye.com/blog/2175401 一.概述 从结构上看Json,所有的数据(data)最终都可以分解成三种类型: 第一种类型是标量(scalar),也就是一个单独的字符串(string)或数字(numbers),比如"ickes"这个字符串。 第二种类型是序列(sequence),又叫做数组(array)</div> </li> <li><a href="/article/2977.htm" title="android点滴4" target="_blank">android点滴4</a> <span class="text-muted">gundumw100</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>Android 47个小知识 http://www.open-open.com/lib/view/open1422676091314.html Android实用代码七段(一) http://www.cnblogs.com/over140/archive/2012/09/26/2611999.html http://www.cnblogs.com/over140/arch</div> </li> <li><a href="/article/3104.htm" title="JavaWeb之JSP基本语法" target="_blank">JavaWeb之JSP基本语法</a> <span class="text-muted">ihuning</span> <a class="tag" taget="_blank" href="/search/javaweb/1.htm">javaweb</a> <div>  目录   JSP模版元素  JSP表达式  JSP脚本片断  EL表达式  JSP注释  特殊字符序列的转义处理  如何查找JSP页面中的错误   JSP模版元素    JSP页面中的静态HTML内容称之为JSP模版元素,在静态的HTML内容之中可以嵌套JSP</div> </li> <li><a href="/article/3231.htm" title="App Extension编程指南(iOS8/OS X v10.10)中文版" target="_blank">App Extension编程指南(iOS8/OS X v10.10)中文版</a> <span class="text-muted">啸笑天</span> <a class="tag" taget="_blank" href="/search/ext/1.htm">ext</a> <div>         当iOS 8.0和OS X v10.10发布后,一个全新的概念出现在我们眼前,那就是应用扩展。顾名思义,应用扩展允许开发者扩展应用的自定义功能和内容,能够让用户在使用其他app时使用该项功能。你可以开发一个应用扩展来执行某些特定的任务,用户使用该扩展后就可以在多个上下文环境中执行该任务。比如说,你提供了一个能让用户把内容分</div> </li> <li><a href="/article/3358.htm" title="SQLServer实现无限级树结构" target="_blank">SQLServer实现无限级树结构</a> <span class="text-muted">macroli</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/SQL+Server/1.htm">SQL Server</a> <div> 表结构如下: 数据库id path titlesort 排序 1 0 首页 0 2 0,1 新闻 1 3 0,2 JAVA 2 4 0,3 JSP 3 5 0,2,3 业界动态 2 6 0,2,3 国内新闻 1 创建一个存储过程来实现,如果要在页面上使用可以设置一个返回变量将至传过去   create procedure test as begin decla</div> </li> <li><a href="/article/3485.htm" title="Css居中div,Css居中img,Css居中文本,Css垂直居中div" target="_blank">Css居中div,Css居中img,Css居中文本,Css垂直居中div</a> <span class="text-muted">qiaolevip</span> <a class="tag" taget="_blank" href="/search/%E4%BC%97%E8%A7%82%E5%8D%83%E8%B1%A1/1.htm">众观千象</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E6%B0%B8%E6%97%A0%E6%AD%A2%E5%A2%83/1.htm">学习永无止境</a><a class="tag" taget="_blank" href="/search/%E6%AF%8F%E5%A4%A9%E8%BF%9B%E6%AD%A5%E4%B8%80%E7%82%B9%E7%82%B9/1.htm">每天进步一点点</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>/**********Css居中Div**********/ div.center { width: 100px; margin: 0 auto; } /**********Css居中img**********/ img.center { display: block; margin-left: auto; margin-right: auto; } </div> </li> <li><a href="/article/3612.htm" title="Oracle 常用操作(实用)" target="_blank">Oracle 常用操作(实用)</a> <span class="text-muted">吃猫的鱼</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a> <div> SQL>select text from all_source where owner=user and name=upper('&plsql_name');  SQL>select * from user_ind_columns where index_name=upper('&index_name');  将表记录恢复到指定时间段以前</div> </li> <li><a href="/article/3739.htm" title="iOS中使用RSA对数据进行加密解密" target="_blank">iOS中使用RSA对数据进行加密解密</a> <span class="text-muted">witcheryne</span> <a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/rsa/1.htm">rsa</a><a class="tag" taget="_blank" href="/search/iPhone/1.htm">iPhone</a><a class="tag" taget="_blank" href="/search/objective+c/1.htm">objective c</a> <div>  RSA算法是一种非对称加密算法,常被用于加密数据传输.如果配合上数字摘要算法, 也可以用于文件签名. 本文将讨论如何在iOS中使用RSA传输加密数据. 本文环境 mac os  openssl-1.0.1j, openssl需要使用1.x版本, 推荐使用[homebrew](http://brew.sh/)安装. Java 8 RSA基本原理 RS</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>