TypeScript是一种由微软开发的自由和开源的编程语言。而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。安德斯·海尔斯伯格,C#的首席架构师,已工作于TypeScript的开发。TypeScript 是 JavaScript 的超集。TypeScript是为大型应用之开发而设计。TypeScript 是JavaScript 类型化子集,它会被编译成原生的JavaScript。 TypeScript 不是「强类型」,是「静态类型检查」的「弱类型」。
TS最大的价值是引入了接口、类、继承的编程思想,TypeScript 在 ES2015 之外还提供了
-
类型
-
接口
-
未来的 ES2016+ 特性 (比如注解/装饰器以及异步/等待)
我们可以使用类似 Gulp,Grunt,WebPack,SystemJS 和 JSPM 这些工具反编译成 Babel 或者 TypeScript。
8
- 什么是HTML语义化?
根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。
- 为什么要语义化?
-
为了在没有CSS的情况下,页面也能呈现出很好地内容结构、代码结构:为了裸奔时好看;
-
用户体验:例如title、alt用于解释名词或解释图片信息、label标签的活用;
-
有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重;
-
方便其他设备解析(如屏幕阅读器、盲人阅读器、移动设备)以意义的方式来渲染网页;
-
便于团队开发和维护,语义化更具可读性,是下一步吧网页的重要动向,遵循W3C标准的团队都遵循这个标准,可以减少差异化。
- 写HTML代码时应注意什么?
-
尽可能少的使用无语义的标签div和span;
-
在语义不明显时,既可以使用div或者p时,尽量用p, 因为p在默认情况下有上下间距,对兼容特殊终端有利;
-
不要使用纯样式标签,如:b、font、u等,改用css设置。
-
需要强调的文本,可以包含在strong或者em标签中(浏览器预设样式,能用CSS指定就不用他们),strong默认样式是加粗(不要用b),em是斜体(不用i);
-
使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td;
-
表单域要用fieldset标签包起来,并用legend标签说明表单的用途;
-
每个input标签对应的说明文本都需要使用label标签,并且通过为input设置id属性,在lable标签中设置for=someld来让说明文本和相对应的input关联起来。
- section
表示文档中的一个区域(或节),比如,内容中的一个专题组,一般来说会有包含一个标题(heading)。一般通过是否包含一个标题 (<h1>-<h6> element) 作为子节点来辨识每一个<section>。一般来说,一个 <section> 应该出现在文档大纲中。
- artical
<article>元素表示文档、页面、应用或网站中的独立结构,其意在成为可独立分配的或可复用的结构,如在发布中,它可能是论坛帖子、杂志或新闻文章、博客、用户提交的评论、交互式组件,或者其他独立的内容项目。
- canvas
<canvas> 标签定义图形,比如图表和其他图像。 <canvas> 标签只是图形容器,您必须使用脚本来绘制图形。
<canvas> 标记和 SVG 以及 VML 之间的差异 <canvas> 标记和 SVG 以及 VML 之间的一个重要的不同是,<canvas> 有一个基于 JavaScript 的绘图 API,而 SVG 和 VML 使用一个 XML 文档来描述绘图。 这两种方式在功能上是等同的,任何一种都可以用另一种来模拟。从表面上看,它们很不相同,可是,每一种都有强项和弱点。例如,SVG 绘图很容易编辑,只要从其描述中移除元素就行。 要从同一图形的一个 <canvas> 标记中移除元素,往往需要擦掉绘图重新绘制它。
- 方法1:table-cell
#html结构:
<div class="box box1">
<span>垂直居中</span>
</div>
#css:
.box1{
display: table-cell;
vertical-align: middle;
text-align: center;
}
- 方法2:display:flex
#css
.box2{
display: flex;
justify-content:center;
align-items:Center;
}
- 方法3:绝对定位和负边距
#css
.box3{position:relative;}
.box3 span{
position: absolute;
width:100px;
height: 50px;
top:50%;
left:50%;
margin-left:-50px;
margin-top:-25px;
text-align: center;
}
React 和 Vue 有许多相似之处,它们都有:
- 使用 Virtual DOM
- 提供了响应式 (Reactive) 和组件化 (Composable) 的视图组件。
- 将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。
区别:
-
运行时性能 在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,所以系统能精确知晓哪个组件确实需要被重渲染。
-
HTML & CSS/模板语法 VS JSX Vue 的整体思想是拥抱经典的 Web 技术,并在其上进行扩展。 任何合乎规范的 HTML 都是合法的 Vue 模板 Vue 设置样式的默认方法是单文件组件里类似 style 的标签。单文件组件让你可以在同一个文件里完全控制 CSS,将其作为组件代码的一部分。
-
规模 两者另一个重要差异是,Vue 的路由库和状态管理库都是由官方维护支持且与核心库同步更新的。React 则是选择把这些问题交给社区维护,因此创建了一个更分散的生态系统。但相对的,React 的生态系统相比 Vue 更加繁荣。
-
原生渲染 React Native 能使你用相同的组件模型编写有本地渲染能力的 APP (iOS 和 Android)。能同时跨多平台开发,对开发者是非常棒的。
Weex 允许你使用 Vue 语法开发不仅仅可以运行在浏览器端,还能被用于开发 iOS 和 Android 上的原生应用的组件。
- 创造前端的富应用 Virtual DOM 改变真实的DOM状态远比改变一个JavaScript对象的花销要大得多。 当有变化产生时,一个新的Virtual DOM对象会被创建并计算新旧Virtual DOM之间的差别。之后这些差别会应用在真实的DOM上。*
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的,cookie的大小是受限的,并且每次请求一个新的页面的时候cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可跨域调用。 除此之外,web storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是cookie也是不可或缺的,cookie的作用是与服务器进行交互,作为http规范的一部分而存在的,而web Storage仅仅是为了在本地“存储”数据而生 sessionStorage、localStorage、cookie都是在浏览器端存储的数据,其中sessionStorage的概念很特别,引入了一个“浏览器窗口”的概念,sessionStorage是在同源的同窗口中,始终存在的数据,也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一个页面,数据仍然存在,关闭窗口后,sessionStorage就会被销毁,同时“独立”打开的不同窗口,即使是同一页面,sessionStorage对象也是不同的
Web Storage带来的好处:
-
减少网络流量:一旦数据保存在本地之后,就可以避免再向服务器请求数据,因此减少不必要的数据请求,减少数 据在浏览器和服务器间不必要的来回传递
-
快速显示数据:性能好,从本地读数据比通过网络从服务器上获得数据快得多,本地数据可以及时获得,再加上网 页本身也可以有缓存,因此整个页面和数据都在本地的话,可以立即显示
-
临时存储:很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用sessionStorage非常方便
状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
- 1xx:指示信息--表示请求已接收,继续处理
- 2xx:成功--表示请求已被成功接收、理解、接受
- 3xx:重定向--要完成请求必须进行更进一步的操作
- 4xx:客户端错误--请求有语法错误或请求无法实现
- 5xx:服务器端错误--服务器未能实现合法的请求
客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。服务端只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。
第一次访问 200 按F5刷新(第二次访问) 304 按Ctrl+F5强制刷新 200
同源策略 只有当协议、端口、和域名都相同的页面,则两个页面具有相同的源。只要网站的 协议名protocol、 主机host、 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用,会受到同源策略的限制。 同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用(通常指使用XMLHttpRequest请求)。
- nginx反向代理
- JSONP跨域 JSONP是一种跨域数据交互的协议,使用JSONP方法获取到的仍然是json格式的数据。 说白了,用JSON来传数据,靠JSONP来跨域。
JSONP(JSON with Padding)是数据格式JSON的一种“使用模式”,可以让网页从别的网域要数据。根据 XmlHttpRequest 对象受到同源策略的影响,而利用 <script>元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。用JSONP抓到的数据并不是JSON,而是任意的JavaScript,用 JavaScript解释器运行而不是用JSON解析器解析。所有,通过Chrome查看所有JSONP发送的Get请求都是js类型,而非XHR。
缺点:
只能使用Get请求 不能注册success、error等事件监听函数,不能很容易的确定JSONP请求是否失败 JSONP是从其他域中加载代码执行,容易受到跨站请求伪造的攻击,其安全性无法确保
- CORS Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,确保安全的跨域数据传输。现代浏览器使用CORS在API容器如XMLHttpRequest来减少HTTP请求的风险来源。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。服务器一般需要增加如下响应头的一种或几种:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
跨域请求默认不会携带Cookie信息,如果需要携带,请配置下述参数:
"Access-Control-Allow-Credentials": true // Ajax设置 "withCredentials": true
- 代理
超文本传输协议.
URI和URL的区别 URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。 Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的
URI一般由三部组成:
- 访问资源的命名机制
- 存放资源的主机名
- 资源自身的名称,由路径表示,着重强调于资源。
URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。 URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。 采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL一般由三部组成:
- 协议(或称为服务方式)
- 存有该资源的主机IP地址(有时也包括端口号)
- 主机资源的具体地址。如目录和文件名等
URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com
。
URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。
HTTP工作原理
HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
以下是 HTTP 请求/响应的步骤:
-
客户端连接到Web服务器 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,
http://www.oakcms.cn
。 -
发送HTTP请求 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
-
服务器接受请求并返回HTTP响应 Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
-
释放连接TCP连接 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
-
客户端浏览器解析HTML内容 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
- 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
- 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
- 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
- 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
- 释放 TCP连接;
- 浏览器将该 html 文本并显示内容;
你轻轻松松的给出了一个“标准答案”:
-
GET在浏览器回退时是无害的,而POST会再次提交请求。
-
GET产生的URL地址可以被Bookmark,而POST不可以。
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
-
GET请求只能进行url编码,而POST支持多种编码方式。
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
-
GET请求在URL中传送的参数是有长度限制的,而POST么有。
-
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
-
GET参数通过URL传递,POST放在Request body中。
(本标准答案参考自w3schools)
-
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
-
GET产生一个TCP数据包;POST产生两个TCP数据包。
XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。
XSS的防御措施
- 编码:对用户输入的数据进行HTML Entity编码
- 过滤:移除用户上传的DOM属性,如onerror等,移除用户上传的style节点,script节点,iframe节点等
- 校正:避免直接对HTML Entity编码,使用DOM Prase转换,校正不配对的DOM标签。
主流的浏览器主要包括:Firefox、Chrome、Safari、Edge、IE等,这些浏览器基于WebKit,Gecko两种内核。(各种主流浏览器内核介绍) WebKit包含两个主要部分WebCore渲染引擎(或排版引擎)和JSCore引擎(用于解析JavaScript)。
浏览器整体框架组成
-
用户界面 (User Interface) 用户之间接触的部分,通常包括地址栏、后退/前进按钮、菜单栏等。
-
浏览器引擎 (Browser Engine) 渲染引擎的查询与操作接口
-
渲染引擎 (Rendering Engine) 显示请求的内容,即页面
-
网络层 (Networking) 网络调用,例如HTTP请求,基于具体操作系统平台
-
UI后端 (UI Backend) 用于绘制图形化组件,利用操作系统的用户接口
-
JavaScript解析器 (JavaScript Interpret) 解析并执行JavaScript代码
-
数据存储(Data Storage) 数据持久层,浏览器需要将数据存储在磁盘,例如cookies
Rendering Engine
-
影响浏览器渲染方式的文档模式 每个浏览器都有自己的页面渲染引擎。渲染引擎包括两部分:一部分负责 HTML、CSS 代码的解析(渲染引擎,如 blink 引擎 or 内核),一部分负责 JavaScript 代码的解析(JavaScript 引擎,如 V8 引擎)。
-
HTML 文档的解析过程
- 纯 HTML 文档,无 CSS 和脚本
- 包含内联样式和内联脚本的 HTML 文档
- 包含外部 CSS 和脚本的 HTML 文档
- JS 解释器的工作原理
- 扫描全局变量,确定所有已声明的变量或函数名
- 顺序执行所有语句
什么是 AJAX ?
AJAX = Async JavaScript And XML
AJAX 是一种用于创建快速动态网页的技术。 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
XMLHttpRequest 是 AJAX 的基础。 所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)。 所有现代浏览器(IE7+、Firefox、Chrome、Safari 以及 Opera)均内建 XMLHttpRequest 对象。
创建 XMLHttpRequest 对象的语法:variable=new XMLHttpRequest();
var xmlhttp;
if (window.XMLHttpRequest)
{
# code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{
# code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}
xmlhttp.open("GET","test1.txt",true);
xmlhttp.send();
# 为了避免这种情况,请向 URL 添加一个唯一的 ID:
xmlhttp.open("GET","demo_get.asp?t=" +
Math.random()
,true);
xmlhttp.send();
# setRequestHeader( header , value )
# 向请求添加 HTTP 头。
# header : 规定头的名称
# value : 规定头的值
异步 - True 或 False? AJAX 指的是异步 JavaScript 和 XML(Asynchronous JavaScript and XML)。
XMLHttpRequest 对象如果要用于 AJAX 的话,其 open() 方法的 async 参数必须设置为 true.
服务器响应 如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。 responseText 获得字符串形式的响应数据。 responseXML 获得 XML 形式的响应数据。
以下为文档原话:
ECMAScript实现继承的方式不止一种。
这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。 作为开发者,你有权决定最适用的继承方式。
在JavaScript中实现继承的方法:
- 对象冒充
- call() call()方法是与经典的对象冒充方法最相似的方法。【第一个参数】用作 this 的对象。【其他参数】直接传递给函数自身。
- apply() apply() 方法有两个参数,第一个参数:【用作 this 的对象】,第二个参数:【要传递给函数的参数的数组】
- 原型链(prototype chaining)
注意: 1、原型链和对象冒充不同,原型链除了继承prototype的内容也能继承ClassA函数内的方法(注意:如果方法中含有this的引用,会出现undefined,可以通过对象冒充来解决该问题) 2、原型链不能像 call和apply一样将父类对象this改为子类对象this 3、如果要使用原型链,那么前提是父类是使用原型定义的
- 混合方式
- es6
class,extend
主要有以下几点:
- 有人可能会这样想:“我 CSS 基础这么好,让我用别人写的?闹呢!”;
- 别人的库可能有很多冗余的、自己用不到的样式,白白增加项目体积;
- 别人的库需要学习成本,自己写的不仅符合自己的 css 书写习惯,起的类名也是自己最好记的。
XHR 是什么? XMLHttpRequest 对象用于在后台与服务器交换数据。
XMLHttpRequest 对象是开发者的梦想,因为您能够:
- 在不重新加载页面的情况下更新网页
- 在页面已加载后从服务器请求数据
- 在页面已加载后从服务器接收数据
- 在后台向服务器发送数据
所有现代的浏览器都支持 XMLHttpRequest 对象。
XHR传数据会base64编码
TeX特别适合于科技论文和书籍的排版,利用它可以在计算机上生成与印刷品几乎完全一样的作品,目前在国外已经被广泛地用于编排书籍、档案、学位论文和私人信件,以及各种复杂的公式、目录、索引和参考文献等。
- 概述
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。 1991年,Rivest开发出技术上更为趋近成熟的md5算法。它在MD4的基础上增加了"安全-带子"(safety-belts)的概念。虽然MD5比MD4复杂度大一些,但却更为安全。这个算法很明显的由四个和MD4设计有少许不同的步骤组成。在MD5算法中,信息-摘要的大小和填充的必要条件与MD4完全相同。Den boer和Bosselaers曾发现MD5算法中的假冲突(pseudo-collisions),但除此之外就没有其他被发现的加密后结果了。
- 原理
对于MD5算法可以简要的概括为:MD5是以512位分组来处理输入信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
- 填充
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448,并且填充必须进行,即使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448
,N为一个非负整数,N可以是零。
-
初始化变量
-
处理分组数据
-
MD5应用
一致性验证
MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。比如,在Unix下有很多软件在下载的时候都有一个文件名相同,文件扩展名为.md5的文件,在这个文件中通常只有一行文本,大致结构如: MD5 (tanajiya.tar.gz) = 38b8c2c1093dd0fec383a9d9ac940515 这就是tanajiya.tar.gz文件的数字签名。MD5将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的MD5信息摘要。为了让读者朋友对MD5的应用有个直观的认识,笔者以一个比方和一个实例来简要描述一下其工作过程: 大家都知道,地球上任何人都有自己独一无二的指纹,这常常成为司法机关鉴别罪犯身份最值得信赖的方法;与之类似,MD5就可以为任何文件(不管其大小、格式、数量)产生一个同样独一无二的“数字指纹”,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”都会发生变化。 我们常常在某些软件下载站点的某软件信息中看到其MD5值,它的作用就在于我们可以在下载该软件后,对下载回来的文件用专门的软件(如Windows MD5 Check等)做一次MD5校验,以确保我们获得的文件与该站点提供的文件为同一文件。 具体来说文件的MD5值就像是这个文件的“数字指纹”。每个文件的MD5值是不同的,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”就会发生变化。比如下载服务器针对一个文件预先提供一个MD5值,用户下载完该文件后,用我这个算法重新计算下载文件的MD5值,通过比较这两个值是否相同,就能判断下载的文件是否出错,或者说下载的文件是否被篡改了。 利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、系统文件安全等方面。
数字签名
MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
安全访问认证
MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方面。如在Unix系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来的Hash值就行了。
- MD5特点
MD5算法具有以下特点:
- 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
- 容易计算:从原数据计算出MD5值很容易。
- 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
- 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。 MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。
文档流其实分为定位流、浮动流、普通流三种
普通流其实就是指BFC中的FC。FC(Formatting Context),直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。常见的FC有BFC、IFC,还有GFC和FFC。
BFC(Block Formatting Context)块级格式化上下文,是用于布局块级盒子的一块渲染区域。MDN上的解释:BFC是Web页面 CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。
一、BFC是什么?
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。 Box: CSS布局的基本单位
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
在一个Web页面的CSS渲染中,块级格式化上下文 (Block Fromatting Context)是按照块级盒子布局的。W3C对BFC的定义如下:
浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。 为了便于理解,我们换一种方式来重新定义BFC。一个HTML元素要创建BFC,则满足下列的任意一个或多个条件即可:
- float的值不是none。
- position的值不是static或者relative。
- display的值是inline-block、table-cell、flex、table-caption或者inline-flex
- overflow的值不是visible
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
BFC布局规则:
- 内部的Box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
- 阻止元素被浮动元素覆盖;
- 可以包含浮动元素;
- 阻止因为浏览器因为四舍五入造成的多列布局换行的情况;
- 阻止相邻元素的margin合并;
- 根元素
- float属性不为none
- position为absolute或fixed
- display为inline-block, table-cell, table-caption, flex, inline-flex
- overflow不为visible
仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新。
逐个遍历newVdom的节点,找到它在oldVdom中的位置,如果找到了就移动对应的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还有没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可。
- 优先处理特殊场景
一方面一些不需要做移动的DOM得到快速处理,另一方面待处理节点变少,缩小了后续操作的处理范围,性能也得到提升
- “原地复用”
Vue在判断更新前后指针是否指向同一个节点,其实不要求它们真实引用同一个DOM节点,实际上它仅判断指向的是否是同类节点(比如2个不同的div,在DOM上它们是不一样的,但是它们属于同类节点),如果是同类节点,那么Vue会直接复用DOM,这样的好处是不需要移动DOM。
-
第一部分是一个循环,循环内部是一个分支逻辑,每次循环只会进入其中的一个分支,每次循环会处理一个节点,处理之后将节点标记为已处理(oldVdom和newVdom都要进行标记,如果节点只出现在其中某一个vdom中,则另一个vdom中不需要进行标记),标记的方法有2种,当节点正好在vdom的指针处,移动指针将它排除到未处理列表之外即可,否则就要采用其他方法,Vue的做法是将节点设置为undefined。
-
循环结束之后,可能newVdom或者oldVdom中还有未处理的节点,如果是newVdom中有未处理节点,则这些节点是新增节点,做新增处理。如果是oldVdom中有这类节点,则这些是需要删除的节点,相应在DOM树中删除之整个过程是逐步找到更新前后vdom的差异,然后将差异反应到DOM树上(也就是patch),特别要提一下Vue的patch是即时的,并不是打包所有修改最后一起操作DOM(React则是将更新放入队列后集中处理),朋友们会问这样做性能很差吧?实际上现代浏览器对这样的DOM操作做了优化,并无差别。
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTPS协议的主要作用可以分为两种:
- 一种是建立一个信息安全通道,来保证数据传输的安全;
- 另一种就是确认网站的真实性。
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
HTTPS和HTTP的区别主要如下:
-
https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
-
http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
-
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
-
http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTP 2.0是在SPDY(An experimental protocol for a faster web, The Chromium Projects)基础上形成的下一代互联网通信协议。HTTP/2 的目的是通过支持请求与响应的多路复用来较少延迟,通过压缩HTTPS首部字段将协议开销降低,同时增加请求优先级和服务器端推送的支持。
- 二进制分帧层,是HTTP 2.0性能增强的核心。
HTTP 1.x在应用层以纯文本的形式进行通信,而HTTP 2.0将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。这样,客户端和服务端都需要引入新的二进制编码和解码的机制。
帧(frame)
HTTP 2.0通信的最小单位,包括帧首部、流标识符、优先值和帧净荷等。
消息(message)
消息是指逻辑上的HTTP消息(请求/响应)。一系列数据帧组成了一个完整的消息。比如一系列DATA帧和一个HEADERS帧组成了请求消息。
流(stream)
流是连接中的一个虚拟信道,可以承载双向消息传输。每个流有唯一整数标识符。为了防止两端流ID冲突,客户端发起的流具有奇数ID,服务器端发起的流具有偶数ID。 所有HTTP 2. 0 通信都在一个TCP连接上完成, 这个连接可以承载任意数量的双向数据流Stream。 相应地, 每个数据流以 消息的形式发送, 而消息由一 或多个帧组成, 这些帧可以乱序发送, 然后根据每个帧首部的流标识符重新组装。 二进制分帧层保留了HTTP的语义不受影响,包括首部、方法等,在应用层来看,和HTTP 1.x没有差别。同时,所有同主机的通信能够在一个TCP连接上完成。
基于二进制分帧层,HTTP 2.0可以在共享TCP连接的基础上,同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义,交错发送出去,最后在另一端根据流ID和首部将它们重新组合起来。 性能对比,高下立见。HTTP 2.0成功解决了HTTP 1.x的队首阻塞问题(TCP层的阻塞仍无法解决),同时,也不需要通过pipeline机制多条TCP连接来实现并行请求与响应。减少了TCP连接数对服务器性能也有很大的提升。
客户端明确指定优先级,服务端可以根据这个优先级作为依据交互数据,比如客户端优先级设置为.css>.js>.jpg(具体可参见《高性能网站建设指南》), 服务端按优先级返回结果有利于高效利用底层连接,提高用户体验。 然而,也不能过分迷信请求优先级,仍然要注意以下问题:
- 服务端是否支持请求优先级
- 会否引起队首阻塞问题,比如高优先级的慢响应请求会阻塞其他资源的交互。
HTTP 1.x每一次通信(请求/响应)都会携带首部信息用于描述资源属性。HTTP 2.0在客户端和服务端之间使用“首部表”来跟踪和存储之前发送的键-值对。首部表在连接过程中始终存在,新增的键-值对会更新到表尾,因此,不需要每次通信都需要再携带首部。
webpack是一个打包模块化js的工具,可以通过loader转换文件,通过plugin扩展功能。
entry 一个可执行模块或库的入口文件。 chunk 多个文件组成的一个代码块,例如把一个可执行模块和它所有依赖的模块组合和一个 chunk 这体现了webpack的打包机制。 loader 文件转换器,例如把es6转换为es5,scss转换为css。 plugin 插件,用于扩展webpack的功能,在webpack构建生命周期的节点上加入扩展hook为webpack加入功能。
从启动webpack构建到输出结果经历了一系列过程,它们是:
- 解析webpack配置参数,合并从shell传入和webpack.config.js文件里配置的参数,生产最后的配置结果。
- 注册所有配置的插件,好让插件监听webpack构建生命周期的事件节点,以做出对应的反应。
- 从配置的entry入口文件开始解析文件构建AST语法树,找出每个文件所依赖的文件,递归下去。
- 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。
- 递归完后得到每个文件的最终结果,根据entry配置生成代码块chunk。
- 输出所有chunk到文件系统。
把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载。 整个打包生成的代码是一个IIFE(立即执行函数),参数为由模块名和模块文件处理成的函数组成的对象,由此,我们可以猜测 webpack在打包时做了模块文件到函数的转换。
webpack就hack了commonjs代码。
原理还是很简单的,其实就是实现exports和require,然后自动加载入口模块,控制缓存模块,that's all。 通过__webpack_require__(0)启动入口模块。
webpack对于es模块的实现,也是基于自己实现的__webpack_require__ 和__webpack_exports__ ,装换成类似于commonjs的形式。对于es模块和commonjs混用的情况,则需要通过__webpack_require__.n的形式做一层包装来实现。
- 输入地址
- 浏览器查找域名的 IP 地址
- 这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...
- 浏览器向 web 服务器发送一个 HTTP 请求
- 服务器的永久重定向响应(从
http://example.com
到http://www.example.com
) - 浏览器跟踪重定向地址
- 服务器处理请求
- 服务器返回一个 HTTP 响应
- 浏览器显示 HTML
- 浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
- 浏览器发送异步请求
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.
- 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; SYN:同步序列编号(Synchronize Sequence Numbers)
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手.
完成三次握手,客户端与服务器开始传送数据。
三次握手耳熟能详,四次挥手估计就,所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,
- 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
- 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
- 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
- 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
-
发布者-订阅者模式(backbone.js)
-
脏值检查(angular.js)
angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:
DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
XHR响应事件 ( $http )
浏览器Location变更事件 ( $location )
Timer事件( $timeout , $interval )
执行 $digest() 或 $apply()
-
数据劫持(vue.js)
数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
要实现mvvm的双向绑定,就必须要实现以下几点:
-
实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
-
实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
-
实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
-
mvvm入口函数,整合以上三者
compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图 因为遍历解析的过程有多次操作dom节点,为提高性能和效率,会先将跟节点el转换成文档碎片fragment进行解析编译操作,解析完成,再将fragment添加回原来的真实dom节点中
Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是: 1、在自身实例化时往属性订阅器(dep)里面添加自己 2、自身必须有一个update()方法 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
- [Promise类实现]
- 构造函数传入一个fn,有两个参数,resolve:成功回调; reject:失败回调;
- state: 状态存储
- doneList: 成功处理函数列表
- failList: 失败处理函数列表
- done: 注册成功处理函数
- fail: 注册失败处理函数
- then: 同时注册成功和失败处理函数
- always: 一个处理注册到成功和失败,都会调用
- resolve: 更新state为:RESOLVED,并且执行成功处理队列
- reject: 更新state为:REJECTED,并且执行失败处理队列
promise有3种状态:pending(待解决,这也是初始化状态),fulfilled(完成),rejected(拒绝)。
javaScript权威指南上的解释是: call() 、apply()可以看作是某个对象的方法,通过调用方法的形式来间接调用函数。bind() 就是将某个函数绑定到某个对象上。
在JS中,这三者都是用来改变函数的this对象的指向的
三者的相似之处:
- 都是用来改变函数的this对象的指向的。
- 第一个参数都是this要指向的对象。
- 都可以利用后续参数传参。
区别:
- 对于call可以这样:xw.say.call(xh);
- 对于apply可以这样:xw.say.apply(xh);
- 而对于bind来说需要这样:xw.say.bind(xh)();
call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以。 call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。由于bind返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
HTML中只能为元素/标签绑定监听函数; Canvas绘图中只有一个元素-canvas,每一个图形/图像都不是元素,不能直接进行事件绑定。
解决办法:“事件委托”——让canvas监听所有的事件,计算事件发生坐标点,是否处于某个图形/图像的范围内。
- 鼠标事件
canvas.onmousedown = function(e) {
#React to the mouse down event
};
canvas.addEventListener('mousedown', function(e) {
#React to the mouse down event
});
上面一种方法看起来更简单一些,但是,如果需要向某个鼠标事件注册多个监听器的话,那么用addEventListener()方法会更合适。
浏览器通过事件对象传递给监听器的鼠标坐标,是窗口坐标(window coordinate),而不是相对与canvas自身的坐标。而大部分情况下,开发者需要知道的是发生鼠标事件的点相对于canvas的位置,而不是在整个窗口中的位置,所以有必要进行坐标变换。
-
键盘事件 canvas是一个不可获取焦点的元素,所以,在canvas上新增键盘事件监听器是徒劳的。如果想要检测键盘事件的话,你应该在document或window对象上新增键盘事件监听器才对。
-
触摸事件 移动端触摸事件与桌面平台的鼠标事件有两个主要的不同点
- 鼠标光标只有一个i额,而触摸点可能有很多
- 鼠标光标可以悬停(hover),而触摸点则不行
- 手指缩放 对于类型为touchstart及touchmove的触摸事件,如果发现有两个点同时在触摸设备,而且它们中至少有一个位置发生了变化,那么就判定用户在pinch屏幕。如果程序发现用户正在pinch屏幕,用于处理touchstart事件的方法会计算两个触摸点之间的距离,以及当前放大倍数与该距离的比值。在touchmove事件的方法也会计算当前两个触摸点之间的距离,并且将该值乘以刚才计算好的比值,就可以得到新的放大倍数。
let canvas = document.getElementById('mycanvas'),
ctx = canvas.getContext('2d')
两者都会在点击时触发,但是在手机WEB端,click会有 200~300
ms,所以请用tap代替click作为点击事件。
singleTap和doubleTap 分别代表单次点击和双次点击。
盒子模型分为上述两种,W3C盒子模型也就是W3C的标准。 这两个模型的唯一区别是计算width和height时,IE盒子模型包含padding和border, W3C盒子模型则不包括。为了使页面在不同浏览器下呈现相同的效果,必须统一盒子模型,因为设置width或者height一般是必须用到的。 那么必须设置浏览器的渲染模式是标准模式,在标准模式下,IE6+和其他现代浏览器会以W3C盒子模型渲染。 box-sizing属性可以指定盒子模型种类,content-box指定盒子模型为W3C,后者为IE盒子模型。 这是CSS3属性,IE8+和其他现代浏览器支持,详见文档。
- box-sizing:content-box
默认值,标准的盒模型,width和height只包括内容(content)的宽度和高度,不包括border,padding,margin,这些都是盒子的外部。
- box-sizing:border-box
这个模式下,当我们设置了盒子宽度和高度的时候,其包括:content+padding+border,但是不包括margin。
接收顺序(事件流方式),需要我们了解:
- 事件捕获:什么叫捕获,其实不用扯那么多一句话从最不具体的到最具体的
- 事件冒泡:什么叫冒泡,正好和上面相反,从最具体的到最不具体的
- 为什么会有两种事件流方式呢?历史原因,ie提出的是事件冒泡,而w3c提出的是事件捕获。
- 现代浏览器高级了,那。。。。。嗯,我知道你要问啥,你一定要问浏览器内部是如何解析这两种事件流的,它的执行顺序:事件捕获-》目标阶段-》事件冒泡,一句话就是先捕获后冒泡
先诉重点理论:
- target:触发事件的某个具体对象,只会出现在事件流的目标阶段(谁触发谁命中,所以肯定是目标阶段)
- currentTarget:绑定事件的对象,恒等于this,可能出现在事件流的任意一个阶段中
- 通常情况下terget和currentTarget是一致的,我们只要使用terget即可,但有一种情况必须区分这三者的关系,那就是在父子嵌套的关系中,父元素绑定了事件,单击了子元素(根据事件流,在不阻止事件流的前提下他会传递至父元素,导致父元素的事件处理函数执行),这时候currentTarget指向的是父元素,因为他是绑定事件的对象,而target指向了子元素,因为他是触发事件的那个具体对象
currentTarget(其事件处理程序当前正在处理事件的那个元素), target(事件的目标)。
通过自己写的demo,我对这两个属性的理解是, currentTarget(你绑定事件的那个元素), target(触发事件的那个目标)
点击button的时候由于事件处理程序注册于button之上,所以处理事件的目标也是button。 如果只是在div上注册点击事件处理程序,虽然事件是由button出发的,但是它本身并没有注册这个事件处理程序,所以会向上冒泡,找到div元素。
对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没 有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。深复制实现代码如下:
- 第一种方法、通过递归解析解决:
var china = { nation : '中国', birthplaces:['北京','上海','广州'], skincolr :'yellow', friends:['sk','ls'] }
#深复制,要想达到深复制就需要用递归
function deepCopy(o,c){ var c = c || {} for(var i in o){
if(typeof o[i] === 'object'){
#要考虑深复制问题了
if(o[i].constructor === Array){
#这是数组
c[i] =[] }else{
#这是对象
c[i] = {} }
deepCopy(o[i],c[i]) }else{ c[i] = o[i] } } return c }
var result = {name:'result'}
result = deepCopy(china,result)
console.dir(result)
- 第二种方法:通过JSON解析解决
var test ={ name:{ xing:{ first:'张', second:'李' }, ming:'老头' }, age :40, friend :['隔壁老王','宋经纪','同事'] }
var result = JSON.parse(JSON.stringify(test))
result.age = 30
result.name.xing.first = '往'
result.friend.push('fdagldf;ghad')
console.dir(test)
console.dir(result)
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。
vue-loader 是一个 Webpack 的 loader,可以将指定格式编写的 Vue 组件转换为 JavaScript 模块。
我们知道了webpack的强大依托于一个个强大的 loader(当然还有plugin,本文就不介绍了)。如果想真的玩溜webpack,我们就必须掌握loader的使用。在我们使用它们前,我们得知道自己需要什么loader。如果想编译less,可以用less-loader;想加载html文件并打包它内链的静态文件,可以使用html-loader。只要我们想对文件进行处理时,我们都可以去找想对应的loader。
loader 是导出为一个函数的 node 模块。该函数在 loader 转换资源的时候调用。给定的函数将调用 loader API,并通过 this 上下文访问。
匹配(test)单个 loader,你可以简单通过在 rule 对象设置 path.resolve 指向这个本地文件 匹配(test)多个 loaders,你可以使用 resolveLoader.modules 配置,webpack 将会从这些目录中搜索这些 loaders。例如,如果你的项目中有一个 /loaders 本地目录
当一个 loader 在资源中使用,这个 loader 只能传入一个参数 - 这个参数是一个包含包含资源文件内容的字符串
同步 loader 可以简单的返回一个代表模块转化后的值。在更复杂的情况下,loader 也可以通过使用 this.callback(err, values...) 函数,返回任意数量的值。错误要么传递给这个 this.callback 函数,要么扔进同步 loader 中。
loader 会返回一个或者两个值。第一个值的类型是 JavaScript 代码的字符串或者 buffer。第二个参数值是 SourceMap,它是个 JavaScript 对象。
当链式调用多个 loader 的时候,请记住它们会以相反的顺序执行。取决于数组写法格式,从右向左或者从下向上执行。
最后的 loader 最早调用,将会传入原始资源内容。 第一个 loader 最后调用,期望值是传出 JavaScript 和 source map(可选)。 中间的 loader 执行时,会传入前一个 loader 传出的结果。 所以,在接下来的例子,foo-loader 被传入原始资源,bar-loader 将接收 foo-loader 的产出,返回最终转化后的模块和一个 source map(可选)
编写 loader 时应该遵循以下准则。它们按重要程度排序,有些仅适用于某些场景,请阅读下面详细的章节以获得更多信息。
- 简单易用。
- 使用链式传递。
- 模块化的输出。
- 确保无状态。
- 使用 loader utilities。
- 记录 loader 的依赖。
- 解析模块依赖关系。
- 提取通用代码。
- 避免绝对路径。
- 使用 peer dependencies。
查阅node与webpack文档,我们可以通过loader-utils来获取loader的配置项。通过node的fs.readFileSync去加载文件
核心包
- babel-core:babel转译器本身,提供了babel的转译API,如babel.transform等,用于对代码进行转译。像webpack的babel-loader就是调用这些API来完成转译过程的。
- babylon:js的词法解析器
- babel-traverse:用于对AST(抽象语法树,想了解的请自行查询编译原理)的遍历,主要给plugin用
- babel-generator:根据AST生成代码
babel是一个转译器,感觉相对于编译器compiler,叫转译器transpiler更准确,因为它只是把同种语言的高版本规则翻译成低版本规则,而不像编译器那样,输出的是另一种更低级的语言代码。 但是和编译器类似,babel的转译过程也分为三个阶段:parsing、transforming、generating,以ES6代码转译为ES5代码为例,babel转译的具体过程如下:
ES6代码输入 ==》 babylon进行解析 ==》 得到AST==》 plugin用babel-traverse对AST树进行遍历转译 ==》 得到新的AST树==》 用babel-generator通过AST树生成ES5代码
babel只是转译新标准引入的语法,比如ES6的箭头函数转译成ES5的函数;而新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的API等(如Proxy、Set等),这些babel是不会转译的。需要用户自行引入polyfill来解决
插件应用于babel的转译过程,尤其是第二个阶段transforming,如果这个阶段不使用任何插件,那么babel会原样输出代码。 我们主要关注transforming阶段使用的插件,因为transform插件会自动使用对应的词法插件,所以parsing阶段的插件不需要配置。
polyfill polyfill是一个针对ES2015+环境的shim,实现上来说babel-polyfill包只是简单的把core-js和regenerator runtime包装了下,这两个包才是真正的实现代码所在(后文会详细介绍core-js)。 使用babel-polyfill会把ES2015+环境整体引入到你的代码环境中,让你的代码可以直接使用新标准所引入的新原生对象,新API等,一般来说单独的应用和页面都可以这样使用。 使用方法 先安装包: npm install --save babel-polyfill 要确保在入口处导入polyfill,因为polyfill代码需要在所有其他代码前先被调用 代码方式: import "babel-polyfill" webpack配置: module.exports = { entry: ["babel-polyfill", "./app/js"] }; 如果只是需要引入部分新原生对象或API,那么可以按需引入,而不必导入全部的环境,具体见下文的core-js
runtime polyfill和runtime的区别 直接使用babel-polyfill对于应用或页面等环境在你控制之中的情况来说,并没有什么问题。但是对于在library中使用polyfill,就变得不可行了。因为library是供外部使用的,但外部的环境并不在library的可控范围,而polyfill是会污染原来的全局环境的(因为新的原生对象、API这些都直接由polyfill引入到全局环境)。这样就很容易会发生冲突,所以这个时候,babel-runtime就可以派上用场了。
通过core-js实现按需引入polyfill或runtime 但是polyfill和runtime都是整体引入的,不能做细粒度的调整,如果我们的代码只是用到了小部分ES6而导致需要使用polyfill和runtime的话,会造成代码体积不必要的增大(runtime的影响较小)。所以,按需引入的需求就自然而然产生了,这个时候就得依靠core-js来实现了。
core-js的组织结构 首先,core-js有三种使用方式:
默认方式:require('core-js') 这种方式包括全部特性,标准的和非标准的 库的形式: var core = require('core-js/library') 这种方式也包括全部特性,只是它不会污染全局名字空间 只是shim: require('core-js/shim')或var shim = require('core-js/library/shim') 这种方式只包括标准特性(就是只有polyfill功能,没有扩展的特性)
- What is Rax A universal React-compatible render engine.
官方描述:一个通用的跨容器的渲染引擎。
关键词:
-
universal:跨容器(Browser/Native/Node)
-
React-compatible:React语法基本兼容
-
Why use Rax
Weex本身是Vue@1.x的语法糖
,如果你和你的团队的技术栈之前就是React,并没有Vue,那么Rax将是一个不错的选择。
由于Rax基于React DSL,所以天生就享有React社区所带来的一些资源,比如:Redux。
此外,相比于React,它的优势:
渐进渲染模式,白屏时间更短 8.5kb(min+gzip),文件体积更小
- 入门 与react/react-native类似,Rax同样是由两个库组成:rax和rax-components:
rax – 核心渲染库,提供了React-compatible API rax-components – 辅助组件库,更准确地说,应该是:元件,提供了UI跨平台的能力 所以:一般来说,基于元件编写的复合组件,是可以同时运行在Native和Web上的。
- 差异点 虽然Rax实现了大部分React-compatible API,可能出于底层需要适配Weex API以及Native性能上的一些考虑,所以在实现细节上,还是会有一些差别,比如:
不支持createClass()方法,更推荐使用ES6 Class替代(Rax并不像React有过多的历史包袱) 向指定container node渲染时,并不会清空当前容器的子节点,而是直接采用appendChild的方式 setState()方法是同步的,不再支持批处理更新(batchedUpdates),而React是异步的。 …
前面开篇里提到过,使用Rax/Weex构建的是:一个移动端·跨平台应用。
那么,从样式编写的角度,该如何看待移动端和跨平台这两个Rax/Weex特性?
- 移动端:宽高/边距,甚至是字体大小等样式,需要能够适配不同屏幕尺寸的手机
- 跨平台:同一份样式代码需要能够同时在Web/IOS/Android平台上运行 面对上述的问题,其实在以往的Web App实践中,已经有了一些类似的经验沉淀:
通过**「rem」和「flexbox」可以做到手机屏幕适配 通过「css in js」**的方式,让JS拥有描述样式的能力,从而做到将同一份代码运行在不同的JS Engine里(抛弃了原来Web固有的CSS样式表) Rax/Weex也正是基于类似上述的思路实现了对应样式API,接下来主要以Rax为例介绍如何编写样式。
关于适配 在传统的Web中,根据手机屏幕宽度的值,动态改变html font-size,再结合rem单位对不同尺寸的手机屏幕进行适配(对于样式数值的转换,往往会通过sass/less来进行预编译)。
而在Weex/Rax中,同样是根据手机屏幕宽度,由于样式已经通过「css in js」的方式引入,所以动态转换用户传递参数(样式数值)就可以达到适配的目的(这里的数值转换,与之前的不同,因为发生在javascript运行时)。
关于布局 在Weex/Rax中,不再支持float布局,取而代之的是flexbox布局(对于移动端而言,理应如此)。
###高阶 事实上,在项目开发过程中,如果将所有的样式代码都写在JS文件里,会发现代码看起来很臃肿,或许我们更习惯于:分离样式代码。
Webpack的诞生,推动了前端自动化工具的发展的同时,也加速了我们对前端的认知,不用再去一直等待标准规范的完全实现,有很多这样的例子:
babel-loader:jsx/es6/es7转换成es5 sass/less-loader:sass/less转换成css vue-loader:实现了SFC(Single File Components) weex-loader:实现了SFC的同时,还注入了__weex_require__(可以引用Native Module) 所以,代码的写法已经不受太多约束,因为可以有很多插件去支撑一个靠谱的想法。
同样的,Rax也提供了这么一个Webpack插件 – 「stylesheet-loader」,让我们能够在Rax应用中通过CSS写样式。
除了样式代码的分离,少写几个引号之外,stylesheet-loader的好处还在于:
对于Weex不支持的样式,能快速给予友好的warning提示 可以跟sass/less-loader结合,使用变量、mixin、嵌套等预编译功能
- 栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址
- 堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值。
基本类型与引用类型最大的区别实际就是传值与传址的区别
- 值传递:基本类型采用的是值传递。
- 址传递:引用类型则是地址传递,将存放在栈内存中的地址赋值给接收的变量。
Node.js采用模块化结构,按照CommonJS规范定义和使用模块。模块与文件是一一对应关系,即加载一个模块,实际上就是加载对应的一个模块文件。
require命令用于指定加载模块,加载时可以省略脚本文件的后缀名。
require方法的参数是模块文件的名字。它分成两种情况,第一种情况是参数中含有文件路径,这时路径是相对于当前脚本所在的目录,第二种情况是参数中不含有文件路径,这时Node到模块的安装目录,去寻找已安装的模块。
有时候,一个模块本身就是一个目录,目录中包含多个文件。这时候,Node在package.json文件中,寻找main属性所指明的模块入口文件。 如果模块目录中没有package.json文件,node.js会尝试在模块目录中寻找index.js或index.node文件进行加载。
模块一旦被加载以后,就会被系统缓存。如果第二次还加载该模块,则会返回缓存中的版本,这意味着模块实际上只会执行一次。如果希望模块执行多次,则可以让模块返回一个函数,然后多次调用该函数。
回流(reflow):指的是网络浏览器为了重新渲染部分或全部的文档而重新计算文档中元素的位置和几何结构的过程。 页面上节点是以树的形式展现的,我们通过js将页面上的一个节点删除,此时为了不让剩下的节点脱节,将断点结合起来重新形成一棵树。而这个重新结合过程就是回流。就是由于某些修改,要将元素回过头来重新“流”一遍。
重绘(repaints):是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。
减少回流的几点建议:
-
减少不必要的DOM深度。因为无论你改变DOM节点树上任何一个层级都会影响节点树的每个层级——从根结点一直到修改的子节点。不必要的节点深度将导致执行回流时花费更多的时间。
-
精简css,去除没有用处的css
-
如果你想让复杂的表现发生改变,例如动画效果,那么请在这个流动线之外实现它。使用position-absolute或position-fixed来实现它,也即是让其脱离文档流,不影响父级;现代浏览器也可以使用CSS3 transition实现动画效果,比改变像素值来的高性能。
-
避免不必要的复杂的css选择符,尤其是使用子选择器,或消耗更多的CPU去做选择器匹配。
-
页面的元素适当定高,例如如果div内容可能有高度差异的动态内容载入; 页面刷新载入的时候,应避免页面元素的晃动、位移等,这些都是额外的重绘,会让你的CPU和风扇兴奋的
-
图片设定不响应重绘的尺寸,如果你的
<img>
不设定尺寸、同时外部容器没有定死高宽,则图片在首次载入时候,占据空间会从0到完全出现,左右上下都可能位移,发生大规模的重绘。可以参见新浪微博载入时候页面高度随着图片显示不断变高的问题,这些都让浏览器重绘了,一是体验可能不好,二是烧CPU的。
在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能吗? 在桌面端和移动端用CSS开启硬件加速 Chrome, FireFox, Safari, IE9+和最新版本的Opera都支持硬件加速,当它们检测到页面中某个DOM元素应用了某些CSS规则时就会开启,最显著的特征的元素的3D变换。
原生的移动端应用(Native mobile applications)总是可以很好的运用GPU,这是为什么它比网页应用(Web apps)表现更好的原因。硬件加速在移动端尤其有用,因为它可以有效的减少资源的利用(麦时注:移动端本身资源有限)。
- 对于loader,它就是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程;
- 对于plugin,它就是一个扩展器,它丰富了wepack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点;
- run:开始编译
- make:从entry开始递归分析依赖并对依赖进行build
- build-moodule:使用loader加载文件并build模块
- normal-module-loader:对loader加载的文件用acorn编译,生成抽象语法树AST
- program:开始对AST进行遍历,当遇到require时触发call require事件
- seal:所有依赖build完成,开始对chunk进行优化(抽取公共模块、加hash等)
- optimize-chunk-assets:压缩代码
- emit:把各个chunk输出到结果文件
作用域是针对变量的,比如我们创建了一个函数,函数里面又包含了一个函数,那么现在就有三个作用域 全局作用域==>函数1作用域==>函数2作用域 作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。 因为函数c是在函数b中创建的,也就是说函数c的作用域包括了函数b的作用域,当然也包括了全局作用域,但是函数b不能向函数c中查找变量,因为作用域只会向上查找。
原型链是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。
Object ==> 构造函数1 ==> 构造函数2
在JavaScript中,一共有两种类型的值,原始值和对象值.每个对象都有一个内部属性[[prototype]],我们通常称之为原型.原型的值可以是一个对象,也可以是null.如果它的值是一个对象,则这个对象也一定有自己的原型.这样就形成了一条线性的链,我们称之为原型链(比如我们新建一个数组,数组的方法就是从数组的原型上继承而来的)
OSI是一个开放性的通信系统互连参考模型,他是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 ;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端的数据流。
-
应用层 与其它计算机进行通讯的一个应用,它是对应应用程序的通信服务的。例如,一个没有通信功能的字处理程序就不能执行通信的代码,从事字处理工作的程序员也不关心OSI的第7层。但是,如果添加了一个传输文件的选项,那么字处理器的程序员就需要实现OSI的第7层。示例:TELNET,HTTP,FTP,NFS,SMTP等。
-
表示层 这一层的主要功能是定义数据格式及加密。例如,FTP允许你选择以二进制或ASCII格式传输。如果选择二进制,那么发送方和接收方不改变文件的内容。如果选择ASCII格式,发送方将把文本从发送方的字符集转换成标准的ASCII后发送数据。在接收方将标准的ASCII转换成接收方计算机的字符集。示例:加密,ASCII等。
-
会话层 它定义了如何开始、控制和结束一个会话,包括对多个双向消息的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的,在某些情况下,如果表示层收到了所有的数据,则用数据代表表示层。示例:RPC,SQL等。
-
传输层 这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。
-
网络层 这层对端到端的包传输进行定义,它定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。示例:IP,IPX等。
-
数据链路层 它定义了在单个链路上如何传输数据。这些协议与被讨论的各种介质有关。示例:ATM,FDDI等。
-
物理层 OSI的物理层规范是有关传输介质的特这些规范通常也参考了其他组织制定的标准。连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。物理层常用多个规范完成对所有细节的定义。示例:Rj45,802.3等。
ask exactly what you want.
GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。
JavaScript是在虚拟机(VM)中执行的,该虚拟机能够最大化地优化代码并压榨每一丝的性能,这也使得JavaScript称为速度最快的动态语言之一。但尽管如此,它还是无法与原生的C/C++代码相媲美。所以,WebAssembly就出现了。 Wasm同样在JavaScript虚拟机中运行,但是它表现得更好。两者可以自由交互、互不排斥,这样你就同时拥有了两者最大的优势——JavaScript巨大的生态系统和有好的语法,WebAssembly接近原生的表现性能。
C到WebAssembly的编译器,推荐使用Emscripten(https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html
),安装这个工具费时费力费空间,但没办法,这是目前为止最好的选择,请仔细阅读安装说明,需占用约1GB的硬盘空间。
元数据(metadata)是关于数据的信息。
标签提供关于 HTML 文档的元数据。元数据不会显示在页面上,但是对于机器是可读的。
典型的情况是,meta 元素被用于规定页面的描述、关键词、文档的作者、最后修改时间以及其他元数据。
标签始终位于 head 元素中。
元数据可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。
<meta>
元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词。
<meta>
标签位于文档的头部,不包含任何内容。<meta>
标签的属性定义了与文档相关联的名称/值对。
注释:<meta>
标签永远位于 head 元素内部。
注释:元数据总是以名称/值的形式被成对传递的。
CSS三大特性——
- 继承: 即子类元素继承父类的样式;
- 优先级: 是指不同类别样式的权重比较;
- 层叠: 是说当数量相同时,通过层叠(后者覆盖前者)的样式。
css优先级
- 在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式。
- 作为style属性写在元素内的样式
- id选择器
- 类选择器
- 标签选择器
- 通配符选择器
- 浏览器自定义或继承
总结排序:!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
CSS优先级:是由四个级别和各级别的出现次数决定的。
四个级别分别为:行内选择符、ID选择符、类别选择符、元素选择符。
优先级的算法:
每个规则对应一个初始"四位数":0、0、0、0
若是 行内选择符,则加1、0、0、0
若是 ID选择符,则加0、1、0、0
若是 类选择符/属性选择符/伪类选择符,则分别加0、0、1、0
若是 元素选择符/伪元素选择符,则分别加0、0、0、1
算法:将每条规则中,选择符对应的数相加后得到的”四位数“,从左到右进行比较,大的优先级越高。
我们知道javascript程序一般是由一系列的字符组成的,每一个字符都有一些含义,比如我们可以使用匹配的字符([], {}, ()), 或一些其他成对的字符('', "")和代码缩进让程序解析更加简单,但是对计算机并不适用,这些字符在内存中仅仅是个数值,但是计算机并不知道一个程序内部有多少个变量这些高级问题, 这个时候我们需要寻找一些能让计算机理解的方式,这个时候,抽象语法树诞生了。
程序代码本身可以被映射成为一棵语法树,而通过操纵语法树,我们能够精准的获得程序代码中的某个节点。例如声明语句,赋值语句,而这是用正则表达式所不能准确体现的地方。
STAR面试法是企业招聘面试过程中可采用的技巧。其中,“STAR”是SITUATION(背景)、TASK(任务)、ACTION(行动)和RESULT(结果)四个英文单词的首字母组合。
技术一面主要判断对基础知识的掌握
技术二面主要判断技术深度及广度
- localStorage - 没有时间限制的数据存储
- sessionStorage - 针对一个 session 的数据存储
HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。
应用程序缓存为应用带来三个优势:
离线浏览 - 用户可在应用离线时使用它们 速度 - 已缓存资源加载得更快 减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源。
如需启用应用程序缓存,请在文档的 <html>
标签中包含 manifest 属性:
<!DOCTYPE HTML>
<html manifest="demo.appcache">
...
</html>
层叠样式表 (Cascading Style Sheets,缩写为 CSS),是一种 样式表 语言,用来描述 HTML 或 XML(包括如 SVG、XHTML 之类的 XML 分支语言)文档的呈现。CSS 描述了在屏幕、纸质、音频等其它媒体上的元素应该如何被渲染的问题。
CSS 是开放网络的核心语言之一,由 W3C 规范 进行标准化。CSS 被分为不同等级:CSS1 现已废弃, CSS2.1 是推荐标准, CSS3 分成多个小模块且正在标准化中。
一个CSS规则由以下组成:
-
一组 属性 ,属性的值更新了 HTML 的内容的显示方式。比如,我想让元素的宽度是其父元素的50%,或者元素背景变为红色。
-
一个 选择器,它选择元素,这(些)元素是你想应用这些最新的属性值于其上的元素。比如,我想将我的CSS规则应用到我HTML文档中的所有段落上。
当浏览器显示文档时,它必须将文档的内容与其样式信息结合。它分两个阶段处理文档:
-
浏览器将 HTML 和 CSS 转化成 DOM (文档对象模型)。DOM在计算机内存中表示文档。它把文档内容和其样式结合在一起。
-
浏览器显示 DOM 的内容。
-
外部样式表 外部样式表是指:当你将你的 CSS 保存在一个独立的扩展名为 .css 的文件中,并从HTML的
<link>
元素中引用它。 -
内部样式表 内部样式表是指不使用外部 CSS 文件,而是将你的 CSS 放置在
<style>
元素中,该元素包含在 HTML head 内。 -
内联样式 内联样式是仅影响一个元素的CSS声明,被 style 属性包括着.除非有必要,否则不要这么做!这很难维护(你可能不得不在每份文档里更新多次同样的信息),并且它还混合了 CSS 表示的样式信息和 HTML 的结构信息,使 CSS 难以阅读和理解。保持不同类型代码的分离和纯净使处理该代码的任何人工作更为容易。
**@-规则(At-rules)**在CSS中被用来传递元数据、条件信息或其它描述性信息。它由(@)符号开始,紧跟着一个表明它是哪种规则的描述符,之后是这种规则的语法块,并最终由一个半角分号(;)结束。每种由描述符定义的@-规则,都有其特有的内部语法和语义。
嵌套语句 是@-规则中的一种,它的语法是 CSS 规则的嵌套块,只有在特定条件匹配时才会应用到文档上。特定条件如下:
- @media 只有在运行浏览器的设备匹配其表达条件时才会应用该@-规则的内容;
- @supports 只有浏览器确实支持被测功能时才会应用该@-规则的内容;
- @document 只有当前页面匹配一些条件时才会应用该@-规则的内容。
-
简单选择器(Simple selectors):通过元素类型、class 或 id 匹配一个或多个元素。
-
属性选择器(Attribute selectors):通过 属性 / 属性值 匹配一个或多个元素。
-
伪类(Pseudo-classes):匹配处于确定状态的一个或多个元素,比如被鼠标指针悬停的元素,或当前被选中或未选中的复选框,或元素是DOM树中一父节点的第一个子节点。
-
伪元素(Pseudo-elements):匹配处于相关的确定位置的一个或多个元素,例如每个段落的第一个字,或者某个元素之前生成的内容。
-
组合器(Combinators):这里不仅仅是选择器本身,还有以有效的方式组合两个或更多的选择器用于非常特定的选择的方法。例如,你可以只选择divs的直系子节点的段落,或者直接跟在headings后面的段落。
-
多用选择器(Multiple selectors):这些也不是单独的选择器;这个思路是将以逗号分隔开的多个选择器放在一个CSS规则下面, 以将一组声明应用于由这些选择器选择的所有元素。
通用选择(*
)是最终的王牌。它允许选择在一个页面中的所有元素。由于给每个元素应用同样的规则几乎没有什么实际价值,更常见的做法是与其他选择器结合使用
-
[attr]:该选择器选择包含 attr 属性的所有元素,不论 attr 的值为何。
-
[attr=val]:该选择器仅选择 attr 属性被赋值为 val 的所有元素。
-
[attr~=val]:该选择器仅选择具有 attr 属性的元素,而且要求 val 值是 attr 值包含的被空格分隔的取值列表里中的一个时(以空格间隔出多个值)的。
###子串值(Substring value)属性选择器 也被称为“伪正则选择器”,因为它们提供类似 regular expression 的灵活匹配方式(但请注意,这些选择器并不是真正的正则表达式):
- [attr|=val] : 选择attr属性的值是 val 或值以 val- 开头的元素(注意,这里的 “-” 不是一个错误,这是用来处理语言编码的)。
- [attr^=val] : 选择attr属性的值以 val 开头(包括 val)的元素。
- [attr$=val] : 选择attr属性的值以 val 结尾(包括 val)的元素。
[attr*=val] : 选择attr属性的值中包含子字符串 val 的元素(一个子字符串就是一个字符串的一部分而已,例如,”cat“ 是 字符串 ”caterpillar“ 的子字符串)。
一个 CSS 伪类(pseudo-class) 是一个以冒号(:)作为前缀,被添加到一个选择器末尾的关键字,当你希望样式在特定状态下才被呈现到指定的元素时,你可以往元素的选择器后面加上对应的伪类(pseudo-class)。
**伪元素(Pseudo-element)**跟伪类很像,但它们又有不同的地方。它们都是关键字,但这次伪元素前缀是两个冒号 (::) , 同样是添加到选择器后面去选择某个元素的某个部分。
- ::after
- ::before
- ::first-letter
- ::first-line
- ::selection
- ::backdrop
-
数值: 长度值,用于指定例如元素宽度、边框(border)宽度或字体大小;以及无单位整数。用于指定例如相对线宽或运行动画的次数。
-
百分比: 可以用于指定尺寸或长度——例如取决于父容器的长度或高度,或默认的字体大小。
-
颜色: 用于指定背景颜色,字体颜色等。
-
坐标位置: 例如,以屏幕的左上角为坐标原点定位元素的位置。
-
函数: 例如,用于指定背景图片或背景图片渐变。
CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。
什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的——前面的的一种会否决后一种):
- 重要性(Importance)
- 专用性(Specificity)
- 源代码次序(Source order)
重载这个 !important 声明的唯一方法是在后面的源码或者是一个拥有更高特殊性的源码中包含相同的 !important 特性的声明。
一个选择器具有的专用性的量是用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位——在四个列中的四个简单数字:
- 千位:如果声明是在style 属性中该列加1分(这样的声明没有选择器,所以它们的专用性总是1000。)否则为0。
- 百位:在整个选择器中每包含一个ID选择器就在该列中加1分。
- 十位:在整个选择器中每包含一个类选择器、属性选择器、或者伪类就在该列中加1分。
- 个位:在整个选择器中每包含一个元素选择器或伪元素就在该列中加1分。
CSS继承是我们需要研究的最后一部分,以获取所有信息并了解什么样式应用于元素。其思想是,应用于某个元素的一些属性值将由该元素的子元素继承,而有些则不会。
CSS为处理继承提供了四种特殊的通用属性值:
- inherit: 该值将应用到选定元素的属性值设置为与其父元素一样。
- initial :该值将应用到选定元素的属性值设置为与浏览器默认样式表中该元素设置的值一样。如果浏览器默认样式表中没有设置值,并且该属性是自然继承的,那么该属性值就被设置为 inherit。
- unset :该值将属性重置为其自然值,即如果属性是自然继承的,那么它就表现得像 inherit,否则就是表现得像 initial。
- revert :如果当前的节点没有应用任何样式,则将该属性恢复到它所拥有的值。换句话说,属性值被设置成自定义样式所定义的属性(如果被设置), 否则属性值被设置成用户代理的默认样式。
文档的每个元素被构造成文档布局内的一个矩形框,框每层的大小都可以使用一些特定的CSS属性调整。 溢流 overflow属性 背景裁剪(Background clip) 框的背景是由颜色和图片组成的,它们堆叠在一起(background-color, background-image)。 它们被应用到一个盒子里,然后被画在盒子的下面。默认情况下,背景延伸到了边界外沿。 轮廓(Outline)
布局技术会覆盖默认的布局行为:
-
position 属性 — 正常布局流中,默认为 static ,使用其它值会引起元素不同的布局方式,例如将元素固定到浏览器视口的左上角。
-
浮动——应用 float 值,诸如 left 能够让块级元素互相并排成一行,而不是一个堆叠在另一个上面。 display 属性——标准值 block, inline or inline-block 会改变元素在正常布局流中的行为方式(见 Types of CSS boxes ),而一些不常见或特殊的值允许我们使用完全不同的方式进行布局,使用工具比如Flexbox。
定位技术(position)允许我们将一个元素从它在页面的原始位置准确地移动到另外一个位置。
-
**静态定位(Static positioning)**是每个元素默认的属性——它表示“将元素放在文档布局流的默认位置——没有什么特殊的地方”。
-
**相对定位(Relative positioning)**允许我们相对元素在正常的文档流中的位置移动它——包括将两个元素叠放在页面上。这对于微调和精准设计(design pinpointing)非常有用。
-
**绝对定位(Absolute positioning)**将元素完全从页面的正常布局流中移出,类似将它单独放在一个图层中. 我们可以将元素相对于页面的
<html>
元素边缘固定,或者相对于离元素最近的被定位的祖先元素(ancestor element)。绝对定位在创建复杂布局效果时非常有用,例如通过标签显示和隐藏的内容面板或者通过按钮控制滑动到屏幕中的信息面板. -
**固定定位(Fixed positioning)**与绝对定位非常类似,除了它是将一个元素相对浏览器视口固定,而不是相对另外一个元素。 在创建类似页面滚动总是处于页面上方的导航菜单时非常有用。
可访问性是让你的网站尽可能多的人使用的做法——我们传统上认为这是关于残疾人的,但实际上它也涵盖了其他群体,比如使用移动设备的人群,或者那些网络连接缓慢的人群。
你也可以把无障碍看成是对每个人都一样的对待,给他们同样的机会,无论他们的能力或环境如何。 就像不应该把某人从物理大楼里排除在外,因为他们是坐在轮椅上(公共建筑通常有轮椅或电梯),也不能排除某个网站上的人因为他们有视觉障碍,或者使用手机。我们都是不同的,但我们都是人,因此拥有同样的(人的)权利。
可访问性和它所需要的最佳实践可以使每个人受益:
-
语义HTML(提高可访问性)也提高了搜索引擎优化,使你的网站更容易获得。
-
关心可访问性展示良好的伦理道德,它提高了你的公众形象。
-
其他一些改善可访问性的好的做法也会让你的网站更容易被其他群体使用,比如移动电话用户,低网速等等。事实上,每个人都可以从很多这样的改进中受益。
Note: 世界卫生组织(World Health Organization)的残疾和健康状况说明书指出,“超过10亿人,约占世界人口的15%,患有某种形式的残疾”,“1.1亿至1.9亿成年人在功能上存在重大困难。”
"网络从根本上是为了为所有的人工作, 无论他们的硬件、软件、语言、文化、位置或身体或精神能力。当网络达到这一目标,它可以被不同的人的听觉范围,运动,和认知能力访问。"
内容安全策略 (CSP, Content Security Policy) 是一个附加的安全层,用于帮助检测和缓解某些类型的攻击,包括跨站脚本 (XSS) 和数据注入等攻击。 这些攻击可用于实现从数据窃取到网站破坏或作为恶意软件分发版本等用途。
CSP被设计成向后兼容;不支持的浏览器依然可以运行使用了它的服务器页面,反之亦然。不支持CSP的浏览器会忽略它,像平常一样运行,默认对网页内容使用标准的同源策略。如果网站不提供CSP头部,浏览器同样会使用标准的同源策略。
内容安全策略标准特点 是一种能被<meta>
元素来配置的一种协议
尽管内容安全策略在 Firefox 4 中已经包含,使用 X-Content-Security-Policy 头部来实现,但它使用的是过时的 CSP 标准。Firefox 23 包含了更新的 CSP 实现,使用的是 W3C CSP 1.0 标准中描述的没有前缀的 Content-Security-Policy 头部和指令。
CSP的主要目标是减少和报告XSS攻击. XSS攻击利用浏览器对从服务器接受的内容的信任。恶意的脚本在受害的浏览器被执行, 因为浏览器相信内容源,甚至当内容源并不是从它应该来的地方过来的。
CSP使服务器管理员能够通过制定浏览器能够执行的可信赖脚本的域名来减少或者消除由XSS可能出现的矢量。 一个兼容CSP的浏览器将只会执行加载与白名单域名的源文件的脚本,忽略那些其他的脚本(包括内联脚本和事件操控HTML属性)
为了重新约束内容被下载的域名, 服务端能够制定那种协议能够被使用;例如(理论上,从安全的立足点来看),一个服务制定所有的内容都通过HTTPS协议来加载
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源。
data:URLs获得一个新的,空的安全上下文。
在页面中用 about:blank 或 javascript: URL 执行的脚本会继承打开该 URL 的文档的源,因为这些类型的 URLs 没有明确包含有关原始服务器的信息。
Internet Explorer 有两个主要的不同点
- 授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。
- 端口:IE 未将端口号加入到同源策略的组成部分之中,因此
http://company.com:81/index.html
和http://company.com/index.html
属于同源并且不受任何限制。
页面可能会因某些限制而改变他的源。脚本可以将 document.domain 的值设置为其当前域或其当前域的超级域。如果将其设置为其当前域的超级域,则较短的域将用于后续源检查。
浏览器单独保存端口号。任何的赋值操作,包括 document.domain = document.domain 都会导致端口号被重写为 null 。因此 company.com:8080 不能仅通过设置 document.domain = "company.com" 来与company.com 通信。必须在他们双方中都进行赋值,以确保端口号都为 null 。
同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest 或 <img>
标签时则会受到同源策略的约束。这些交互通常分为三类:
-
通常允许跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。
-
通常允许跨域资源嵌入(Cross-origin embedding)。之后下面会举例说明。
-
通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或availability of an embedded resource.
-
<script src="..."></script>
标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。 -
<link rel="stylesheet" href="...">
标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type 消息头。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。 -
<img>
嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,... -
<video>
和<audio>
嵌入多媒体资源。 -
<object>
,<embed>
和<applet>
的插件。 -
@font-face 引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
-
<frame>
和<iframe>
载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。
使用 CORS 允许跨源访问。
-
阻止跨域写操作,只要检测请求中的一个不可测的标记(CSRF token)即可,这个标记被称为Cross-Site Request Forgery (CSRF) 标记。必须使用这个标记来阻止页面的跨站读操作。
-
阻止资源的跨站读取,需要保证该资源是不可嵌入的。阻止嵌入行为是必须的,因为嵌入资源通常向其暴露信息。
-
阻止跨站嵌入,需要确保你的资源不能是以上列出的可嵌入资源格式。多数情况下浏览器都不会遵守 Conten-Type 消息头。例如,如果您在HTML文档中指定
<script>
标记,则浏览器将尝试将HTML解析为JavaScript。 当您的资源不是您网站的入口点时,您还可以使用CSRF令牌来防止嵌入。
存储在浏览器中的数据,如localStorage和IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。
Cookies 使用不同的源定义方式。一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。Firefox 和 Chrome 使用 Public Suffix List 决定一个域是否是一个公共后缀(public suffix)。Internet Explorer使用其自己的内部方法来确定域是否是公共后缀。不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名(sub-domains) 访问 cookie。设置 cookie 时,你可以使用Domain,Path,Secure,和Http-Only标记来限定其访问性。读取 cookie 时,不会知晓它的出处。 即使您仅使用安全的https连接,您看到的任何cookie都可能使用不安全的连接进行设置。
当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。
跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 请求所带来的风险。
跨域资源共享标准( cross-origin sharing standard )允许在下列场景中使用跨域 HTTP 请求:
- 前文提到的由 XMLHttpRequest 或 Fetch 发起的跨域 HTTP 请求。
- Web 字体 (CSS 中通过 @font-face 使用跨域字体资源), 因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用。
- WebGL 贴图
- 使用 drawImage 将 Images/video 画面绘制到 canvas
- 样式表(使用 CSSOM)
- Scripts (未处理的异常)
服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example
的访问,该首部字段的内容如下:
Access-Control-Allow-Origin: http://foo.example
当用户访问使用HTTPS的页面时,他们与web服务器之间的连接是使用SSL加密的,从而保护连接不受嗅探器和中间人攻击。
如果HTTPS页面包括由普通明文HTTP连接加密的内容,那么连接只是被部分加密:非加密的内容可以被嗅探者入侵,并且可以被中间人攻击者修改,因此连接不再受到保护。当一个网页出现这种情况时,它被称为混合内容页面。
超文本传输协议(HTTP)是用于传输诸如HTML的超媒体文档的应用层协议。它被设计用于Web浏览器和Web服务器之间的通信,但它也可以用于其他目的。 HTTP遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。 HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。虽然通常基于TCP / IP层,但可以在任何可靠的传输层上使用; 也就是说,一个不会静默丢失消息的协议,如UDP。
要展现一个网页,浏览器首先发送一个请求来获取页面的HTML文档,再解析文档中的资源信息发送其他请求,获取可执行脚本或CSS样式来进行页面布局渲染,以及一些其它页面资源(如图片和视频等)。然后,浏览器将这些资源整合到一起,展现出一个完整的文档,也就是网页。浏览器执行的脚本可以在之后的阶段获取更多资源,并相应地更新网页。
代理主要有如下几种作用:
- 缓存(可以是公开的也可以是私有的,像浏览器的缓存)
- 过滤(像反病毒扫描,家长控制...)
- 负载均衡(让多个服务器服务不同的请求)
- 认证(对不同资源进行权限管理)
- 日志记录(允许存储历史信息)
- HTTP 是简单的 下一代HTTP/2协议将HTTP消息封装到了帧(frames)中,HTTP大体上还是被设计得简单易读。HTTP报文能够被人读懂,还允许简单测试,降低了门槛,对新人很友好。
- HTTP 是可扩展的 在 HTTP/1.0 中出现的 HTTP headers 让协议扩展变得非常容易。
- HTTP 是无状态,有会话的
- HTTP 和连接 HTTP/2则发展得更远,通过在一个连接复用消息的方式来让这个连接始终保持为暖连接。
当客户端想要和服务端进行信息交互时(服务端是指最终服务器,或者是一个中间代理),过程表现为下面几步:
- 打开一个TCP连接:TCP连接被用来发送一条或多条请求,以及接受回应消息。客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的TCP连接连向服务端。
- 发送一个HTTP报文:HTTP报文(在HTTP/2之前)是语义可读的。在HTTP/2中,这些简单的消息被封装在了帧中,这使得报文不能被直接读取,但是原理仍是相同的。
- 读取服务端返回的报文信息
- 关闭连接或者为后续请求重用连接。
-
一个HTTP的method,经常是由一个动词像GET, POST 或者一个名词像OPTIONS,HEAD来定义客户端的动作行为。通常客户端的操作都是获取资源(GET方法)或者发送HTML form表单值(POST方法),虽然在一些情况下也会有其他操作。
-
要获取的资源的路径,通常是上下文中就很明显的元素资源的URL,它没有protocol (http://),domain(developer.mozilla.org),或是TCP的port(HTTP一般在80端口)。 HTTP协议版本号。
-
为服务端表达其他信息的可选头部headers。
-
对于一些像POST这样的方法,报文的body就包含了发送的资源,这与回应报文的body类似。
回应报文包含了下面的元素:
- HTTP协议版本号。
- 一个状态码(status code),来告知对应请求执行成功或失败,以及失败的原因。
- 一个状态信息,这个信息是非权威的状态码描述信息,可以由服务端自行设定。
- HTTP headers,与请求头部类似。
- 可选项,比起请求报文,响应报文中更常见地包含获取的资源body。
重用已获取的资源能够有效的提升网站与应用的性能。Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。
缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能够被多个用户使用。私有缓存只能用于单独用户。本文将主要介绍浏览器与代理缓存,除此之外还有网关缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上,为站点和 web 应用提供更好的稳定性、性能和扩展性。
虽然 HTTP 缓存不是必须的,但重用缓存的资源通常是必要的。然而常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。 普遍的缓存案例:
- 一个检索请求的成功响应: 对于 GET请求,响应状态码为:200,则表示为成功。一个包含例如HTML文档,图片,或者文件的响应.
- 不变的重定向: 响应状态码:301.
- 错误响应: 响应状态码:404 的一个页面.
- 不完全的响应: 响应状态码 206,只返回局部的信息.
- 除了 GET 请求外,如果匹配到作为一个已被定义的cache键名的响应.
Cache-control 头
缓存过期机制
过期机制中,最重要的指令是 "max-age=<seconds>
",表示资源能够被缓存(保持新鲜)的最大时间。相对Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件,通常可以手动设置一定的时长以保证缓存有效,例如图片、css、js等静态资源。
HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。
Cookie主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
会话期Cookie
会话期Cookie是最简单的Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。会话期Cookie不需要指定过期时间(Expires)或者有效期(Max-Age)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期Cookie也会被保留下来,就好像浏览器从来没有关闭一样。
持久性Cookie
和关闭浏览器便失效的会话期Cookie不同,持久性Cookie可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。
标记为 Secure 的Cookie只应通过被HTTPS协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过Cookie传输,因为Cookie有其固有的不安全性,Secure 标记也无法提供确实的安全保障。从 Chrome 52 和 Firefox 52 开始,不安全的站点(http:)无法使用Cookie的 Secure 标记。
为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。如果包含服务端 Session 信息的 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记。
Domain 和 Path 标识定义了Cookie的作用域:即Cookie应该发送给哪些URL。
Domain 标识指定了哪些主机可以接受Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了Domain,则一般包含子域名。
Path 标识指定了主机下的哪些路径可以接受Cookie(该URL路径必须存在于请求URL中)。以字符 %x2F ("/") 作为路径分隔符,子路径也会被匹配。
SameSite Cookie允许服务器要求某个cookie在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。但目前SameSite Cookie还处于实验阶段,并不是所有浏览器都支持。
JavaScript通过Document.cookies访问Cookie 通过Document.cookie属性可创建新的Cookie,也可通过该属性访问非HttpOnly标记的Cookie。 请留意在安全节提到的安全隐患问题,JavaScript可以通过跨站脚本攻击(XSS)的方式来窃取Cookie。
会话劫持和XSS 在Web应用中,Cookie常用来标记用户或授权会话。因此,如果Web应用的Cookie被窃取,可能导致授权用户的会话受到攻击。常用的窃取Cookie的方法有利用社会工程学攻击和利用应用程序漏洞进行XSS攻击。
HttpOnly类型的Cookie由于阻止了JavaScript对其的访问性而能在一定程度上缓解此类攻击。
跨站请求伪造(CSRF)
- 对用户输入进行过滤来阻止XSS;
- 任何敏感操作都需要确认;
- 用于敏感信息的Cookie只能拥有较短的生命周期;
- 第三方Cookie 每个Cookie都会有与之关联的域(Domain),如果Cookie的域和页面的域相同,那么我们称这个Cookie为第一方Cookie(first-party cookie),如果Cookie的域和页面的域不同,则称之为第三方Cookie(third-party cookie.)。
Cookie的一个极端使用例子是僵尸Cookie(或称之为“删不掉的Cookie”),这类Cookie较难以删除,甚至删除之后会自动重建。它们一般是使用Web storage API、Flash本地共享对象或者其他技术手段来达到的。
HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应,成功响应,重定向,客户端错误和服务器错误。状态代码由 section 10 of RFC 2616定义
100 Continue 这个临时响应表明,迄今为止的所有内容都是可行的,客户端应该继续请求,如果已经完成,则忽略它。 101 Switching Protocol 该代码是响应客户端的 Upgrade 标头发送的,并且指示服务器也正在切换的协议。 102 Processing (WebDAV) 此代码表示服务器已收到并正在处理该请求,但没有响应可用
204 No Content 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。
HTTP 消息头允许客户端和服务器通过 request和 response传递附加信息。一个请求头由不区分大小写的名称后跟一个冒号“:”,冒号后跟具体的值(不带换行符)组成。该值前面的引导空白会被忽略。
自定专用消息头可通过'X-' 前缀来添加;但是由于其在非标准字段标准化使用时造成的不便之处,这种用法被IETF在2012年6月发布的 RFC5548 中明确弃用;其他的消息头在 IANA 注册表 中列出, 其原始内容在 RFC 4229 中定义.
根据不同上下文,可将消息头分为:
- 一般头: 同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。
- 请求头: 包含有关要获取的资源或客户端本身更多信息的消息头。
- 响应头: 包含有关服务器响应的补充信息,如其位置或服务器本身(名称和版本等)的消息头。
- 实体头: 包含有关实体主体的更多信息,比如主体长(Content-Length)度或其MIME类型。
消息头也可以根据代理对其的处理方式分为:
端到端消息头
这类消息头必须被传输到最终的消息接收者,也即,请求的服务器或响应的客户端。中间的代理服务器必须转发未经修改的端到端消息头,并且必须缓存它们。
逐跳消息头
这类消息头仅对单次传输连接有意义,不能通过代理或缓存进行重新转发。这些消息头包括 Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailer, Transfer-Encoding 及 Upgrade。注意,只能使用 Connection 来设置逐跳一般头。
HTTP(HyperText Transfer Protocol)是万维网(World Wide Web)的基础协议。自 Tim Berners-Lee 博士和他的团队在1989-1991年间创造出它以来,HTTP已经发生了太多的变化,在保持协议简单性的同时,不断扩展其灵活性。如今,HTTP已经从一个只在实验室之间交换文件的早期协议进化到了可以传输图片,高分辨率视频和3D效果的现代复杂互联网协议。
HTTP/0.9 的响应内容并不包含HTTP头,这意味着只有HTML文件可以传送,无法传输其他类型的文件;也没有状态码或错误代码:一旦出现问题,一个特殊的包含问题描述信息的HTML文件将被发回,供人们查看。
由于 HTTP/0.9 协议的应用十分有限,浏览器和服务器迅速扩展内容使其用途更广:
- 协议版本信息现在会随着每个请求发送(HTTP/1.0被追加到了GET行)。
- 状态码会在响应开始时发送,使浏览器能了解请求执行成功或失败,并相应调整行为(如更新或使用本地缓存)。
- 引入了HTTP头的概念,无论是对于请求还是响应,允许传输元数据,使协议变得非常灵活,更具扩展性。
- 在新HTTP头的帮助下,具备了传输除纯文本HTML文件以外其他类型文档的能力(感谢Content-Type头)。
HTTP和Web安全模型--同源策略是互不相关的。事实上,当前的Web安全模型是在HTTP被创造出来后才被发展的!这些年来,已经证实了它如果能通过在特定的约束下移除一些这个策略的限制来管的宽松些的话,将会更有用。这些策略导致大量的成本和时间被花费在通过转交到服务端来添加一些新的HTTP头来发送。这些被定义在了Cross-Origin Resource Sharing (CORS) or the Content Security Policy (CSP)规范里。
不只是这大量的扩展,很多的其他的头也被加了进来,有些只是实验性的。比较著名的有Do Not Track (DNT) 来控制隐私,X-Frame-Options, 还有很多。
在2010年到2015年,谷歌通过实践了一个实验性的SPDY协议,证明了一个在客户端和服务器端交换数据的另类方式。其收集了浏览器和服务器端的开发者的焦点问题。明确了响应数量的增加和解决复杂的数据传输,SPDY成为了HTTP/2协议的基础。
HTTP/2在HTTP/1.1有几处基本的不同:
- HTTP2是二进制协议而不是文本协议。不再可读和无障碍的手动创建,改善的优化技术现在可被实施。
- 这是一个复用协议。并行的请求能在同一个链接中处理,移除了HTTP/1.x中顺序和阻塞的约束。
- 压缩了headers。因为headers在一系列请求中常常是相似的,其移除了重复和传输重复数据的成本。
- 其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
2016年里HTTP的新扩展:
- 对Alt-Svc的支持允许了给定资源的位置和资源鉴定,允许了更智能的CDN缓冲机制。
- Client-Hints 的引入允许浏览器或者客户端来主动交流它的需求,或者是硬件约束的信息给服务端。
- 在Cookie头中引入安全相关的的前缀,现在帮助保证一个安全的cookie没被更改过。
HTTP消息是服务器和客户端之间交换数据的方式。有两种类型的消息︰ 请求--由客户端发送用来触发一个服务器上的动作;响应--来自服务器的应答。
原始的HTTP消息︰ 由软件、浏览器、 代理或 服务器完成。他们通过配置文件(用于代理服务器或服务器),API (用于浏览器)或其他接口提供HTTP消息。
HTTP/2二进制框架机制被设计为不需要改动任何API或配置文件即可应用︰ 它大体上对用户是透明的。
HTTP 请求和响应具有相似的结构,由以下部分组成︰
- 一行起始行用于描述要执行的请求,或者是对应的状态,成功或失败。这个起始行总是单行的。
- 一个可选的HTTP头集合指明请求或描述消息正文。
- 一个空行指示所有关于请求的元数据已经发送完毕。
- 一个可选的包含请求相关数据的正文 (比如HTML表单内容), 或者响应相关的文档。 正文的大小有起始行的HTTP头来指定。
HTTP/1.x 报文有一些性能上的缺点:
- Header 不像 body,它不会被压缩。
- 两个报文之间的 header 通常非常相似,但它们仍然在连接中重复传输。
- 无法复用。当在同一个服务器打开几个连接时:TCP 热连接比冷连接更加有效。
HTTP/2 引入了一个额外的步骤:它将 HTTP/1.x 消息分成帧并嵌入到流 (stream) 中。数据帧和报头帧分离,这将允许报头压缩。将多个流组合,这是一个被称为 多路复用 (multiplexing) 的过程,它允许更有效的底层 TCP 连接。
HTTP 报文是使用 HTTP 的关键;它们的结构简单,并且具有高可扩展性。HTTP/2 帧机制是在 HTTP/1.x 语法和底层传输协议之间增加了一个新的中间层,而没有从根本上修改它,即它是建立在经过验证的机制之上。
在像 HTTP 这样的Client-Server(客户端-服务器)协议中,会话分为三个阶段:
- 客户端建立一条 TCP 连接(如果传输层不是 TCP,也可以是其他适合的连接)。
- 客户端发送请求并等待应答。
- 服务器处理请求并送回应答,回应包括一个状态码和对应的数据。
连接管理是一个 HTTP 的关键话题:打开和保持连接在很大程度上影响着网站和 Web 应用程序的性能。在 HTTP/1.x 里有好些个模型:短连接, 长连接, 和 HTTP 流水线。
有两个新的模型在 HTTP/1.1 诞生了。首先是长连接模型,它会保持连接去完成多次连续的请求,减少了不断重新打开连接的时间。然后是 HTTP 流水线模型,它还要更先进一些,多个连续的请求甚至都不用等待立即返回就可以被发送,这样就减少了耗费在网络延迟上的时间。
<canvas>
提供了一些使用 JavaScript 来绘制 2D 图像的接口;
<canvas>
元素有一个叫做 getContext() 的方法,这个方法是用来获得渲染上下文和它的绘画功能。getContext()只有一个参数,上下文的格式
可缩放矢量图形 (SVG) 帮助你使用直线,曲线,和其他的几何图形来生成(渲染)图像。通过使用矢量图形,你能够画出任意拉伸也不失真的图像。
开启 WebGL(即 Web 3D 图像 API)历程的指南。这项技术可帮助你在 Web 内容中使用标准的 OpenGL ES。
Mathematical Markup Language (MathML) 是一个用于描述数学公式、符号的一种 XML 标记语言。
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object )都有一个私有属性(称之为 proto)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象 ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
给对象设置属性会创建自有属性。获取和设置属性的唯一限制是内置 getter 或 setter 的属性。
JavaScript创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放。 后一个过程称为垃圾回收。这个“自动”是混乱的根源,并让JavaScript(和其他高级语言)开发者感觉他们可以不关心内存管理。 这是错误的。
不管什么程序语言,内存生命周期基本是一致的:
- 分配你所需要的内存;
- 使用分配到的内存(读、写);
- 不需要时将其释放\归还;
所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像JavaScript这些高级语言中,大部分都是隐含的。
使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。
大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“所分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。
高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。
垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。
在这里,“对象”的概念不仅特指 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。
这是最天真的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。
限制:循环引用 该算法有个限制:无法处理循环引用。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。
这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。
“脏检查”是Angular中的核心机制之一,它是实现双向绑定、MVVM模式的重要基础。
Angular将双向绑定转换为一堆watch表达式,然后递归检查这些watch表达式的结果是否变了,如果变了,则执行相应的watcher函数。等到Model的值不再变化,也就不会再有watcher函数被触发,一个完整的digest循环就结束了。
我们经常听说Angular是一个MV*
的框架,这是因为Angular拓展了浏览器的事件模型,建立了一个自己的上下文环境。
当接受View上的事件指令所转发的事件时,就会切换到Angular的上下文环境,来相应这类事件,$digest循环就会触发。
$digest是一个内部函数,正常的应用代码中是不应该直接调用它的。要想主动触发它,就要调用scope.$apply函数,它是触发Angular“脏检查机制”的常用公开接口。
Angular并不是周期性触发藏检查。只有当UI事件,ajax请求或者 timeout 延迟事件,才会触发脏检查。
- 简单理解,一次脏检查就是调用一次 $apply() 或者 $digest(),将数据中最新的值呈现在界面上。
- 而每次 UI 事件变更,ajax 还有 timeout 都会触发 $apply()。
$watch和$digest是相辅相成的。两者一起,构成了Angular作用域的核心:数据变化的响应。 监听器的监听函数应当返回我们所关注的那部分数据的变化,通常,这部分数据就存在于作用域中。为了使得访问作用域更便利,在调用监控函数的时候,使用当前作用域作为实参。
遍历一遍所有watcher函数称为一轮脏检查。执行完一轮脏检查,如果任何一个watcher所监听的值改变过,那么就会重新再进行一轮脏检查,直到所有的watcher函数都报告其所监听的值不再变了。
箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数
引入箭头函数有两个方面的作用:更简短的函数并且不绑定this。
在箭头函数出现之前,每个新定义的函数都有它自己的 this值(在构造函数的情况下是一个新对象,在严格模式的函数调用中为 undefined,如果该函数被称为“对象方法”则为基础对象等)。This被证明是令人厌烦的面向对象风格的编程。
由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this---译者注),他们的第一个参数会被忽略。(这种现象对于bind方法同样成立---译者注)
箭头函数表达式对非方法函数是最合适的。
箭头函数没有定义this绑定。另一个涉及Object.defineProperty();
箭头函数不能用作构造器,和 new一起用会抛出错误。
yield 关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作生成器。
箭头函数可以有一个“简写体”或常见的“块体”。
在一个简写体中,只需要一个表达式,并附加一个隐式的返回值。在块体中,必须使用明确的return语句。
闭包是函数和声明该函数的词法环境的组合。
JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。
makeAdder 是一个函数工厂 — 他创建了将指定的值和它的参数相加求和的函数。
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。
因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
在 Web 中,你想要这样做的情况特别常见。大部分我们所写的 JavaScript 代码都是基于事件的 — 定义某种行为,然后将其添加到用户触发的事件之上(比如点击或者按键)。我们的代码通常作为回调:为响应事件而执行的函数。
编程语言中,比如 Java,是支持将方法声明为私有的,即它们只能被同一个类中的其它方法所调用。
而 JavaScript 没有这种原生支持,但我们可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免非核心的方法弄乱了代码的公共接口部分。
JavaScript类型化数组是一种类似数组的对象,并提供了一种用于访问原始二进制数据的机制。 正如你可能已经知道,Array 存储的对象能动态增多和减少,并且可以存储任何JavaScript值。JavaScript引擎会做一些内部优化,以便对数组的操作可以很快。然而,随着Web应用程序变得越来越强大,尤其一些新增加的功能例如:音频视频编辑,访问WebSockets的原始数据等,很明显有些时候如果使用JavaScript代码可以快速方便地通过类型化数组来操作原始的二进制数据将会非常有帮助。
但是,不要把类型化数组与正常数组混淆,因为在类型数组上调用 Array.isArray() 会返回false。此外,并不是所有可用于正常数组的方法都能被类型化数组所支持(如 push 和 pop)。
浏览器组成可分两部分:Shell+内核。浏览器内核又可以分成两部分:渲染引擎(layout engineer或者Rendering Engine)和JS引擎。
浏览器内核分成两部分渲染引擎和js引擎,由于js引擎越来越独立,内核就倾向于只指渲染引擎 渲染引擎是一种对HTML文档进行解析并将其显示在页面上的工具
webkit的渲染过程: 构建DOM树、构建Render树,布局Render树,绘制Render树。
浏览器在解析HTML文件的时候,“自上而下”加在,加载的过程中进行解析渲染。在解析过程中,如果遇到请求外部资源,如图片、CSS、iconfot等,这些请求过程是异步的,不会影响HTML文档的继续加载和解析。
浏览器首先会解析HTML文件构造DOM树,然后解析CSS文件构建渲染树,渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕。这个过程非常复杂,涉及到两个概念:reflow 和 repaint。
页面首次加载的时候,两个过程都会发生,这两个过程都很消耗性能,尤其是reflow,如果优化的不好,会造成很坏的用户体验。所以,我们要尽量减少reflow和repaint。尽量合并一些过程。
JS的执行机制就是一个主线程 + 一个任务队列。同步任务就是放在主线程上执行的任务,异步任务就是放在任务队列的任务。所有的同步任务都在主线程执行,这构成了一个执行栈,异步任务有了运行结果会在任务队列中放置一个事件,比如定时2秒,到2秒后才能放进任务队列(callback放进任务队列,而不是setTimeout函数放进队列)。脚本运行时,先依次运行执行栈,然后从队列中提取事件来运行任务队列中的任务,这个过程是不断重复的。所以叫事件循环(Event Loop)。
因为JS是单线程的,这是从JS引擎的角度来看的,所谓的单线程就是指在JS引擎中负责解释和执行JS代码的线程只有一个:主线程。 JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。 为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
JS是单线程的,那么他是如何是实现异步操作的
JS的异步是通过回调函数实现的,即通过任务队列,在主线程执行完当前的任务栈(所有的同步操作),主线程空闲后轮询任务队列,并将任务队列中的任务(回调函数)取出来执行。”回调函数”(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。
JS中的异步运行机制
-
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
-
主线程之外,还存在一个”任务队列”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
-
一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
-
主线程不断重复上面的第三步。
JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。 其中栈存放变量,堆存放复杂对象,池存放常量。
JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中(闭包除外),由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问
引用数据类型的值是保存在堆内存中的对象。JS不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。
堆存取数据的方式,则与书架与书非常相似。
书虽然也有序的存放在书架上,但是我们只要知道书的名字,我们就可以很方便的取出我们想要的书,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。好比在JSON格式的数据中,我们存储的key-value是可以无序的,因为顺序的不同并不影响我们的使用,我们只需要关心书的名字。
typeof(null) //object
typeof(undefined) //undefined
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
前面说过,及时清除引用非常重要。但是,你不可能记得那么多,有时候一疏忽就忘了,所以才有那么多内存泄漏。
最好能有一种方法,在新建引用的时候就声明,哪些引用必须手动清除,哪些引用可以忽略不计,当其他引用消失以后,垃圾回收机制就可以释放内存。这样就能大大减轻程序员的负担,你只要清除主要引用就可以了。
ES6 考虑到了这一点,推出了两种新的数据结构:WeakSet
和 WeakMap
。它们对于值的引用都是不计入垃圾回收机制的,所以名字里面才会有一个"Weak",表示这是弱引用。
性能 可用性 伸缩性 扩展性 安全性
反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理的作用:
(1)保证内网的安全,可以使用反向代理提供WAF功能,阻止web攻击
大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。
公司会建立很多的服务器,这些服务器组成了服务器集群,然后,当用户访问网站的时候,先访问一个中间服务器,再让这个中间服务器在服务器集群中选择一个压力较小的服务器,然后将该访问请求引入选择的服务器
所以,用户每次访问,都会保证服务器集群中的每个服务器压力趋于平衡,分担了服务器压力,避免了服务器崩溃的情况
一句话:nginx会给你分配服务器压力小的去访问
nginx通过proxy_pass_http 配置代理站点,upstream实现负载均衡。
babel 转译语法需要一些plugin 如 react,es2015,stage-0,stage-1等等
其中的 es2015 表示 babel会加载 es6 相关的编译模块
然后 stage-0 表示的是什么呢? stage 系列集合了一些对 es7 的草案支持的插件,由于是草案,所以作为插件的形式提供。
- stage-0 - Strawman: just an idea, possible Babel plugin.
- stage-1 - Proposal: this is worth working on.
- stage-2 - Draft: initial spec.
- stage-3 - Candidate: complete spec and initial browser implementations.
- stage-4 - Finished: will be added to the next yearly release.
stage 是向下兼容 0>1>2>3>4 所包含的插件数量依次减少
babel polyfill 有三种:
- babel-runtime
- babel-plugin-transform-runtime
- babel-polyfill
babel-runtime和 babel-plugin-transform-runtime的区别是,相当一前者是手动挡而后者是自动挡,每当要转译一个api时都要手动加上require('babel-runtime'),而babel-plugin-transform-runtime会由工具自动添加,主要的功能是为api提供沙箱的垫片方案,不会污染全局的api,因此适合用在第三方的开发产品中。
runtime转换器插件主要做了三件事:
- 当你使用generators/async方法、函数时自动调用babel-runtime/regenerator
- 当你使用ES6 的Map或者内置的东西时自动调用babel-runtime/core-js
- 移除内联babel helpers并替换使用babel-runtime/helpers来替换
transform-runtime优点
- 不会污染全局变量
- 多次使用只会打包一次
- 依赖统一按需引入,无重复引入,无多余引入
transform-runtime缺点:
- 不支持实例化的方法Array.includes(x) 就不能转化
- 如果使用的API用的次数不是很多,那么transform-runtime 引入polyfill的包会比不是transform-runtime 时大
总的来说一句话,你可以使用内置的一些东西例如Promise,Set,Symbol等,就像使用无缝的使用polyfill,来使用babel 特性,并且无全局污染、极高代码库适用性。
babel-polyfill则是通过改写全局prototype的方式实现,比较适合单独运行的项目。 开启babel-polyfill的方式,可以直接在代码中require,或者在webpack的entry中添加,也可以在babel的env中设置useBuildins为true来开启。 但是babel-polyfill会有近100K, 打包后代码冗余量比较大, 对于现代的浏览器,有些不需要polyfill,造成流量浪费 污染了全局对象
- angularjs官方声明不在维护;
- 顶级对象$scope让逻辑变得混乱;
- vue + vue-router + vuex 工具链强大;
- angular脏检查影响性能;vue 组件化开发;
1、先从数列中取出一个数作为基准数
2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
3、再对左右区间重复第二步,直到各区间只有一个数
二分插入排序也是一种插入排序,原理和插入排序是一样的,但是之所以二分是快速查找出要插入的位置; 插入排序是基于比较的排序。所谓的基于比较,就是通过比较数组中的元素,看谁大谁小,根据结果来调整元素的位置。
因此,对于这类排序,就有两种基本的操作:①比较操作; ②交换操作
这个代理实际上是利用http-proxy-middleware这个插件完成的,具体到这个插件的运行机制,由于是英文再加上能力有限就没深究了。但我想探究的是这种代理方式实际上是如何做到的,我看网上有人说实际上就是我们的本地服务器将请求转发给了目标服务器。之所以出现跨域是因为浏览器有同源策略的限制,但服务器是没有的,所以这种代理方式能够实现的机制大体就是:
本地服务器 --》 代理 --》目标服务器 --》拿到数据后通过代理伪装成本地服务请求的返回值 ---》然后浏览器就顺利收到了我们想要的数据
这是我的简单理解,按这个理解来说的话只要服务器允许跨域,任何人都能够拿到它的数据吗?那样同源策略不就大大弱化了吗?目前对这个问题还不是太理解,希望有想法的小伙伴留言指正!
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
对象里目前存在的属性描述符= 有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。
DocumentFragments 是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。
因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(reflow)(对元素位置和几何上的计算)。因此,使用文档片段document fragments 通常会起到优化性能的作用(better performance)。
RegExp.$1...$9属性用于返回正则表达式模式中某个子表达式匹配的文本。
正则表达式中每个小括号内的部分表达式就是一个子表达式。
该属性是RegExp全局对象的一个只读属性,所有主流浏览器均支持该属性。
reduce 为数组中的每一个元素依次执行回调函数 reduce的用处多多,比如计算数组求和是比较普通的方法了,还有一种比较好用的妙处是可以进行二维数组的展平(flatten)
Object.defineProperty(obj, prop, descriptor)
Object.defineProperty 是定义key为Symbol的属性的方法之一。
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
- Observer:能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
Observer的核心是通过Obeject.defineProperty()来监听数据的变动,这个函数内部定义setter和getter,每当数据发生变化,就会触发setter。这时候Observer就要通知订阅者,订阅者就是Watcher。
- Compile:对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
Compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
- Watcher:作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:
在自身实例化时往属性订阅器(dep)里面添加自己 自身必须有一个update()方法 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调
(所谓数据劫持就是给对象增加get,set)
-
观察对象,给对象增加Object.defineProperty
-
vue特点是不能新增不存在的属性 不存在的属性没有get和set
-
深度响应 因为每次赋予一个新对象时会给这个新对象增加defineProperty(数据劫持)
通过递归observe(val)进行数据劫持添加上了get和set,递归继续向a里面的对象去定义属性,
数据代理就是让我们每次拿data里的数据时,不用每次都写一长串,如mvvm._data.a.b这种,我们其实可以直接写成mvvm.a.b这种显而易见的方式
编译一下了,把{{}}里面的内容解析出来 但是我们手动修改后的数据并没有在页面上发生改变
发布订阅主要靠的就是数组关系,订阅就是放入函数,发布就是让数组里的函数执行
现在我们要订阅一个事件,当数据改变需要重新刷新视图,这就需要在replace替换的逻辑里来处理 通过new Watcher把数据订阅一下,数据一变就执行改变内容的操作
Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。
当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
由于 Vue 不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。
$('#div1').slideDown(1000);
//向下展开,下拉。1000毫秒,表示动画展开过程时间。
$('#div1').slideUp(1000);
//向上收起
$('#div1').slideToggle(1000);
//合成展开收起
跨文档传输消息(XDM)也就是跨域传递消息,是实现跨域的另一种方法 XDM的核心就是浏览器的postMessage()方法 在XDM中,“另一个地方”就是指包含在当前页面的iframe元素,或者由当前页面弹出的窗口。
postMessage()方法就是用来与不同域之间的窗口进行通信的API,之所以只能与内嵌框架或在当前页面的弹出窗口进行通信,是因为要使用postMessage()的前提就是要获得接收页面所在的窗口对象,在该对象上调用postMessage方法。
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后(e.g., 在该方法之后设置的事件、之前设置的timeout 事件,etc.)向目标窗口派发一个 MessageEvent 消息。 该MessageEvent消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
如HTML转义符、java 转义符、xml 转义符、 oracle 转义符、sql 转义符 、sqlserver 转义符、php 转义符、asp 转义符、vb转义符、 javascript 转义符等等,还有网址中的百分号。
例如,HTML的< >&"©
分别是<,>,&,",©;的转义字符
XML只有5个转义符: < >& " '
window.requestAnimationFrame() 方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。
创建:
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
添加:
appendChild()
移出:
removeChild()
替换:
replaceChild()
插入:
insertBefore()
复制:
cloneNode(true)
查找:
getElementsByTagName() //通过标签名称
getElementsByClassName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
使用 getCurrentPosition() 方法来获得用户的位置。
q.js在nodejs里是一个非常流行的promise库
q.js跟async要解决的问题差不多,都是解决回调函数的嵌套问题,避免嵌套层级太深导致一系列的问题.只是q.js是以promise来实现回调的扁平化,而async则是通过流程来控制多个异步回调的处理.
在某个元素之前插入一个新的元素;
在调用此方法时,必须告诉它三件事: 1.想插入的新元素(newElement). 2.想把这个新元素插入到哪个现有元素(targetElement)的前面。 3.这两个共同的父元素(parentElement);
- Array.isArray();
- instanceof操作符
var arrayStr=new Array("1","2","3","4","5");
alert(arrayStr instanceof Array);
- Object.prototype.toString.call(obj) === '[object Array]';
-
Unicode 是「字符集」
-
UTF-8 是「编码规则」
-
字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point)
-
编码规则:将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)
广义的 Unicode 是一个标准,定义了一个字符集以及一系列的编码规则,即 Unicode 字符集和 UTF-8、UTF-16、UTF-32 等等编码……
Unicode 字符集为每一个字符分配一个码位,例如「知」的码位是 30693,记作 U+77E5(30693 的十六进制为 0x77E5)。
UTF-8 顾名思义,是一套以 8 位为一个编码单位的可变长编码。会将一个码位编码为 1 到 4 个字节
Google开发者文档中有提到:
mobile browsers will wait approximately 300ms from the time that you tap the button to fire the click event. > The reason for this is that the browser is waiting to see if you are actually performing a double tap.
移动浏览器为什么会设置300毫秒的等待时间呢?这与双击缩放的方案有关。平时我们有可能已经注意到了,双击缩放,即用手指在屏幕上快速点击两次,可以看到内容或者图片放大,再次双击,浏览器会将网页缩放至原始比例。
<meta name="viewport" content="width=device-width user-scalable= 'no'">
FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick 在检测到touchend事件的时候,会通过 DOM 自定义事件立即触发一个模拟click事件,并把浏览器在 300 毫秒之后真正触发的click事件阻止掉。
指针事件最初由微软提出,现已进入 W3C 规范的候选推荐标准阶段 (Candidate Recommendation)。指针事件是一个新的 web 事件系列,相应的规范旨在使用一个单独的事件模型,对所有输入类型,包括鼠标 (mouse)、触摸 (touch)、触控 (stylus) 等,进行统一的处理。
指针事件 (Pointer Events) 目前兼容性不太好,不知道在以后会不会更加支持。
当Client端收到Server的SYN+ACK应答后,其状态变为ESTABLISHED,并发送ACK包给Server;
如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且 依次等待3秒、6秒、12秒后重新发送SYN+ACK包 ,以便Client重新发送ACK包。
Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。
如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。 但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包响应,方能感知到Server的错误。
-
块级元素会独占一行,其宽度自动填满其父元素宽度;行内元素不会独占一行,相邻的行内元素会排列在同一行,直至一行排不下才会换行,其宽度随元素的内容而变化。
-
块级元素可以包含行内元素和块级元素;行内元素不能包含块级元素。
-
行内元素设置width、height、margin-top、margin-bottom、padding-top、padding-bottom无效。
display:inline-block; display:inline; display:block;
IE浏览器可以使用userData来存储数据,容量可达到640K,这种方案是很可靠的,不需要安装额外的插件。缺点:它仅在IE下有效。
$.ajax()函数依赖服务器提供的信息来处理返回的数据。如果服务器报告说返回的数据是XML,那么返回的结果就可以用普通的XML方法或者jQuery的选择器来遍历。如果见得到其他类型,比如HTML,则数据就以文本形式来对待。
通过dataType选项还可以指定其他不同数据处理方式。除了单纯的XML,还可以指定 html、json、jsonp、script或者text。
B+树和二叉树、平衡二叉树一样,都是经典的数据结构。B+树由B树和索引顺序访问方法(ISAM,是不是很熟悉?对,这也是MyISAM引擎最初参考的数据结构)演化而来,但是在实际使用过程中几乎已经没有使用B树的情况了。
B+树的定义十分复杂,因此只简要地介绍B+树:B+树是为磁盘或其他直接存取辅助设备而设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶节点指针进行连接。
-
所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
-
不可能在非叶子结点命中;
-
非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
-
更适合文件索引系统;
什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
事件委托到底是一个什么原理:
有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。
这里其实还有2层意思的:
第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;
第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
为什么要用事件委托:
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;
浏览器事件委托的原理:
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题)
事件一开始从文档的根节点流向目标对象(捕获阶段), 然后在目标对向上被触发(目标阶段), 之后再回溯到文档的根节点(冒泡阶段)。
function(){ /* code */ }(); // SyntaxError: Unexpected token (
function foo(){ /* code */ }(); // SyntaxError: Unexpected token )
立即执行函数(IIFE)
(function(){ /* code */ }());
为什么这样就能立即执行并且不报错呢?因为在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明。
# 最常用的两种写法
(function(){ /* code */ }()); # 老道推荐写法
(function(){ /* code */ })(); # 当然这种也可以
# 括号和JS的一些操作符(如 = && || ,等)可以在函数表达式和函数声明上消除歧义
# 如下代码中,解析器已经知道一个是表达式了,于是也会把另一个默认为表达式
# 但是两者交换则会报错
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
# 如果你不怕代码晦涩难读,也可以选择一元运算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
# 你也可以这样
new function(){ /* code */ }
new function(){ /* code */ }() // 带参数
立即执行函数能配合闭包保存状态。像普通的函数传参一样,立即执行函数也能传参数。如果在函数内部再定义一个函数,而里面的那个函数能引用外部的变量和参数(闭包),利用这一点,我们能使用立即执行函数锁住变量保存状态。
立即执行函数在模块化中也大有用处。用立即执行函数处理模块化可以减少全局变量造成的空间污染,构造更多的私有变量。
addEventListener() 是 W3C DOM 规范中提供的注册事件监听器的方法。它的优点包括:
- 它允许给一个事件注册多个监听器。 特别是在使用AJAX库,JavaScript模块,或其他需要第三方库/插件的代码。
- 它提供了一种更精细的手段控制 listener 的触发阶段。(即可以选择捕获或者冒泡)。
- 它对任何 DOM 元素都是有效的,而不仅仅只对 HTML 元素有效。
target.removeEventListener(type, listener[, useCapture])
element.innerHTML 属性设置或获取HTML语法表示的元素的后代。
Node.innerText 是一个表示一个节点及其后代的“渲染”文本内容的属性。
Node.insertBefore() 在参考节点之前插入一个节点作为一个指定父节点的子节点。
Node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。
Document.createElement() #添加元素 Document.createTextNode() #添加文本
Node是一个接口,许多DOM类型从这个接口继承,并允许类似地处理(或测试)这些各种类型。
以下接口都从Node继承其方法和属性: Document, Element, CharacterData (which Text, Comment, and CDATASection inherit), ProcessingInstruction, DocumentFragment, DocumentType, Notation, Entity, EntityReference
从其父类EventTarget[1]继承属性。
Element是非常通用的基类,所有 Document对象下的对象都继承它. 这个接口描述了所有相同种类的元素所普遍具有的方法和属性。 这些继承自Element并且增加了一些额外功能的接口描述了具体的行为. 例如, HTMLElement 接口是所有HTML元素的基础接口, 而 SVGElement 接口是所有SVG元素的基本接口.
Document接口表示任何在浏览器中已经加载好的网页,并作为一个入口去操作网页内容(也就是DOM tree)。DOM tree包括像 <body>
、<table>
这样的还有其他的元素。它提供了全局操作document的功能,像获取网页的URL和在document里创建一个新的元素。
String.concat() String.endsWith() String.includes() String.lastIndexOf() String.localeCompare() String.match() String.padEnd() String.repeat()
String.substr() String.trim()
内插表达式——Hi\n${name}!
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
其中File对象可以是来自用户在一个<input>
元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。
移位时,移出的位数全部丢弃,移出的空位补入的数与左移还是右移有关。如果是左移,则规定补入的数全部是0;如果是右移,还与被移位的数据是否带符号有关。若是不带符号数,则补入的数全部为0;若是带符号数,则补入的数全部等于原数的最左端位上的原数(即原符号位) 类似于乘除法,左移一位相当于乘以2.两位乘以4
- 优化
重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。
使用:script标签引入cdn/git下载文件;commonjs方式require。
修改:下载.js源文件(非.min.js/其他.js);修改后本地保存,然后引入本地文件。
JavaScript 变量可以是局部变量或全局变量。私有变量可以用到闭包。 闭包是可访问上一层函数作用域里变量的函数,即便上一层函数已经关闭。
- tcp面向连接,udp无连接;
- 对系统资源要求(tcp较多,udp少);
- udp程序结构简单;
- 流模式与数据报模式;
- tcp保证数据正确性,udp可能丢包;
- tcp保证数据顺序,udp不保证;
HTML事件可以是浏览器行为,也可以是用户行为。 HTML 事件的实例: HTML 页面完成加载 HTML input 字段改变时 HTML 按钮被点击
javascript:void(0) 中最关键的是 void 关键字, void 是 JavaScript 中非常重要的关键字, 该操作符指定要计算一个表达式但是不返回值。
href="#"与href="javascript:void(0)"的区别
#
包含了一个位置信息,默认的锚是#top 也就是网页的上端。而javascript:void(0), 仅仅表示一个死链接。
在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id
。
如果你要定义一个死链接请使用 javascript:void(0)。
百度的面试氛围很是轻松
javascript会调用valueOf来转换为一个基本数据类型,在这种情况下,如果javascript不能通过valueOf转成一个number,会尝试调用toString,然后再转。实在无法转就只能NaN了。
new一个Function,继承通过prototype。超类和子类可以通过子类的prototype=new 超类(),然后把prototype的constructor指回子类。
- IE IE浏览器(Microsoft Internet Explorer) 对url长度限制是2083(2K+53),超过这个限制,则自动截断(若是form提交则提交按钮不起作用)。
- firefox firefox(火狐浏览器)的url长度限制为 65 536字符,但实际上有效的URL最大长度不少于100,000个字符。
- chrome chrome(谷歌)的url长度限制超过8182个字符返回本文开头时列出的错误。
W3C是addEventListener,IE是attachEvent。 attachEvent——兼容:IE7、IE8;不兼容firefox、chrome、IE9、IE10、IE11、safari、opera addEventListener——兼容:firefox、chrome、IE、safari、opera;不兼容IE7、IE8
addEventListener共有3个参数,如下所示:element.addEventListener(type,listener,useCapture)
;
attachEvent共有2个参数,如下所示:element.attachEvent(type,listener)
;
-
在浏览器支持上,IE5-8支持前者,IE9+和其他浏览器支持后者。由于原始版本IE并不支持事件的捕获,所以前者只有两个参数:事件类型和处理程序函数。
-
前者采用了带有 'on' 前缀的时间处理程序属性名,而后者不带此前缀。
-
前者允许相同的事件处理程序函数被注册多次。
使用bubbling(冒泡)模式,他是从内而外的流程,所以会先执行蓝色元素的click事件再执行红色元素的click事件, capture(捕获)模式,和bubbling(冒泡)模式相反是由外而内,会先执行红色元素的click事件才执行蓝色元素的click事件。
事件从事件源逐级向上传递,这一机制就叫事件冒泡机制。
- event 对象的 target 属性指代触发这个 event 的对象。其在冒泡和捕获型事件中的指代与 event.currentTarget 均不同。而 currentTarget 是指当事件在整个DOM中起泡时,找到本次事件的绑定者;而对应 target 指代本次事件的引发者。
因为在加法运算里,本来优先级就是字符串最高,数值次之,在隐式转换里,除去布尔值之外,大多数的对象都是通过 toString 转换的原始值,JS在拿到原始值之后发现可用,就直接使用了,所以最后转成字符是一件很正常的事情
<script type="text/javascript">
function handleRes(data){
console.log(data.name + 'is' + data.age + 'years old');
//tom is 20 years old
}
</script>
<script type="text/javascript" src="http://www.baidu.com/person.js"></script>
url http://www.baidu.com/person.js 的代码如下
handleRes({name: 'tom', age: 20})
- 利用jQuery发送jsonp请求
$.ajax({
url: 'xxxxx', //一个跨域的url
type: 'get',
dataType: 'jsonp', //设置服务器返回的数据类型
jsonp: 'onJsonPLoad', //这个值用来配置前面提过的callback,它会拼接到url的后面
jsonpCallback: 'handleRes', //用来设置回调函数名称
success: function (res){ //这里的success回调就相当于之前写到的handleRes方法。
console.log(res);
}})
- 可能很多小伙伴都不在项目中使用jQuery了,我们可以利用这个 https://github.com/webmodules/jsonp 插件来封装一个发送jsonp请求的方法,这个插件的具体使用方法也很简单大家可以点开链接查看,这里就不做赘述了。
HTTP请求报文由3部分组成(请求行+请求头+请求体)
- 请求方法
GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。
- Cookie
服务端是怎么知道客户端的多个请求是隶属于一个Session呢?注意到后台的那个jsessionid=5F4771183629C9834F8382E23BE13C4C木有?原来就是通过HTTP请求报文头的Cookie属性的jsessionid的值关联起来的!
HTTP的响应报文也由三部分组成(响应行+响应头+响应体)
- {} == {}/false
- [] == []/false
- null==undefined/true
<body>
<div class="left"></div>
<div class="main"></div>
</body>
<style>
.left {
float: left;
width: 100px;
border: 1px solid black;
height: -webkit-fill-available;
}
.main {
margin-left: 110px;
width: 100%;
border: 1px solid black;
height: -webkit-fill-available;
}
</style>
.left {
float: left;
margin-right: 10px;
width: 100px;
border: 1px solid black;
height: -webkit-fill-available;
}
.main {
overflow: hidden;
border: 1px solid black;
height: -webkit-fill-available;
/* 或overflow:auto */
}
/*
* tableUI 0.1
* Copyright (c) 2009JustinYoung http://justinyoung.cnblogs.com/
* Date: 2010-03-30
* 使用tableUI可以方便地将表格提示使用体验。先提供的功能有奇偶行颜色交替,鼠标移上高亮显示
*/
(function ($) {
$.fn.yourName = function (options) {
//各种属性、参数
}
var options = $.extend(defaults, options);
//合并多个对象为一个。这里就是,如果你在调用的时候写了新的参数,就用你新的参数,如果没有写,就用默认的参数。
this.each(function () {
//插件实现代码
});
})(jQuery);
-
快速上手(学习成本低)
-
开发效率高(选择器、批量操作 DOM、链型操作……)
-
一系列的封装(动画、ajax)
-
浏览器兼容(1.x版本 兼容IE6、7、8)
-
jQuery 里有一个插件机制,就是利用$.fn 可以扩展 jQuery 的方法,做到自己定制 jQuery
在提倡前后端分离的情况下,前端相对原来接手了更多的处理逻辑,包括路由。 如果使用react等前端框架建站的话,建议使用前端路由,在前端路由跳转中,始终能够保证是单页应用(SPA),后端更多是提供数据请求接口。
区别在于express是服务器端的路由,也就是说需要向后台服务器发送请求,然后服务器来决定来render那个.html,这也就是最早的mvc架构模式,而前端的路由是将这一过程放在浏览器端,也就是前台写js代码控制,不在请求服务器,前台一般利用histroy和hash来控制,达到不刷新页面可以使显示内容发生变化,这样好处是js代码不发生变化(浏览器端可以维护一个稳定的model);一般单页应用就是前台来控制路由,这样速度更快,用户体验更好。单页应用还将模板拿到了浏览器端,从而解放了服务端,服务端趋于服务化。
- 提高工作效率,低耦合,提高工作效率,每人明确分工;
- 彻底解放前端,前端不再需要向后台提供模板或是后台在前端html中嵌入后台代码
- 提高工作效率,分工更加明确;
- 局部性能提升
- 降低维护成本
- gulp
gulp强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp执行这些task,从而构建项目的整个前端开发流程。 gulp严格上讲,模块化不是他强调的东西,他旨在规范前端开发流程。
- webpack
webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。 webpack更是明显强调模块化开发,而那些文件压缩合并、预处理等功能,不过是他附带的功能。
gulp与webpack上是互补的,还是可替换的,取决于你项目的需求。如果只是个vue或react的单页应用,webpack也就够用;如果webpack某些功能使用起来麻烦甚至没有(雪碧图就没有),那就可以结合gulp一起用。
就像你刚才说的一样,单页面应用会继续火,react和vue接下来几年依然会流行,webpack和gulp这些工具也会变得更加简单,后端的逻辑会更多放到前端来做
- JSON.parse(JSON.stringify(data))
- $.extend(deep, [], obj)
- 自己手写进行实现
function ajax(method, url, data) {
var request = new XMLHttpRequest();
return new Promise(function (resolve, reject) {
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
resolve(request.responseText);
} else {
reject(request.status);
}
}
};
request.open(method, url);
request.send(data);
});
}
var log = document.getElementById('test-promise-ajax-result');
var p = ajax('GET', '/api/categories');
p.then(function (text) {
# 如果AJAX成功,获得响应内容
log.innerText = text;
}).catch(function (status) {
# 如果AJAX失败,获得响应代码
log.innerText = 'ERROR: ' + status;
});
CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}
- 定义模块
根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性
- 模块输出:
模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象
- 加载模块:
加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象
AMD AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范
由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出
requireJS主要解决两个问题
- 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
- js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
CMD CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同.
AMD与CMD区别 最明显的区别就是在模块定义时对依赖的处理不同 1、AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块 2、CMD推崇就近依赖,只有在用到某个模块的时候再去require
方法1.传统引入js包 方法2.在hmtl 加入(推荐)
/*html5 tag*/
<!--[if lt IE 9]>
<script>(function(tags){for(var i=0; i<tags.length; i++)document.createElement(tags[i]);})(["article","aside","details","figcaption","figure","footer","header","hgroup","nav","section","menu","video"]);</script>
<![endif]-->
ES6中的箭头函数会直接调用的this是继承父级的this。
每个函数都有一个prototype(原型)属性,这个属性是一个指针,一个对象。无论什么时候,我们只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性对象指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个 constroctor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。
1、所有的函数都是 Function 的实例。
2、在构造函数上都有一个原型属性 prototype,该属性也是一个对象;
3、那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;
4、而实例对象上有一个 proto 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用。
javascript中,原型也是一个对象,通过原型可以实现对象的属性继承,javascript的对象中都包含了一个protype内部属性,这个属性对应的就是该对象的原型。javascript的原型对象中还包含一个constructor属性,这个属性对应创建所有指向该原型的实例的构造函数。
HTTP是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。在 Web 上进行数据交换的基础,是一种 client-server 协议. HTTP被设计于上20世纪90年代初期,是一种可扩展的协议。它是应用层的协议,通过TCP,或者是TLS-加密的TCP连接来发送,理论上任何可靠的传输协议都可以使用。
在HTTP/2中,这些报文被嵌入到了一个新的二进制结构,帧。帧允许实现很多优化,比如报文头部的压缩和复用。
- 一个HTTP的method,经常是由一个动词像GET, POST 或者一个名词像OPTIONS,HEAD来定义客户端的动作行为。
- 要获取的资源的路径,通常是上下文中就很明显的元素资源的URL,它没有protocol
(http://)
,domain(developer.mozilla.org)
,或是TCP的port(HTTP一般在80端口)。 - HTTP协议版本号。
- 为服务端表达其他信息的可选头部headers。
- 对于一些像POST这样的方法,报文的body就包含了发送的资源,这与回应报文的body类似。
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
- Cache 头域
Cache-Control 这个是非常重要的规则。 这个用来指定Response-Request遵循的缓存机制。各个指令含义如下 Cache-Control:Public 可以被任何缓存所缓存 Cache-Control:Private 内容只缓存到私有缓存中 Cache-Control:no-cache 所有内容都不会被缓存
- Client 头域
- Cookie/Login 头域
- Entity头域
- Miscellaneous 头域
提供了Request的上下文信息的服务器,告诉服务器我是从哪个链接过来的,比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站。
-
Transport 头域
- Connection Connection: keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接
- Host(发送请求时,该报头域是必需的) 请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的
http响应
- HTTP协议版本号。
- 一个状态码(status code),来告知对应请求执行成功或失败,以及失败的原因。
- 一个状态信息,这个信息是非权威的状态码描述信息,可以由服务端自行设定。
- HTTP headers,与请求头部类似。
- 响应报文中更常见地包含获取的资源body。
-
Cache头域
- Expires 浏览器会在指定过期时间内使用本地缓存
-
Cookie/Login 头域
- Set-Cookie 非常重要的header, 用于把cookie 发送到客户端浏览器, 每一个写入cookie都会生成一个Set-Cookie.
- Entity头域 和If-None-Match 配合使用。
- Last-Modified 用于指示资源的最后修改日期和时间。
- Content-Type WEB服务器告诉浏览器自己响应的对象的类型和字符集
- Miscellaneous 头域 指明HTTP服务器的软件信息
- Transport头域 客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接
-
Location头域
- Location 用于重定向一个新的位置, 包含新的URL地址
HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)
从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间
在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重用连接。在后来的HTTP/1.0中以及HTTP/1.1中,引入了重用连接的机制,就是在http请求头中加入Connection: keep-alive来告诉对方这个请求响应完成后不要关闭,下一次咱们还用这个请求继续交流。协议规定HTTP/1.0如果想要保持长连接,需要在请求头中加上Connection: keep-alive,而HTTP/1.1默认是支持长连接的,有没有这个请求头都行。
如果HTTP/1.1版本的http请求报文不希望使用长连接,则要在请求头中加上Connection: close
,接收到这个请求头的对端服务就会主动关闭连接。
(服务器超时,超限可设置) 一般服务端都会设置keep-alive超时时间。超过指定的时间间隔,服务端就会主动关闭连接。同时服务端还会设置一个参数叫最大请求数,比如当最大请求数是300时,只要请求次数超过300次,即使还没到超时时间,服务端也会主动关闭连接。
一般情况下这个特殊标志就是Content-Length,来指明响应体的数据大小,比如Content-Length: 120表示响应体内容有120个字节,这样浏览器接收到120个字节的响应体后就知道了已经响应完成。
把Last-Modified和ETags请求的http报头一起使用,这样可利用客户端(例如浏览器)的缓存。因为服务器首先产生Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存。
过程如下: 1.客户端请求一个页面(A)。
2.服务器返回页面A,并在给A加上一个Last-Modified/ETag。
3.客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。
4.客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。
5.服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。
Etag 主要为了解决 Last-Modified 无法解决的一些问题。
- 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间)
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改
- 某些服务器不能精确的得到文件的最后修改时间;
HTTPS 相比 HTTP 多了一层 SSL/TLS
双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是: (1)不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高 (2)因每个客户端、服务器的安全级别不同,密钥极易泄露
既可以安全的获取公钥,又能防止黑客冒充呢? 那就需要用到终极武器了:SSL 证书(申购) SSL 证书中包含的具体内容有: (1)证书的发布机构CA (2)证书的有效期 (3)公钥 (4)证书所有者 (5)签名
客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验
(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验
(2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发
(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。
(4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密
(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比
(6)对比结果一致,则证明服务器发来的证书合法,没有被冒充
(7)此时浏览器就可以读取证书中的公钥,用于后续加密了
所以通过发送SSL证书的形式,既解决了公钥获取问题,又解决了黑客冒充问题,一箭双雕,HTTPS加密过程也就此形成
所以相比HTTP,HTTPS 传输更加安全
(1) 所有信息都是加密传播,黑客无法窃听。
(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。
(3) 配备身份证书,防止身份被冒充。
HTTPS 缺点:
(1)SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐
(2)HTTPS 降低用户访问速度(多次握手)
(3)网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转)
(4)HTTPS 涉及到的安全算法会消耗 CPU 资源,需要增加大量机器(https访问过程需要加解密)
CA是Certificate Authority的缩写,也叫“证书授权中心”。 它是负责管理和签发证书的第三方机构,就好比例子里面的中介——C 公司。一般来说,CA必须是所有行业和所有公众都信任的、认可的。因此它必须具有足够的权威性。就好比A、B两公司都必须信任C公司,才会找 C 公司作为公章的中介。
- 验证网站是否可信(针对HTTPS)
- 验证某文件是否可信(是否被篡改)
将原有的直接操作dom的思想转变到操作数据上去
vue: vue是一个兴起的前端js库,是一个精简的MVVM。从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来,通过对数据的操作就可以完成对页面视图的渲染。
Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
二者也是可以结合起来一起使用的,vue侧重数据绑定,jquery侧重样式操作,动画效果等,则会更加高效率的完成业务需求
块级元素水平居中 1:margin: 0 auto
element { margin: 0 auto; }
2:负边距+绝对定位
3: 弹性盒子flexbox:
块级元素垂直居中(元素高度已知):
1: 利用负边距+绝对定位
.outside { width:720px; height: 720px; margin: 0 auto ; position: relative; /祖先元素的非static定位/ } .inner { width: 350px; height: 350px; position: absolute; top: 50%; /元素相对其最近的position属性不为static的元素(祖先元素)移动50%,top、right、bottom 和 left 属性指定定位元素的位置。/ margin-top: -175px; /元素向上移动自身的50%,此时,正好垂直居中/ }
href是Hypertext Reference的缩写,表示超文本引用。用来建立当前元素和文档之间的链接。常用的有:link、a。
src是source的缩写,src的内容是页面必不可少的一部分,是引入。src指向的内容会嵌入到文档中当前标签所在的位置。常用的有:img、script、iframe。
sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。
sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。 当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
var Socket = new WebSocket(url, [protocol] );
HTTP 协议有一个缺陷:通信只能由客户端发起。
我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。
- 0 - 表示连接尚未建立。
- 1 - 表示连接已建立,可以进行通信。
- 2 - 表示连接正在进行关闭。
- 3 - 表示连接已经关闭或者连接不能打开。
Socket.send() 使用连接发送数据 Socket.close() 关闭连接
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
send()方法用于向服务器发送数据。
websocketd 的实质,就是命令行的 WebSocket 代理。只要命令行可以执行的程序,都可以通过它与浏览器进行 WebSocket 通信。
常用的 Node 实现有以下三种。
- µWebSockets
- Socket.IO
- WebSocket-Node
要解决的问题是,避免处理函数被频繁的触发,让函数每隔一段时间执行一次,当在执行周期内被触发时,不允许被执行,所以直接为函数的执行添加时间间隔就Ok了。 函数节流应用的实际场景,多数在监听页面元素滚动事件的时候会用到。因为滚动事件,是一个高频触发的事件。以下是监听页面元素滚动的示例代码:
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
当DOM事件被频繁触发时,在延时周期内,只在最后一次被触发时,执行处理函数,在此之前的触发都不进行处理。 clearTimeout() 方法可取消由 setTimeout() 方法设置的 timeout。
# 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer);
# 清除未执行的代码,重置回初始化状态
# timer => 由 setTimeout() 返回的 ID 值。该值标识要取消的延迟执行代码块。
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
函数防抖的要点,也是需要一个setTimeout来辅助实现。延迟执行需要跑的代码。
最早也是最有名的前端模块管理器,非RequireJS莫属。它采用AMD格式,异步加载各种模块。
Webpack 是一个可以将前端模板引擎、预处理语言、JavaScript 模块进行合并、压缩、打包最终成为能被JavaScript 引擎识别可以在浏览器端正常运行的文件。
Entry:入口文件,Webpack 执行构建的过程将从这里开始。给定入口文件,Webpack 会分析所有依赖到的静态资源并加载相应代码进行处理,最终打包成指定的文件输出到目标文件夹中。
Output:与Entry 相对应,Output 可以配置打包完成后输出的文件位置及文件名等信息。
Module:配置处理模块的规则。Module 通常会包含一个Loader 数组,那Loader 在这个过程中起什么作用呢?Webpack 本身只能理解JavaScript,但是却可以打包Sass、Less、png 等非 JS 资源,主要是因为在加载这些资源前都会链式调用 loader 进行预处理,将其转换成 Webpack可以理解的JavaScript 模块。
Resolve:配置寻找模块的规则。在这个选项中可以配置查找文件的扩展名和文件别名等。
Plugins:配置扩展插件,用于扩展Webpack 的功能。大量的Plugins 插件几乎可以让Webpack 完成任何与构建相关的任务。
DevServer:在本地启用一个HTTP 服务器监听特定的端口,供开发时测试与调试使用。
Webpack的处理速度更快更直接,能打包更多不同类型的文件。
module.exports = {
entry: __dirname + "/app/main.js", #已多次提及的唯一入口文件
output: {
path: __dirname + "/public", #打包后的文件存放的地方
filename: "bundle.js" #打包后输出文件的文件名
}
}
npm install --save-dev webpack-dev-server
loader:
- test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
- loader:loader的名称(必须)
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选);
- query:为loaders提供额外的设置选项(可选)
Babel其实是一个编译JavaScript的平台,它可以编译代码帮你达到以下目的:
- 让你能使用最新的JavaScript代码(ES6,ES7...),而不用管新标准是否被当前使用的浏览器完全支持;
- 让你能使用基于JavaScript进行了拓展的语言,比如React的JSX;
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-env-preset包和解析JSX的babel-preset-react包)。
HTTP/2是HTTP协议自1999年HTTP 1.1发布后的首个更新,主要基于SPDY协议(是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验)。
性能提升的核心在于二进制帧层.它指HTTP消息在客户端和服务端如何封装和传输.
-
流,消息,帧 接下来介绍二进制帧机制来明白数据如何在客户端和服务端交换的。
-
请求和响应的多路复用
-
流的优先级.
-
流量控制
流量控制是一种机制,用来阻止发送者发送大量的接收者不需要,或者没能力处理的数据.接收者可能会在重负下很繁忙,或者只愿意分配固定的资源给特定的流.例如,客户端可能以高的优先级请求大量的视频数据,然后用户暂停了视频,那么客户端现在想要停止或者减少服务端的传输来避免取和缓存没必要的数据.或者一个代理服务器连接有很快的下流,很慢的上流,同样的也要控制以多大的流速传输数据,从而匹配上流的速度,从而控制资源的使用.
-
服务端推送
-
头部压缩
- 每个请求都需单独建立连接(keep-alive能解决部分问题单不能交叉推送)
- 每个请求和响应都需要完整的头信息
- 数据未加密
- 多路复用
- 压缩头信息
- 请求划分优先级
- 支持服务器端主动推送