kkxiaojun / blog Goto Github PK
View Code? Open in Web Editor NEW学习笔记
学习笔记
特点
栈是一种后进先出(LIFO)的数据结构
应用
特点
栈是一种先进先出(FIFO)的数据结构
应用
解决数组长度固定的不足
链表:按线性次序排列的一组数据节点。单链表的末节点特征是next为null
除了有next引用,还有prev引用
一种非线性数据结构。作为一种抽象数据类型,树可以用来对一组元素进行层次化的组织。
二叉树
每个节点均不超过2度的有序树称为二叉树。
满二叉树
若二叉树 T 中所有叶子的深度完全相同,则称之为满二叉树
完全二叉树
若在一棵满二叉树中,从最右侧起将相邻的若干匹叶子节点摘除掉,则得到的二叉树称作完全二叉树
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:按树的深度进行遍历
深度优先遍历:前序遍历、中序遍历、后序遍历
广度优先遍历:广度优先遍历会先访问离根节点最近的节点
小顶堆和大顶堆
满足一下两条性质的二叉树:
void expression
均为undefined
<script>
元素定义了6个属性
async: 可选。表示应该立即下载的脚本,但不应妨碍页面中的其他操作。只对外部脚本文件有效
charset: 可选。表示通过src属性指定
defer: 可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效(更常用的做法是把脚本放到页面底部)
src: 可选。表示包含要执行代码的外部文件
type:可选。表示编写代码使用的脚本语言的内同类型
Object的每个实例都有下列属性和方法:
执行环境:定义了变量或函数有权访问的其它数据
理解:
没有块级作用域
if (true) {
var color = 'blue';
}
console.log(color); // blue
JavaScript具有自动垃圾收集机制,原理:找到那些不再使用的变量,然后释放内存
策略
检测数组
function isArray (arr) {
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
} else {
return Object.prototype.toString.call(arr) === '[Object Array]';
}
}
转换方法
方法 | 用法 |
---|---|
toLocalString() | 返回字符串形式,每次都调用toLocalString |
toString() | 返回字符串形式 |
valueOf() | 返回字符串形式 |
栈和队列方法
方法类型 | 方法 |
---|---|
栈方法(LIFO) | push()、pop() |
队列方法(FIFO) | unshift()、shift() |
重排序
reverse()
反序
sort()
升序,调用每个数组项的toString()方法,比较得到的字符串
// 解决 10,5这样的大小问题
arr.sort(
function compoare(value1, value2) {
return value2 - value1;
}
)
操作方法
方法 | 语法 | 是否改变原数组 |
---|---|---|
concat() | arrayObject.concat(arrayX,arrayX,......,arrayX) | 否,返回新数组 |
slice() | arrayObject.slice(start,end) | 否,返回新数组 |
splice() | array.splice(index,howmany,item1,.....,itemX) | 是 |
位置方法
方法 | 语法 |
---|---|
array.indexOf(item, start) | 从数组的开头开始查找,不支持ie8 |
lastIndexOf(item, start) | 从数组的末尾开始查找 |
迭代方法(ie9)
方法 | 语法 | 返回值 |
---|---|---|
every() | arr.every(callback[, thisArg]) | true,false |
filter() | arr.filter(callback(element[, index[, array]])[, thisArg]) | 返回true的项 |
forEach() | array.forEach(callback(currentValue, index, array){ //do something }, this) | 无 |
map() | var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg])。方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 | 新数组 |
some() | arr.some(callback[, thisArg]) | true,false |
缩小方法
方法 | 语法 |
---|---|
reduce() | arr.reduce(function(prev, cur, index, array){}) |
reduceRight() | arr.reduceRight(function(prev, cur, index, array){}) |
Date.parse()
,Date.UTC()
不同宿主在如何解析日期字符串上仍存在许多差异
没有重载
后面的会覆盖前面的函数
arguments
,this
length
,表示函数希望接受的命名参数的个数prototype
apply()
。在特定的作用域中调用函数call()
。在特定的作用域中调用函数。类数组转化:Array.prototype.slice.call(arguments)
Boolean,Number,String
不依赖宿主环境的对象,这些对象在ECMAScript执行之前就已经存在(不必显示地实例化)
Global
,Math
数据属性:
模式 | 解释 | 优点 | 缺点 |
---|---|---|---|
工厂模式 | 这种模式抽象了创建具体对象的过程 | 解决了创建多个相似对象的问题 | 没有解决对象识别的问题 |
构造函数模式 | 使用new操作符创建对象 | 可以将它的实例标记为特定的类型 | 每个方法都要在每个实例上创建一遍 |
原型模式 | 用prototype属性,创建实例的共享方法和属性 | 共享方法和属性 | 每个实例一般要有属于自己的全部属性 |
组合构造函数模式和原型模式 | 构造函数和原型模式一起使用 | 两种模式的优点 | 无 |
动态原型模式 | 根据检验方法是否有效来决定是否需要初始化原型 | 避免大量相同的添加操作 | 无 |
寄生构造函数模式 | 创建一个函数,返回新创建的对象 | 解决特殊需求,比如说不改prototype,但是要新增额外方法 | 无 |
稳妥构造函数模式 | 适合在安全的环境中,防止数据被其他应用程序改变时使用 | 安全性 | 无 |
实现继承,主要用原型链(prototype)实现
确定原型和实例的关系
instanceof
,isPrototypeOf
描述 | 属性 |
---|---|
窗口位置 | window.screenLeft/window.screenX,window.screenTop/window.screenY |
窗口大小 | window.innerWidth/innerHeight/outerHeight/outerWidth |
导航和打开窗口 | window.open() |
对象 | 属性 |
---|---|
location | hash,host,host,name,href,pathname,port,protocol,search |
navigator | |
screen | |
history | (方法)go(),back().forward(),length |
每个节点都有一个nodeType属性用于表明节点的类型
nodeName和nodeValue属性
操作节点
appendChild(),insertBefore(),removeChild()
文档信息
document.title
,document.URL
,document.domain
,document.referrer
查找元素
getElementById()
,getElementsByTagName()
,getElementsByName()
,getElementByClassName()
选择符API
querySelector()
。返回第一个元素querySelectorAll()
。返回所有scrollIntoView()
事件冒泡
IE的事件流叫做事件冒泡。即事件开始时由最具体的元素(文档中嵌套深的节点)接受,后逐级向上传播到不具体的节点。
let eventUtil = {
addHandler: (element, type, handler) => {
// dom2级事件处理程序(ie9)
if (element.addEventListener) {
// false表示在冒泡阶段调用事件处理程序
element.addEventListener(type, handler, false);
// dom0级事件处理程序(ie)
} else if (element.attachEvent) {
element.attachEvent('on' + type, handler);
// 其它事件
} else {
element['on' + type] = handler;
}
},
removeHandler: (element, type, handler) => {
// dom2级事件处理程序(ie9)
if (element.addEventListener) {
// false表示在冒泡阶段调用事件处理程序
element.removeEventListener(type, handler, false);
// dom0级事件处理程序(ie)
} else if (element.attachEvent) {
// ie事件处理程序
element.detachEvent('on' + type, handler);
// 其它事件
} else {
element['on' + type] = null;
}
},
stopPropagation: e => {
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = false;
},
preventDefault: e => {
e.preventDefault ? e.preventDefault() : e.returnValue = false;
},
getEvent: e => {
return e || window.event;
},
getTarget: e => {
return e.target || e.srcElement;
}
};
事件捕获
与事件冒泡相反
手写冒泡
<ul class="parent">
<li class="son1">son1</li>
<li class="son2">son2</li>
</ul>
let parent = document.querySelector('.parent');
eventUtil.addHandler(parent, 'click', e => {
console.log(e.target.innerText)
})
基础
发送异步请求
创建过程
创建XMLHttpRequest对象,也就是创建一个异步调用对象.
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息(xhr.open(method, url, true/false)).
设置响应HTTP请求状态变化的函数.(onreadystatechange,readyState==4,status==200)
发送HTTP请求.(xhr.send(method, url, true/false))
获取异步调用返回的数据.
使用JavaScript和DOM实现局部刷新.
method
var xhr;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xhr=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onreadystatechange=function()
{
if (xhr.readyState==4 && xhr.status==200)
{
document.getElementById("txtHint").innerHTML=xhr.responseText;
}
}
xhr.open("GET","gethint.asp?q="+str,true);
if(method === 'post') {
xhr.send(data);
} else {
xhr.send();
}
}
AJAX的工作原理
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。 Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
ajax优缺点
优点:无刷新更新数据,异步与服务器通信,前后端负载均衡
缺点:
Promise
是ES6新增的语法,解决了callback hell
的问题。
可以把Promise看成是一个状态机。初始状态是pending,通过resolve or reject 可以将状态转化为fulfilled or rejected.状态一旦改变就不能再次改变。
then
函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending
状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then
调用就失去意义了。
Promise实现类似Axios
// 用promise实现类似axios的功能
function p(method, url, data) {
return new Promise((resolve, reject) => {
let xhrObj;
if (window.XMLHttpRequest) {
xhrObj = new XMLHttpRequest();
} else {
xhrObj = new ActiveObject("Microsoft.XMLHTTP");
}
xhrObj.open(method, url, true);
if (method === 'post') {
xhrObj.send(data);
}
xhrObj.send();
xhrObj.onreadystatechange = () => {
if (xhrObj.readyState === 400) {
let res = xhrObj.response;
if (xhrObj.status === 200) {
return resolve(JSON.parse(res));
} else {
return reject(xhrObj);
}
}
}
})
}
promise
// 三种状态
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// promise 接收一个函数参数,该函数会立即执行
function MyPromise(fn) {
let _this = this;
_this.currentState = PENDING;
_this.value = undefined;
// 用于保存 then 中的回调,只有当 promise
// 状态为 pending 时才会缓存,并且每个实例至多缓存一个
_this.resolvedCallbacks = [];
_this.rejectedCallbacks = [];
_this.resolve = function (value) {
if (value instanceof MyPromise) {
// 如果 value 是个 Promise,递归执行
return value.then(_this.resolve, _this.reject)
}
setTimeout(() => { // 异步执行,保证执行顺序
if (_this.currentState === PENDING) {
_this.currentState = RESOLVED;
_this.value = value;
_this.resolvedCallbacks.forEach(cb => cb());
}
})
};
_this.reject = function (reason) {
setTimeout(() => { // 异步执行,保证执行顺序
if (_this.currentState === PENDING) {
_this.currentState = REJECTED;
_this.value = reason;
_this.rejectedCallbacks.forEach(cb => cb());
}
})
}
// 用于解决以下问题
// new Promise(() => throw Error('error))
try {
fn(_this.resolve, _this.reject);
} catch (e) {
_this.reject(e);
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
var self = this;
// 规范 2.2.7,then 必须返回一个新的 promise
var promise2;
// 规范 2.2.onResolved 和 onRejected 都为可选参数
// 如果类型不是函数需要忽略,同时也实现了透传
// Promise.resolve(4).then().then((value) => console.log(value))
onResolved = typeof onResolved === 'function' ? onResolved : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => throw r;
if (self.currentState === RESOLVED) {
return (promise2 = new MyPromise(function (resolve, reject) {
// 规范 2.2.4,保证 onFulfilled,onRjected 异步执行
// 所以用了 setTimeout 包裹下
setTimeout(function () {
try {
var x = onResolved(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
});
}));
}
if (self.currentState === REJECTED) {
return (promise2 = new MyPromise(function (resolve, reject) {
setTimeout(function () {
// 异步执行onRejected
try {
var x = onRejected(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
});
}));
}
if (self.currentState === PENDING) {
return (promise2 = new MyPromise(function (resolve, reject) {
self.resolvedCallbacks.push(function () {
// 考虑到可能会有报错,所以使用 try/catch 包裹
try {
var x = onResolved(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (r) {
reject(r);
}
});
self.rejectedCallbacks.push(function () {
try {
var x = onRejected(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (r) {
reject(r);
}
});
}));
}
};
// 规范 2.3
function resolutionProcedure(promise2, x, resolve, reject) {
// 规范 2.3.1,x 不能和 promise2 相同,避免循环引用
if (promise2 === x) {
return reject(new TypeError("Error"));
}
// 规范 2.3.2
// 如果 x 为 Promise,状态为 pending 需要继续等待否则执行
if (x instanceof MyPromise) {
if (x.currentState === PENDING) {
x.then(function (value) {
// 再次调用该函数是为了确认 x resolve 的
// 参数是什么类型,如果是基本类型就再次 resolve
// 把值传给下个 then
resolutionProcedure(promise2, value, resolve, reject);
}, reject);
} else {
x.then(resolve, reject);
}
return;
}
// 规范 2.3.3.3.3
// reject 或者 resolve 其中一个执行过得话,忽略其他的
let called = false;
// 规范 2.3.3,判断 x 是否为对象或者函数
if (x !== null && (typeof x === "object" || typeof x === "function")) {
// 规范 2.3.3.2,如果不能取出 then,就 reject
try {
// 规范 2.3.3.1
let then = x.then;
// 如果 then 是函数,调用 x.then
if (typeof then === "function") {
// 规范 2.3.3.3
then.call(
x,
y => {
if (called) return;
called = true;
// 规范 2.3.3.3.1
resolutionProcedure(promise2, y, resolve, reject);
},
e => {
if (called) return;
called = true;
reject(e);
}
);
} else {
// 规范 2.3.3.4
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// 规范 2.3.4,x 为基本类型
resolve(x);
}
}
// generator/yield
var fetch = require('node-fetch');
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
// 无限迭代器
function* idMaker(){
let index = 0;
while(true)
yield index++;
}
let gen = idMaker(); // "Generator { }"
console.log(gen.next().value);
// 0
console.log(gen.next().value);
// 1
console.log(gen.next().value);
// 2
// ...
// async/await(它就是 Generator 函数的语法糖)
async function Name() {
await fetch(ulr)
}
优点
特点
fetch(url, {credentials: 'include'})
实例
if (window.fetch && method == 'fetch') {
let requestConfig = {
credentials: 'include', // Fetch 请求默认是不带 cookie 的,需要设置 `fetch(url, {credentials: 'include'})`
method: type,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
mode: "cors",
cache: "force-cache"
}
if (type == 'POST') {
// 发送post请求需要设置body属性传数据
Object.defineProperty(requestConfig, 'body', {
value: JSON.stringify(data)
})
}
try {
const response = await fetch(url, requestConfig); // async function, return Promise
const responseJson = await response.json(); // parses response to JSON
return responseJson
} catch (error) {
throw new Error(error)
}
}
超文本传输协议(Hypertext Transfer Protocol),是应用层
协议。
面向报文
UDP 是一个面向报文(报文可以理解为一段段的数据)的协议。意思就是 UDP 只是报文的搬运工,不会对报文进行任何拆分和拼接操作。
具体来说:
在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
不可靠性
高效性
因为 UDP 没有 TCP 那么复杂,需要保证数据不丢失且有序到达。所以 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的。
传输方式
UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能
TCP的头部比UDP复杂很多,对于 TCP(Transmission Control Protocol) 头部来说,以下几个字段是很重要的
头部 | 详情 |
---|---|
Sequence number | 这个序号保证了 TCP 传输的报文都是有序的,对端可以通过序号顺序的拼接报文 |
Acknowledgement Number | 这个序号表示数据接收端期望接收的下一个字节的编号是多少,同时也表示上一个序号的数据已经收到 |
Window Size | 窗口大小,表示还能接收多少字节的数据,用于流量控制标识符 |
URG=1 | 该字段为一表示本数据报的数据部分包含紧急信息,是一个高优先级数据报文,此时紧急指针有效。紧急数据一定位于当前数据包数据部分的最前面,紧急指针标明了紧急数据的尾部。 |
ACK=1 | 该字段为一表示确认号字段有效。此外,TCP 还规定在连接建立后传送的所有报文段都必须把 ACK 置为一。 |
PSH=1 | 该字段为一表示接收端应该立即将数据 push 给应用层,而不是等到缓冲区满后再提交。 |
RST=1 | 该字段为一表示当前 TCP 连接出现严重问题,可能需要重新建立 TCP 连接,也可以用于拒绝非法的报文段和拒绝连接请求。 |
SYN=1 | 当SYN=1,ACK=0时,表示当前报文段是一个连接请求报文。当SYN=1,ACK=1时,表示当前报文段是一个同意建立连接的应答报文。 |
FIN=1 | 该字段为一表示此报文段是一个释放连接的请求报文。 |
HTTP Headers
让协议扩展变的很容易。HTTP Cookies
就可以解决这个问题。注意,HTTP本质是无状态的,使用Cookies可以创建有状态的会话。连接(一般指TCP连接)是由传输层控制的
HTTP/1.0
HTTP/1.0为每一个响应/请求都打开一个TCP连接,缺点: 打开一个TCP连接需要多次往返消息传递(三次握手),速度慢。
HTTP/1.1
HTTP/1.1引入了持久连接的概念,底层的TCP连接可以通过Connection(keep-alive)头部来被部分控制
为了更好的适合HTTP,设计一种更好传输协议的进程一直在进行。
Google就研发了一种以UDP为基础,能提供更可靠更高效的传输协议QUIC。
HTTP长连接和短连接这个说法是有有问题的。应该是TCP(传输层协议)连接。
TCP长连接
tcp建立一次连接后不关闭(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间)。web中的js,css,html都是可以缓存的
TCP短连接
tcp每次建立连接后,请求完成,连接关闭。下次传输连接需要再次建立。
优点与缺点
请求报文
GET/test/xx.txt HTTP/ 1.1 // 起始行
Accept: text/* // 首部
Host: d.w.org // 首部
响应报文
HTTP/1.1 200 OK // 起始行
Content-type: text/plain // 首部
Content-length: 15 // 首部
hi ni hao // 主体
通用字段 | 作用 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 浏览器想要优先使用的连接类型,比如 keep-alive |
Date | 创建报文时间 |
Pragma | 报文指令 |
Via | |
Transfer-Encoding | 传输编码方式 |
Upgrade | 要求客户端升级协议 |
Warning | 在内容中可能存在错误 |
请求字段 | 作用 |
---|---|
Accept | 能正确接收的媒体类型 |
Accept-Charset | 能正确接收的字符集 |
Accept-Encoding | 能正确接收的编码格式列表 |
Accept-Language | 能正确接收的语言列表 |
Expect | 期待服务端的指定行为 |
From | 请求方邮箱地址 |
Host | 服务器的域名 |
If-Match | 两端资源标记比较 |
If-Modified-Since | 本地资源未修改返回 304(比较时间) |
If-None-Match | 本地资源未修改返回 304(比较标记) |
User-Agent | 客户端信息 |
Max-Forwards | 限制可被代理及网关转发的次数 |
Proxy-Authorization | 向代理服务器发送验证信息 |
Range | 请求某个内容的一部分 |
Referer | 表示浏览器所访问的前一个页面 |
TE | 传输编码方式 |
响应字段 | 作用 |
---|---|
Accept-Ranges | 是否支持某些种类的范围 |
Age | 资源在代理缓存中存在的时间 |
ETag | 资源标识 |
Location | 客户端重定向到某个 URL |
Proxy-Authenticate | 向代理服务器发送验证信息 |
Server | 服务器名字 |
WWW-Authenticate | 获取资源需要的验证信息 |
实体字段 | 作用 |
---|---|
Allow | 资源的正确请求方式 |
Content-Encoding | 内容的编码格式 |
Content-Language | 内容使用的语言 |
Content-Length | request body 长度 |
Content-Location | 返回数据的备用地址 |
Content-MD5 | Base64加密格式的内容 MD5检验值 |
Content-Range | 内容的位置范围 |
Content-Type | 内容的媒体类型 |
Expires | 内容的过期时间 |
Last_modified | 内容的最后修改时间 |
类别
状态码 | 类别 | 原因 |
---|---|---|
1XX | Informational(信息性状态码) | 接收的请求正在处理 |
2XX | Success | 请求正常处理完毕 |
3XX | Redirectin | 需要进行附加操以完成请求 |
4XX | Client Error(客户端错误) | 服务器无法处理请求 |
5XX | Server Error | 服务器请求出错 |
状态码详情
表示目前为止一切正常, 客户端应该继续请求, 如果已完成请求则忽略
200 表明请求已经成功. 默认情况下成功的请求将会被缓存。不同请求方式对于请求成功的意义如下:
201 是一个代表成功的应答状态码,表示请求已经被成功处理,并且创建了新的资源。新的资源在应答返回之前已经被创建。同时新增的资源会在应答消息体中返回,其地址或者是原始请求的路径,或者是 Location 首部的值。
300 是一个用来表示重定向的响应状态码,表示该请求拥有多种可能的响应。用户代理或者用户自身应该从中选择一个。
301 永久重定向 说明请求的资源已经被移动到了由 Location 头部指定的url上,是固定的不会再改变。搜索引擎会根据该响应修正。
302 重定向状态码表明请求的资源被暂时的移动到了由Location 头部指定的 URL 上。浏览器会重定向到这个URL, 但是搜索引擎不会对该资源的链接进行更新
303 重定向状态码,通常作为 PUT 或 POST 操作的返回结果,它表示重定向链接指向的不是新上传的资源,而是另外一个页面,比如消息确认页面或上传进度页面。而请求重定向页面的方法要总是使用 GET。
304 浏览器已缓存,不用再请求服务器资源
307 临时重定向)是表示重定向的响应状态码,说明请求的资源暂时地被移动到 Location 首部所指向的 URL 上。
状态码 307 与 302 之间的唯一区别在于,当发送重定向请求的时候,307 状态码可以确保请求方法和消息主体不会发生变化。当响应状态码为 302 的时候,一些旧有的用户代理会错误地将请求方法转换为 GET:使用非 GET 请求方法而返回 302 状态码,Web 应用的运行状况是不可预测的;而返回 307 状态码时则是可预测的。对于 GET 请求来说,两种情况没有区别。
在重定向过程中,请求方法和消息主体不会发生改变,然而在返回 301 状态码的情况下,请求方法有时候会被客户端错误地修改为 GET 方法。
HTTPS 还是通过了 HTTP 来传输信息,但是信息通过 TLS (传输层安全协议,Transport Layer Security)协议进行了加密。
TLS
TLS协议位于传输层之上,应用层之下。首次进行TLS协议传输时需要两个RTT(同一个封包来回时间(Round-Trip Time))。接下来可以通过Session Resumption(会话复用) 减少到一个 RTT。
在 TLS 中使用了两种加密技术,分别为:对称加密和非对称加密
对称加密。对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。
非对称加密。有公钥私钥之分,公钥所有人都可以知道,可以将数据用公钥加密,但是将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。
TLS 握手过程如下图
TCP连接建立(3次握手)
在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。
TCP连接释放(4次挥手)
A、B端都处于连接已建立的状态。
HTTP 2.0 相比于 HTTP 1.X,可以说是大幅度提高了 web 的性能。
在 HTTP 1.X 中,为了性能考虑,我们会引入雪碧图、将小图内联、使用多个域名等等的方式。这一切都是因为浏览器限制了同一个域名下的请求数量,当页面中需要请求很多资源的时候,队头阻塞(Head of line blocking)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。
HTTP/2是二进制协议而不是文本协议。
HTTP 2.0 中所有加强性能的核心点在于此。在之前的 HTTP 版本中,我们是通过文本的方式传输数据。在 HTTP 2.0 中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。
在HTTP2.0中有两个非常重要的概念:帧(frame)和流(stream),帧代表着最小的数据单位,流由帧组成。
多路复用
就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。
在 HTTP 1.X 中,我们使用文本的形式传输 header,在 header 携带 cookie 的情况下,可能每次都需要重复传输几百到几千的字节。
在 HTTP 2.0 中,使用了 HPACK 压缩格式对传输的 header 进行编码,减少了 header 的大小。并在两端维护了索引表,用于记录出现过的 header ,后面在传输过程中就可以传输已经记录过的 header 的键名,对端收到数据后就可以通过键名找到对应的值
在 HTTP 2.0 中,服务端可以在客户端某个请求后,主动推送其他资源。
可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用 prefetch
这是一个谷歌出品的基于 UDP 实现的同为传输层的协议,目标很远大,希望替代 TCP 协议。
DNS 的作用就是通过域名查询到具体的 IP。
因为 IP 存在数字和英文的组合(IPv6),很不利于人类记忆,所以就出现了域名。你可以把域名看成是某个 IP 的别名,DNS 就是去查询这个别名的真正名称是什么。
在 TCP 握手之前就已经进行了 DNS 查询,这个查询是操作系统自己做的。当你在浏览器中想访问 www.google.com 时,会进行一下操作:
以上介绍的是 DNS 迭代查询,还有种是递归查询,区别就是前者是由客户端去做请求,后者是由系统配置的 DNS 服务器做请求,得到结果后将数据返回给客户端。
PS:DNS 是基于 UDP 做的查询。
这是一个很经典的面试题,在这题中可以将本文讲得内容都串联起来。
在“标准模式”(Standards Mode) 页面按照 HTML 与 CSS 的定义渲染,而在“怪异模式”(Quirks Mode)就是浏览器为了兼容很早之前针对旧版本浏览器设计、并未严格遵循 W3C 标准的网页而产生的一种页面渲染模式。
浏览器基于页面中文件类型描述的存在以决定采用哪种渲染模式;如果存在一个完整的DOCTYPE则浏览器将会采用标准模式,而如果它缺失则浏览器将会采用怪异模式。
IE:trident内核
Firefox:gecko(壁虎)内核
safari:webkit内核,WebKit的优势在于高效稳定,兼容性好,且源码结构清晰,易于维护。
Chrome:Blink(基于webkit,google与opera software共同开发)
opera:以前是presto内核,现在改用google chrome的Blink内核
描述内容的含义
可替换元素(replaced element)
img, object, iframe, video 等
,展现效果不是由 CSS 来控制的。这些元素是一种外部对象,它们外观的渲染,是独立于 CSS 的。(浏览器根据元素的标签和属性,来决定元素的具体显示内容。)
非替换元素
大多数标签属于非替换元素,这部分标签把标签里的内容直接告诉浏览器显示出来
讨论margin-top和margin-bottom对行内元素是否起作用,则要对行内替换元素和行内非替换元素分别讨论。
行内替换元素:(img)有影响
行内非替换元素:无影响
w3c标准盒模型
属性width,height只包含内容content,不包含border和padding。
ie盒模型
width = content + padding * 2 + border * 2
box-sizing
控制元素盒模型的解析方式
1、display:none 元素不再占用空间。
2、visibility: hidden 使元素在网页上不可见,但仍占用空间。
块格式化上下文(block formatting context) 是页面上的一个独立的渲染区域,容器里面的子元素不会在布局上影响到外面的元素。它是决定块盒子的布局及浮动元素相互影响的一个因素。
触发条件
特性
用处
原理:清除浮动,实际上是清除父元素的高度塌陷。因为子元素脱离了父元素的文档流,所以,父元素失去了高度,导致了塌陷。要解决这个问题,就是让父元素具有高度。
浮动元素的特性: 在正常布局中位于该浮动元素之下的内容,此时会围绕着浮动元素,填满其右侧的空间。浮动到右侧的元素,其他内容将从左侧环绕它,浮动元素影响的不仅是自己,它会影响周围的元素对其进行环绕。
float仍会占据其位置,position:absolute不占用页面空间 会有重叠问题
用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,以及新的requestAnimationFrame
<div id="demo" style="position:absolute; width:100px; height:100px; background:#ccc; left:0; top:0;"></div>
<script>
var demo = document.getElementById('demo');
function rander(){
demo.style.left = parseInt(demo.style.left) + 1 + 'px'; //每一帧向右移动1px
}
requestAnimationFrame(function(){
rander();
//当超过300px后才停止
if(parseInt(demo.style.left)<=300) requestAnimationFrame(arguments.callee);
});
</script>
css3使用
@Keyframes 结合animation
transition:property duration timing-function delay
两列布局
三列布局
弹性布局flex
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
CSS Grid
px:绝对单位,页面按精确像素展示
em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认字体是16px),整个页面内1em不是一个固定的值。
rem:相对单位,可理解为”root em”, 相对根节点html的字体大小来计算,CSS3新加属性,chrome/firefox/IE9+支持。
vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%。
vh:viewpoint height,视窗高度,1vh等于视窗高度的1%。
vmin:vw和vh中较小的那个。
vmax:vw和vh中较大的那个。
行内布局
line-height + text-align
vertical-align + text-align
块布局
position absolute + margin auto
position absolute + negative margin
position absolute + translate(-50%, -50%)
1.flex
#wrap{
display:flex;
justify-content:center;
align-items:center;
}
2.tabel
.parent {
text-align: center;//水平居中
display: table-cell;
vertical-align: middle;//垂直居中
}
.child {
display: inline-block;//防止块级元素宽度独占一行,内联元素可不设置
}
3.absolute+transform 水平垂直居中
<div class="parent">
<div class="child">Demo</div>
</div>
<style>
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
4.webkit-box
//对父级元素设置
position: relative;
display: -webkit-box;
-webkit-box-align: center;
-webkit-box-pack: center;
要使用的工具函数
function isArray(arr){
if (typeof Array.isArray === 'function'){
return Array.isArray(arr);
} else{
return Object.prototype.toString.call(arr) === '[object Array]';
}
}
原理
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成
步骤
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码实现
// 对还未排序的全部数,自左向右对相邻的两个数进行对比,较大的数往下沉,较小的数往上冒泡
function bubbleSort(arr) {
if (!isArray(arr) || !arr.length) {
return;
}
let temp = null, len = arr.length;
for (let i = 0; i < len - 1; i++) { // 每循环一次,就确定一个相对最大元素
for (let j = 1; j < len -i; j++) { // 内层:有i个已经排好序,剩下:len - 1 -i 个需要排序
if (arr[j-1] > arr [j]) {
temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
// 改进:对于后面已经排好序的数进行记录,下一次不再进行比较
function bubbleSort2(arr) {
if (!isArray(arr) || !arr.length) {
return;
}
let temp = null, pos = arr.length, end = arr.length;
for (let i = 0; i < arr.length; i++) {
end = pos;
for (let j = 1; j < end; j++) {
if (arr[j-1] > arr [j]) {
temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
pos = j;
}
}
}
return arr;
}
// 改进:从左右两边,正反向分别冒泡
function bubbleSort3(arr) {
var low = 0;
var high = arr.length - 1; //设置变量的初始值
var tmp, j;
console.time('2.改进后冒泡排序耗时');
while (low < high) {
for (j = low; j < high; ++j) //正向冒泡,找到最大者
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
--high; //修改high值, 前移一位
for (j = high; j > low; --j) //反向冒泡,找到最小者
if (arr[j] < arr[j - 1]) {
tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
}
++low; //修改low值,后移一位
}
return arr;
}
原理
简单选择排序的基本**非常简单,即:第一趟,从 n 个元素中找出关键字最小的元素与第一个元素交换;第二趟,在从第二个元素开始的 n-1 个元素中再选出关键字最小的元素与第二个元素交换;如此,第 k 趟,则从第 k 个元素开始的 n-k+1 个元素中选出关键字最小的元素与第 k 个元素交换,直到整个序列按关键字有序。
步骤
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
代码实现
function selectionSort(arr) {
if (!isArray(arr) || !arr.length) {
return;
}
let minItemIndex = 0, temp = null, len = arr.length;
for (let i = 0; i < len; i++) {
minItemIndex = i;
for (let j = i + 1; j < len; j++) {
if (arr[minItemIndex] > arr[j]) {
minItemIndex = j;
}
}
if (i !== minItemIndex) {
temp = arr[minItemIndex];
arr[minItemIndex] = arr[i];
arr[i] = temp;
}
}
return arr;
}
原理
原理是通过构建youxuxulie,对于未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入
步骤
代码实现
// 原理是通过构建youxuxulie,对于未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入
function insertionSort(arr) {
if (!isArray(arr) || !arr.length) {
return;
}
let current = null, preItemIndex = null, len = arr.length;
for (let i = 1; i< len; i++) {
preItemIndex = i - 1;
current = arr[i];
while (preItemIndex >= 0 && current < arr[preItemIndex]) {
arr[preItemIndex + 1] = arr[preItemIndex];
preItemIndex--;
}
// 满足条件,交换
if (current !== arr[preItemIndex+1]) {
arr[preItemIndex + 1] = current;
}
}
return arr;
}
原理
希尔排序是基于插入排序的以下两点性质而提出的改进方法:
希尔排序基本**是:先将整个待排序序列分割成若干个子序列分别进行直接插入排序,待整个序列中"基本有序"时,再对全体记录进行直接插入排序。
步骤
代码实现
function shellSort(arr) {
var len = arr.length,
temp,
gap = 1;
while(gap < len/3) { //动态定义间隔序列
gap =gap*3+1;
}
for (gap; gap > 0; gap = Math.floor(gap/3)) {
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
arr[j+gap] = arr[j];
}
arr[j+gap] = temp;
}
}
return arr;
}
原理
归并排序是另一类不同的排序方法,这种方法是运用分治法解决问题的典型范例。归并排序的基本**是基于合并操作,即合并两个已经有序的序列是容易的,不论这两个序列是顺序存储还是链式存储,合并操作都可以Ο(m+n)时间内完成(假设两个有序表的长度分别为 m 和 n)。
步骤
为此,由分治法的一般设计步骤得到归并排序的过程为:
代码实现
function mergeSort(arr) { // 采用自上而下的递归方法
var len = arr.length;
if(len < 2) {
return arr;
}
var middle = Math.floor(len / 2),
left = arr.slice(0, middle),
right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right)
{
var result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
原理
快速排序是将分治法运用到排序问题中的一个典型例子,快速排序的基本**是:通过一个枢轴(pivot)元素将 n 个元素的序列分为左、右两个子序列 Ll 和 Lr,其中子序列 Ll中的元素均比枢轴元素小,而子序列 Lr 中的元素均比枢轴元素大,然后对左、右子序列分别进行快速排序,在将左、右子序列排好序后,则整个序列有序,而对左右子序列的排序过程直到子序列中只包含一个元素时结束,此时左、右子序列由于只包含一个元素则自然有序。
步骤
用分治法的三个步骤来描述快速排序的过程如下:
划分步骤:通过枢轴元素 x 将序列一分为二, 且左子序列的元素均小于 x,右子
序列的元素均大于 x;
治理步骤:递归的对左、右子序列排序;
组合步骤:无
代码实现
// 输入:数据元素数组 arr,划分序列区间[low..high]
// 输出:将序列划分为两个子序列并返回枢轴元素的位置
function partition(arr, low, high) {
let pivot = arr[low];
while (low < high) {
while (low < high && arr[high] >= pivot) {
high--;
}
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) {
low++;
}
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
function quickSort(arr, low, high) {
if (low < high) {
let pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
return arr;
}
原理
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:
大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;
堆排序的平均时间复杂度为 Ο(nlogn)。
步骤
图示
将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
return this
if (Object.a == null) {} // 除了这个其它均用===
git remote add upstream 开源项目地址
git checkout -b dev
git status
git add .
git commit -m
git push origin branch
git fetch upstream
git rebase upstream/master
git push origin master
题目->考点->知识再到题目
onload
事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了。DOMContentLoaded
事件触发时,仅当DOM加载完成,不包括样式表,图片,flash类型
值类型。栈内存(栈是为执行线程留出的内存空间,栈附属于线程,因此当线程结束时栈被回收)
引用类型(对象、数组、函数)。堆内存(堆(heap)是为动态分配预留的内存空间,堆通常通过运行时在应用程序启动时被分配,当应用程序(进程)退出时被回收)。
typeof。只能识别值类型和函数,不能识别引用类型
typeof undefined // undefined
typeof 123 // number
typeof 'rty' // string
typeof true // boolean
typeof null // object
typeof {} // object
typeof [] // object
typeof console.log // function
计算-强制类型转换
10个函数类型( String,Number,Boolean,Array,Function,Date,RegExp,Error,Object,Event )函数类型 有 __proto__
和 prototype
属性。
2个对象类型(Math,JSON) 对象类型只有__proto__
属性。
构造函数
return this
function Food(){
this.cai = cai;
// return this // 默认返回
}
构造函数-扩展
var a = {} 其实是var a = new Object()的语法糖
var a = [] 其实是var a = new Object()的语法糖
function Foo() {} 其实是var Foo = new Function()
基本概念
原型:所有的函数才有的prototype
属性,prototype
属性值是一个普通的对象。
原型链:JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
对象实例和它的构造器之间建立一个链接(它是__proto__
属性,是从构造函数的prototype
属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。
JavaScript是动态的没有class实现。在ES6中引入了class
关键字,但是是语法糖。
谈到继承时,JavaScript只有一种结构:对象。每个object都有一个私有属性(__proto__
)指向它的原型对象(prototype)。该原型对象也有一个自己的(__proto__
),层层往上直到一个对象的原型对象为null
。根据定义,null
没有原型。
__proto__
(隐式原型)属性,属性值是一个普通的对象。prototype
(原型)属性,属性值也是一个普通的对象。里边有一个constructor
,指向函数自身。__proto__
(隐式原型)属性值指向它构造函数的prototype
(原型)属性值。obj.__proto__ === Object.prototype // true
__proto__
(即构造函数的prototype)中寻找。循环对象自身的属性
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
// 高级浏览器已经在for in中屏蔽了来自原型链的属性
}
}
例子
// 构造函数
function Foo(name, age) {
this.name = name;
this.age = age;
}
Foo.prototype.alertName = function () {
alert(this.name)
}
// 创建示例
var f = new Foo('kk', 90);
f.printName = function () {
console.log(this.name)
}
// 测试
f.printName()
f.alertName()
f.toString() // 要去 f.__proto.__proto__找
图示
使用instanceof判断一个函数是否是一个变量的构造函数
__proto__
一层层往上,能否对应到Foo.prototype__proto__
不是标准属性,并且该属性不是标准属性,不可以用在编程中,用于浏览器内部
如何准确判断一个变量是数组
// arr instanceof Array
// 判断数组
function isArray(arr) {
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
} else {
return Object.prototype.toString.call(arr) === '[object Array]';
}
}
写一个原型链继承的例子
// 形象例子
function Animal() {
this.eat = function() {console.log('animal eat');}
}
function Cat(){
this.mill = function() {console.log('cat mill');}
}
// 原型链继承
Cat.prototype = new Animal();
var bosimao = new Cat();
// 接近实战的例子
function Ele(id) {
this.elem = document.getElementById(id)
}
Ele.prototype.html = function(val) {
var elem = this.elem
if (val) {
elem.innerHTML = val
return this //链式调用
} else {
return elem.innerHTML
}
}
Ele.ptototype.on = function(type, handle) {
var elem = this.elem
elem.addEventListner(type, handle)
return this // 链式调用
}
var divc = new Ele('id');
divc.on('click', function(e){
console.log('i am click')
})
描述new一个对象的例子
1、创建一个空对象,并且this变量引用该对象,同时继承了该函数的原型(实例对象通过__proto__属性指向原型对象;obj.proto = Base.prototype;) 2、属性和方法被加入到 this 引用的对象中。
1. 创建一个新对象
2. this指向这个新对象
3. 执行代码对this赋值
4. 返回this
function Food(){
this.cai = cai;
// return this // 默认有这一行
}
详解
function myNew(_constructor, arg) {
var obj = {};
obj._proto_ = _constructor.prototype;
//把该对象的原型指向构造函数的原型对象,就建立起原型了:obj->Animal.prototype->Object.prototype->null
return _constructor.call(obj, arg);
}
zepto(或其它框架)源码中如何使用原型链
执行上下文。
this。要在执行时才能确认,定义时无法确认。
call,bind,apply
// 指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象)
fun.call(thisArg, arg1, arg2, ...)
fun.apply(thisArg, [argsArray])
// 创建一个新函数,在调用时设置this关键字为提供的值。
function.bind(thisArg[, arg1[, arg2[, ...]]])
不要尝试用几句话去说明闭包
使用场景
对变量提升的理解
说明this的几种不同使用场景
创建10个a标签,点击弹出相应的序号
var i;
for (i = 0; i < 10; i++) {
(function (i) {
var a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('', function (e) {
e.preventDefault();
alert(i); // 自由变量,要去父作用域获取值
});
document.body.appendChild(a);
})(i)
}
如何理解作用域
实际开发中闭包的应用
实际开发中主要用于封装变量,收敛权限
异步与同步区别
单线程
Date
Date.now() // 获取当前时间的毫秒数
var dt = new Date()
dt.getTime() // 获取毫秒数
dt.getFullYear() // 年
dt.getMonth()
dt.getDay()
dt.getHours()
dt.getMinutes()
dt.getSeconds()
Math
Math.random() // 获取随机数
Array
forEach()
every()
some()
sort()
map()
filter()
Object
for in
写一个能遍历对象和数组的函数
function forEach(obj, callback) {
var key;
if (obj instanceof Array) {
obj.forEach(function (item, index) {
callback(index, item);
})
} else {
for (key in obj) {
callback(key, obj[key]);
}
}
}
HTML(HyperText Markup Language)
结构:dom树
获取DOM节点
getElementById() //元素
getElementsByTagName() //集合
getElementsByClassName() // 集合
querySelectorAll()
querySelector()
proterty
js属性
style,className,nodeName,nodeType
Attribute
html属性
createElement(),appendChild(),.parentElement,childNodes,removeChild()
function bindEvent(elem, type, selector, fn) {
if(fn == null) {
fn = selector;
selector = null;
}
elem.addEventListener(type, function(e) {
var target;
if(selector) {
// 代理
target = e.target;
if(target.matches(selector)) {
fn.call(target, e)
}
} else {
fn(e)
}
})
}
代理:
XMLHttpRequest
var xhr = new XMLHttpRequest()
xhr.open('GET', 'url', false)
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if(xhr.status === 2) {
xhr.response
}
}
}
xhr.send(null)
readyState | 作用 |
---|---|
0 | 未初始化,还未调用send() |
1 | 已调用send(),还在发送请求 |
2 | 请求发送成功,已经接收到响应内容 |
3 | 解析响应内容 |
4 | 相应内容解析完成,可以在客户端用了 |
跨域
可以跨域的标签
存储
cookie
缺点:
localStorage,sessionStorage
代码管理
基本命令:
AMD
var path = require('path')
var webpack = require('path')
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: './app.js'
},
output: {
path: path.resolve(__dirname, './dist')
filename: 'bundle.js'
}
}
从哪里入手:
加载资源优化
静态资源的压缩合并
静态资源的缓存
使用cdn让资源加载更快
渲染优化
XSS跨站请求攻击
插入一段script
XSRF跨站请求伪造
lodash
ES6,针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用
var obj = { a: 0 , b: { c: 0}};
// ES6
Object.assign({}, obj)
JSON
var obj = { a: 0 , b: { c: 0}};
JSON.parse(JSON.stringify(obj))
递归
(function ($) {
'use strict';
var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');
function type () {
return Object.prototype.toString.call(this).slice(8, -1);
}
for (var i = types.length; i--;) {
$['is' + types[i]] = (function (self) {
return function (elem) {
return type.call(elem) === self;
};
})(types[i]);
}
return $;
})(window.$ || (window.$ = {}));//类型判断
function copy (obj,deep) {
if ($.isFunction(obj)) {
return new Function("return " + obj.toString())();
} else if (obj === null || (typeof obj !== "object")) {
return obj;
} else {
var name, target = $.isArray(obj) ? [] : {}, value;
for (name in obj) {
value = obj[name];
if (value === obj) {
continue;
}
if (deep) {
if ($.isArray(value) || $.isObject(value)) {
target[name] = copy(value,deep);
} else if ($.isFunction(value)) {
target[name] = new Function("return " + value.toString())();
} else {
target[name] = value;
}
} else {
target[name] = value;
}
}
return target;
}
}
跨域是发生在浏览器端
jsonp的原理和简单实现
function jsonp (req) {
var script = document.createElement('script')
var url = req.url + '?callback=' + req.callback.name
script.src = url
document.getElementsByTagName('head')[0].appendChild(script)
}
for..of和for...in的区别, 使用时注意用Object.hasOwnProperty判断是否真的包含元素
var a = [4,1,6]
for(var i of a) {console.log(i)} // 4,1,6
for(var i in a) {console.log(i)} // 0,1,2
Object.keys与for...of的区别:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.