let 闭包
let 会产生临时性死区,在以后的执行上下文中,会进行变量晋升,然而未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就援用此变量就会报错,此变量未初始化。
数组的遍历办法有哪些
办法 | 是否扭转原数组 | 特点 |
---|---|---|
forEach() | 否 | 数组办法,不扭转原数组,没有返回值 |
map() | 否 | 数组办法,不扭转原数组,有返回值,可链式调用 |
filter() | 否 | 数组办法,过滤数组,返回蕴含符合条件的元素的数组,可链式调用 |
for…of | 否 | for…of 遍历具备 Iterator 迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历一般的 obj 对象,将异步循环变成同步循环 |
every() 和 some() | 否 | 数组办法,some()只有有一个是 true,便返回 true;而 every()只有有一个是 false,便返回 false. |
find() 和 findIndex() | 否 | 数组办法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值 |
reduce() 和 reduceRight() | 否 | 数组办法,reduce()对数组正序操作;reduceRight()对数组逆序操作 |
其余值到字符串的转换规则?
- Null 和 Undefined 类型,null 转换为 “null”,undefined 转换为 “undefined”,
- Boolean 类型,true 转换为 “true”,false 转换为 “false”。
- Number 类型的值间接转换,不过那些极小和极大的数字会应用指数模式。
- Symbol 类型的值间接转换,然而只容许显式强制类型转换,应用隐式强制类型转换会产生谬误。
- 对一般对象来说,除非自行定义 toString() 办法,否则会调用 toString()(Object.prototype.toString())来返回外部属性 [[Class]] 的值,如 ”[object Object]”。如果对象有本人的 toString() 办法,字符串化时就会调用该办法并应用其返回值。
浏览器是如何对 HTML5 的离线贮存资源进行治理和加载?
- 在线的状况下,浏览器发现 html 头部有 manifest 属性,它会申请 manifest 文件,如果是第一次拜访页面,那么浏览器就会依据 manifest 文件的内容下载相应的资源并且进行离线存储。如果曾经拜访过页面并且资源曾经进行离线存储了,那么浏览器就会应用离线的资源加载页面,而后浏览器会比照新的 manifest 文件与旧的 manifest 文件,如果文件没有产生扭转,就不做任何操作,如果文件扭转了,就会从新下载文件中的资源并进行离线存储。
- 离线的状况下,浏览器会间接应用离线存储的资源。
当在浏览器中输出 Google.com 并且按下回车之后产生了什么?
(1)解析 URL: 首先会对 URL 进行解析,剖析所须要应用的传输协定和申请的资源的门路。如果输出的 URL 中的协定或者主机名不非法,将会把地址栏中输出的内容传递给搜索引擎。如果没有问题,浏览器会查看 URL 中是否呈现了非法字符,如果存在非法字符,则对非法字符进行本义后再进行下一过程。
(2)缓存判断: 浏览器会判断所申请的资源是否在缓存里,如果申请的资源在缓存里并且没有生效,那么就间接应用,否则向服务器发动新的申请。
(3)DNS 解析: 下一步首先须要获取的是输出的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则应用,如果没有则向本地 DNS 服务器发动申请。本地 DNS 服务器也会先查看是否存在缓存,如果没有就会先向根域名服务器发动申请,取得负责的顶级域名服务器的地址后,再向顶级域名服务器申请,而后取得负责的权威域名服务器的地址后,再向权威域名服务器发动申请,最终取得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给申请的用户。用户向本地 DNS 服务器发动申请属于递归申请,本地 DNS 服务器向各级域名服务器发动申请属于迭代申请。
(4)获取 MAC 地址: 当浏览器失去 IP 地址后,数据传输还须要晓得目标主机 MAC 地址,因为应用层下发数据给传输层,TCP 协定会指定源端口号和目标端口号,而后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目标地址。而后将下发给数据链路层,数据链路层的发送须要退出通信单方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目标 MAC 地址须要分状况解决。通过将 IP 地址与本机的子网掩码相与,能够判断是否与申请主机在同一个子网里,如果在同一个子网里,能够应用 APR 协定获取到目标主机的 MAC 地址,如果不在一个子网里,那么申请应该转发给网关,由它代为转发,此时同样能够通过 ARP 协定来获取网关的 MAC 地址,此时目标主机的 MAC 地址应该为网关的地址。
(5)TCP 三次握手: 上面是 TCP 建设连贯的三次握手的过程,首先客户端向服务器发送一个 SYN 连贯申请报文段和一个随机序号,服务端接管到申请后向服务器端发送一个 SYN ACK 报文段,确认连贯申请,并且也向客户端发送一个随机序号。客户端接管服务器的确认应答后,进入连贯建设的状态,同时向服务器也发送一个 ACK 确认报文段,服务器端接管到确认后,也进入连贯建设状态,此时单方的连贯就建设起来了。
(6)HTTPS 握手: 如果应用的是 HTTPS 协定,在通信前还存在 TLS 的一个四次握手的过程。首先由客户端向服务器端发送应用的协定的版本号、一个随机数和能够应用的加密办法。服务器端收到后,确认加密的办法,也向客户端发送一个随机数和本人的数字证书。客户端收到后,首先查看数字证书是否无效,如果无效,则再生成一个随机数,并应用证书中的公钥对随机数加密,而后发送给服务器端,并且还会提供一个后面所有内容的 hash 值供服务器端测验。服务器端接管后,应用本人的私钥对数据解密,同时向客户端发送一个后面所有内容的 hash 值供客户端测验。这个时候单方都有了三个随机数,依照之前所约定的加密办法,应用这三个随机数生成一把秘钥,当前单方通信前,就应用这个秘钥对数据进行加密后再传输。
(7)返回数据: 当页面申请发送到服务器端后,服务器端会返回一个 html 文件作为响应,浏览器接管到响应后,开始对 html 文件进行解析,开始页面的渲染过程。
(8)页面渲染: 浏览器首先会依据 html 文件构建 DOM 树,依据解析到的 css 文件构建 CSSOM 树,如果遇到 script 标签,则判端是否含有 defer 或者 async 属性,要不然 script 的加载和执行会造成页面的渲染的阻塞。当 DOM 树和 CSSOM 树建设好后,依据它们来构建渲染树。渲染树构建好后,会依据渲染树来进行布局。布局实现后,最初应用浏览器的 UI 接口对页面进行绘制。这个时候整个页面就显示进去了。
(9)TCP 四次挥手: 最初一步是 TCP 断开连接的四次挥手过程。若客户端认为数据发送实现,则它须要向服务端发送连贯开释申请。服务端收到连贯开释申请后,会通知应用层要开释 TCP 链接。而后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明客户端到服务端的连贯曾经开释,不再接管客户端发的数据了。然而因为 TCP 连贯是双向的,所以服务端仍旧能够发送数据给客户端。服务端如果此时还有没发完的数据会持续发送,结束后会向客户端发送连贯开释申请,而后服务端便进入 LAST-ACK 状态。客户端收到开释申请后,向服务端发送确认应答,此时客户端进入 TIME-WAIT 状态。该状态会继续 2MSL(最大段生存期,指报文段在网络中生存的工夫,超时会被摈弃)工夫,若该时间段内没有服务端的重发申请的话,就进入 CLOSED 状态。当服务端收到确认应答后,也便进入 CLOSED 状态。
async/await 如何捕捉异样
async function fn(){
try{let a = await Promise.reject('error')
}catch(error){console.log(error)
}
}
参考 前端进阶面试题具体解答
TCP 和 UDP 的概念及特点
TCP 和 UDP 都是传输层协定,他们都属于 TCP/IP 协定族:
(1)UDP
UDP 的全称是 用户数据报协定,在网络中它与 TCP 协定一样用于解决数据包,是一种无连贯的协定。在 OSI 模型中,在传输层,处于 IP 协定的上一层。UDP 有不提供数据包分组、组装和不能对数据包进行排序的毛病,也就是说,当报文发送之后,是无奈得悉其是否平安残缺达到的。
它的特点如下:
1)面向无连贯
首先 UDP 是不须要和 TCP 一样在发送数据前进行三次握手建设连贯的,想发数据就能够开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
具体来说就是:
- 在发送端,应用层将数据传递给传输层的 UDP 协定,UDP 只会给数据减少一个 UDP 头标识下是 UDP 协定,而后就传递给网络层了
- 在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
2)有单播,多播,播送的性能
UDP 不止反对一对一的传输方式,同样反对一对多,多对多,多对一的形式,也就是说 UDP 提供了单播,多播,播送的性能。
3)面向报文
发送方的 UDP 对应用程序交下来的报文,在增加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因而,应用程序必须抉择适合大小的报文
4)不可靠性
首先不可靠性体现在无连贯上,通信都不须要建设连贯,想发就发,这样的状况必定不牢靠。
并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关怀对方是否曾经正确接管到数据了。
再者网络环境时好时坏,然而 UDP 因为没有拥塞管制,始终会以恒定的速度发送数据。即便网络条件不好,也不会对发送速率进行调整。这样实现的弊病就是在网络条件不好的状况下可能会导致丢包,然而长处也很显著,在某些实时性要求高的场景(比方电话会议)就须要应用 UDP 而不是 TCP。
5)头部开销小,传输数据报文时是很高效的。
UDP 头部蕴含了以下几个数据:
- 两个十六位的端口号,别离为源端口(可选字段)和指标端口
- 整个数据报文的长度
- 整个数据报文的测验和(IPv4 可选字段),该字段用于发现头部信息和数据中的谬误
因而 UDP 的头部开销小,只有 8 字节,相比 TCP 的至多 20 字节要少得多,在传输数据报文时是很高效的。
(2)TCP TCP 的全称是传输控制协议是一种面向连贯的、牢靠的、基于字节流的传输层通信协议。TCP 是面向连贯的、牢靠的流协定(流就是指不间断的数据结构)。
它有以下几个特点:
1)面向连贯
面向连贯,是指发送数据之前必须在两端建设连贯。建设连贯的办法是“三次握手”,这样能建设牢靠的连贯。建设连贯,是为数据的牢靠传输打下了根底。
2)仅反对单播传输
每条 TCP 传输连贯只能有两个端点,只能进行点对点的数据传输,不反对多播和播送传输方式。
3)面向字节流
TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的状况下以字节流形式进行传输。
4)牢靠传输
对于牢靠传输,判断丢包、误码靠的是 TCP 的段编号以及确认号。TCP 为了保障报文传输的牢靠,就给每个包一个序号,同时序号也保障了传送到接收端实体的包的按序接管。而后接收端实体对已胜利收到的字节发回一个相应的确认 (ACK);如果发送端实体在正当的往返时延(RTT) 内未收到确认,那么对应的数据(假如失落了)将会被重传。
5)提供拥塞管制
当网络呈现拥塞的时候,TCP 可能减小向网络注入数据的速率和数量,缓解拥塞。
6)提供全双工通信
TCP 容许通信单方的应用程序在任何时候都能发送数据,因为 TCP 连贯的两端都设有缓存,用来长期寄存双向通信的数据。当然,TCP 能够立刻发送一个数据段,也能够缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于 MSS)
渐进加强和优雅降级之间的区别
(1)渐进加强(progressive enhancement):次要是针对低版本的浏览器进行页面重构,保障根本的性能状况下,再针对高级浏览器进行成果、交互等方面的改良和追加性能,以达到更好的用户体验。(2)优雅降级 graceful degradation:一开始就构建残缺的性能,而后再针对低版本的浏览器进行兼容。
两者区别:
- 优雅降级是从简单的现状开始的,并试图缩小用户体验的供应;而渐进加强是从一个十分根底的,可能起作用的版本开始的,并在此基础上一直裁减,以适应将来环境的须要;
- 降级(性能衰竭)意味着往回看,而渐进加强则意味着往前看,同时保障其根基处于平安地带。
“优雅降级”观点认为应该针对那些最高级、最欠缺的浏览器来设计网站。而将那些被认为“过期”或有性能缺失的浏览器下的测试工作安顿在开发周期的最初阶段,并把测试对象限定为支流浏览器(如 IE、Mozilla 等)的前一个版本。在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却不妨 (poor, but passable)”的浏览体验。能够做一些小的调整来适应某个特定的浏览器。但因为它们并非咱们所关注的焦点,因而除了修复较大的谬误之外,其它的差别将被间接疏忽。
“渐进加强”观点则认为应关注于内容自身。内容是建设网站的诱因,有的网站展现它,有的则收集它,有的寻求,有的操作,还有的网站甚至会蕴含以上的种种,但相同点是它们全都波及到内容。这使得“渐进加强”成为一种更为正当的设计范例。这也是它立刻被 Yahoo 所驳回并用以构建其“分级式浏览器反对 (Graded Browser Support)”策略的起因所在。
for…in 和 for…of 的区别
for…of 是 ES6 新增的遍历形式,容许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,和 ES3 中的 for…in 的区别如下
- for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
- for… in 会遍历对象的整个原型链,性能十分差不举荐应用,而 for … of 只遍历以后对象不会遍历原型链;
- 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包含原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
总结: for…in 循环次要是为了遍历对象而生,不适用于遍历数组;for…of 循环能够用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。
三栏布局的实现
三栏布局个别指的是页面中一共有三栏,左右两栏宽度固定,两头自适应的布局,三栏布局的具体实现:
- 利用 相对定位,左右两栏设置为相对定位,两头设置对应方向大小的 margin 的值。
.outer {
position: relative;
height: 100px;
}
.left {
position: absolute;
width: 100px;
height: 100px;
background: tomato;
}
.right {
position: absolute;
top: 0;
right: 0;
width: 200px;
height: 100px;
background: gold;
}
.center {
margin-left: 100px;
margin-right: 200px;
height: 100px;
background: lightgreen;
}
- 利用 flex 布局,左右两栏设置固定大小,两头一栏设置为 flex:1。
.outer {
display: flex;
height: 100px;
}
.left {
width: 100px;
background: tomato;
}
.right {
width: 100px;
background: gold;
}
.center {
flex: 1;
background: lightgreen;
}
- 利用浮动,左右两栏设置固定大小,并设置对应方向的浮动。两头一栏设置左右两个方向的 margin 值,留神这种形式,两头一栏必须放到最初:
.outer {height: 100px;}
.left {
float: left;
width: 100px;
height: 100px;
background: tomato;
}
.right {
float: right;
width: 200px;
height: 100px;
background: gold;
}
.center {
height: 100px;
margin-left: 100px;
margin-right: 200px;
background: lightgreen;
}
- 圣杯布局,利用浮动和负边距来实现。父级元素设置左右的 padding,三列均设置向左浮动,两头一列放在最后面,宽度设置为父级元素的宽度,因而前面两列都被挤到了下一行,通过设置 margin 负值将其挪动到上一行,再利用绝对定位,定位到两边。
.outer {
height: 100px;
padding-left: 100px;
padding-right: 200px;
}
.left {
position: relative;
left: -100px;
float: left;
margin-left: -100%;
width: 100px;
height: 100px;
background: tomato;
}
.right {
position: relative;
left: 200px;
float: right;
margin-left: -200px;
width: 200px;
height: 100px;
background: gold;
}
.center {
float: left;
width: 100%;
height: 100px;
background: lightgreen;
}
- 双飞翼布局,双飞翼布局绝对于圣杯布局来说,左右地位的保留是通过两头列的 margin 值来实现的,而不是通过父元素的 padding 来实现的。实质上来说,也是通过浮动和外边距负值来实现的。
.outer {height: 100px;}
.left {
float: left;
margin-left: -100%;
width: 100px;
height: 100px;
background: tomato;
}
.right {
float: left;
margin-left: -200px;
width: 200px;
height: 100px;
background: gold;
}
.wrapper {
float: left;
width: 100%;
height: 100px;
background: lightgreen;
}
.center {
margin-left: 100px;
margin-right: 200px;
height: 100px;
}
HTTP 响应报文的是什么样的?
申请报⽂有 4 局部组成:
- 响应⾏
- 响应头
- 空⾏
- 响应体
- 响应⾏:由网络协议版本,状态码和状态码的起因短语组成,例如 HTTP/1.1 200 OK。
- 响应头:响应部⾸组成
- 响应体:服务器响应的数据
GET 办法 URL 长度限度的起因
实际上 HTTP 协定标准并没有对 get 办法申请的 url 长度进行限度,这个限度是特定的浏览器及服务器对它的限度。
IE 对 URL 长度的限度是 2083 字节(2K+35)。因为 IE 浏览器对 URL 长度的允许值是最小的,所以开发过程中,只有 URL 不超过 2083 字节,那么在所有浏览器中工作都不会有问题。
GET 的长度值 = URL(2083)-(你的 Domain+Path)-2(2 是 get 申请中?= 两个字符的长度)
上面看一下支流浏览器对 get 办法中 url 的长度限度范畴:
- Microsoft Internet Explorer (Browser):IE 浏览器对 URL 的最大限度为 2083 个字符,如果超过这个数字,提交按钮没有任何反馈。
- Firefox (Browser):对于 Firefox 浏览器 URL 的长度限度为 65,536 个字符。
- Safari (Browser):URL 最大长度限度为 80,000 个字符。
- Opera (Browser):URL 最大长度限度为 190,000 个字符。
- Google (chrome):URL 最大长度限度为 8182 个字符。
支流的服务器对 get 办法中 url 的长度限度范畴:
- Apache (Server):能承受最大 url 长度为 8192 个字符。
- Microsoft Internet Information Server(IIS):能承受最大 url 的长度为 16384 个字符。
依据下面的数据,能够晓得,get 办法中的 URL 长度最长不超过 2083 个字符,这样所有的浏览器和服务器都可能失常工作。
对盒模型的了解
CSS3 中的盒模型有以下两种:规范盒子模型、IE 盒子模型 盒模型都是由四个局部组成的,别离是 margin、border、padding 和 content。
规范盒模型和 IE 盒模型的区别在于设置 width 和 height 时,所对应的范畴不同:
- 规范盒模型的 width 和 height 属性的范畴只蕴含了 content,
- IE 盒模型的 width 和 height 属性的范畴蕴含了 border、padding 和 content。
能够通过批改元素的 box-sizing 属性来扭转元素的盒模型:
box-sizeing: content-box
示意规范盒模型(默认值)box-sizeing: border-box
示意 IE 盒模型(怪异盒模型)
title 与 h1 的区别、b 与 strong 的区别、i 与 em 的区别?
- strong 标签有语义,是起到减轻语气的成果,而 b 标签是没有的,b 标签只是一个简略加粗标签。b 标签之间的字符都设为粗体,strong 标签增强字符的语气都是通过粗体来实现的,而搜索引擎更偏重 strong 标签。
- title 属性没有明确意义只示意是个题目,H1 则示意档次明确的题目,对页面信息的抓取有很大的影响
- i 内容展现为斜体,em 示意强调的文本
CSS 预处理器 / 后处理器是什么?为什么要应用它们?
预处理器, 如:less
,sass
,stylus
,用来预编译 sass
或者 less
,减少了css
代码的复用性。层级,mixin
,变量,循环,函数等对编写以及开发 UI 组件都极为不便。
后处理器, 如:postCss
,通常是在实现的样式表中依据 css
标准解决 css
,让其更加无效。目前最常做的是给css
属性增加浏览器公有前缀,实现跨浏览器兼容性的问题。
css
预处理器为 css
减少一些编程个性,无需思考浏览器的兼容问题,能够在 CSS
中应用变量,简略的逻辑程序,函数等在编程语言中的一些根本的性能,能够让 css
更加的简洁,减少适应性以及可读性,可维护性等。
其它 css
预处理器语言:Sass(Scss)
, Less
, Stylus
, Turbine
, Swithch css
, CSS Cacheer
, DT Css
。
应用起因:
- 构造清晰,便于扩大
- 能够很不便的屏蔽浏览器公有语法的差别
- 能够轻松实现多重继承
- 完满的兼容了
CSS
代码,能够利用到老我的项目中
浏览器乱码的起因是什么?如何解决?
产生乱码的起因:
- 网页源代码是
gbk
的编码,而内容中的中文字是utf-8
编码的,这样浏览器关上即会呈现html
乱码,反之也会呈现乱码; html
网页编码是gbk
,而程序从数据库中调出出现是utf-8
编码的内容也会造成编码乱码;- 浏览器不能自动检测网页编码,造成网页乱码。
解决办法:
- 应用软件编辑 HTML 网页内容;
- 如果网页设置编码是
gbk
,而数据库贮存数据编码格局是UTF-8
,此时须要程序查询数据库数据显示数据后退程序转码; - 如果浏览器浏览时候呈现网页乱码,在浏览器中找到转换编码的菜单进行转换。
map 和 Object 的区别
Map | Object | |
---|---|---|
意外的键 | Map 默认状况不蕴含任何键,只蕴含显式插入的键。 | Object 有一个原型, 原型链上的键名有可能和本人在对象上的设置的键名产生抵触。 |
键的类型 | Map 的键能够是任意值,包含函数、对象或任意根本类型。 | Object 的键必须是 String 或是 Symbol。 |
键的程序 | Map 中的 key 是有序的。因而,当迭代的时候,Map 对象以插入的程序返回键值。 | Object 的键是无序的 |
Size | Map 的键值对个数能够轻易地通过 size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,所以能够间接被迭代。 | 迭代 Object 须要以某种形式获取它的键而后能力迭代。 |
性能 | 在频繁增删键值对的场景下体现更好。 | 在频繁增加和删除键值对的场景下未作出优化。 |
如何应用 for…of 遍历对象
for…of 是作为 ES6 新增的遍历形式,容许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,一般的对象用 for..of 遍历是会报错的。
如果须要遍历的对象是类数组对象,用 Array.from 转成数组即可。
var obj = {
0:'one',
1:'two',
length: 2
};
obj = Array.from(obj);
for(var k of obj){console.log(k)
}
如果不是类数组对象,就给对象增加一个 [Symbol.iterator] 属性,并指向一个迭代器即可。
// 办法一:var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function(){var keys = Object.keys(this);
var count = 0;
return {next(){if(count<keys.length){return {value: obj[keys[count++]],done:false};
}else{return {value:undefined,done:true};
}
}
}
};
for(var k of obj){console.log(k);
}
// 办法二
var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function*(){var keys = Object.keys(obj);
for(var k of keys){yield [k,obj[k]]
}
};
for(var [k,v] of obj){console.log(k,v);
}
forEach 和 map 办法有什么区别
这办法都是用来遍历数组的,两者区别如下:
- forEach()办法会针对每一个元素执行提供的函数,对数据的操作会扭转原数组,该办法没有返回值;
- map()办法不会扭转原数组的值,返回一个新数组,新数组中的值为原数组调用函数解决之后的值;
link 和 @import 的区别
两者都是内部援用 CSS 的形式,它们的区别如下:
- link 是 XHTML 标签,除了加载 CSS 外,还能够定义 RSS 等其余事务;@import 属于 CSS 领域,只能加载 CSS。
- link 援用 CSS 时,在页面载入时同时加载;@import 须要页面网页齐全载入当前加载。
- link 是 XHTML 标签,无兼容问题;@import 是在 CSS2.1 提出的,低版本的浏览器不反对。
- link 反对应用 Javascript 管制 DOM 去扭转款式;而 @import 不反对。