js一些梳理
前端学习网站:掘金 博客园 CSDN 大前端
浏览器组成 1.Shell部分2.内核
内核的组成 1.渲染引擎 负责页面显示 2.JS引擎 3. 其他模块
主流内核介绍
 	>> * Trident(IE内核)
 	>> * Gecko(火狐FireFox内核)
 	>> * Webkit(苹果Safari内核)
 	>> * Presto(欧朋Opera内核)
 	>> * Webkit的分支Blink内核(谷歌Chrome内核)
 	 
 	JS引擎---Chrome浏览器,使用新的JS引擎V8,可以直接把JS代码转换为机器码,所以执行速度大大提高
 	JS的组成
 	* ECMAScript
 	* DOM(Document Object Model)
 	* BOM(Browser Object Model)
 	 
 	JS运行在哪里---JS是一门解释性语言,运行在浏览器中,由浏览器的JS引擎负责解释运行JS代码。
 	 
 	JS是一门语言
 	>> * 任何属性都可以修改
 	>> * 任何标签都可以有ID属性,可以通过ID属性获取该元素
 	>> * 修改属性时,HTML当中怎么写,JS当中就怎么写,但class是特例,用className
 	>> * 修改样式的格式:obj.style.属性=值
 	>> * JS用style修改属性时,如果CSS的属性有"-"的话,通常把"-"去掉,然后把"-"后面的单词首字母大写
 	>> * 传统的做法是把script标签写在head标签里面
 	>> * script标签中的type属性可以不用写, 默认就是type="text/javascript"
 	>> * 延迟属性defer,添加该属性后,脚本文件会在整个页面都解析完毕后执行
 	>> * 异步属性async,添加该属性后,脚本会立即下载执行,但不妨碍页面中的其他操作
 	 
 	noscript标签
 	指定在不支持脚本的浏览器中显示替代内容
 	>> * 不支持脚本指浏览器自身不支持脚本,或,支持,但是被禁用了
 	 
 	变量命名
 	> * 第一个字符必须是字母,下划线(_)或者美元符号($)
 	> * 其他字符可以是字母,下划线(_)或者美元符号($)或者数字
 	> * 命名一般采用驼峰大小写格式,即第一个字母小写,剩下的每个单词首字母大写
 	> * 不能用关键字,保留字做为标示符
 	 
 	* 严格模式(strict mode)
 	> * 作用:告诉JS引擎切换到严格模式下解析代码,这种模式可以消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为,这是在ES5中新增的一种运行模式
 	>> * 针对整个文件,将"use strict"放在脚本文件的第一行,则整个脚本都将以"严格模式"运行,如果这行语句不在第一行,则无效
 	>> * 针对单个函数,将"use strict"放在函数体的第一行,则整个函数以"严格模式"运行。
 	> * 注意点:
 	>> * 同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。
 	function sayHi(){
 	"use strict"
 	alert(!this);
 	}
 	 
 	循环结构
 	1-while循环
 	初始值;
 	while(循环退出条件){
 	循环体(语句)
 	循环退出条件的改变
 	}
 	2-for循环
 	for(初始值;循环退出条件;循环退出条件的改变){
 	循环体(语句)
 	}
 	 
 	在使用属性时,用[]可以代替所有的.,但是.不一定能代替[]
 	 
 	数组
 	> * 可以通过下标来访问数组中的元素
 	> * 数组的下标是从0开始的
 	> * 可以通过数组的length属性获取到数组的长度
 	> * getElementsByTagName方法获取的数据返回的就是一个数组
 	 
 	数据类型 Undefined、Boolean、Number、String、function
Object包括 对象、数组、null
 	 
 	Undefined 未定义
 	> * 未定义类型只有一个值undefined,这个值的意思是变量没有定义
 	> * 未定义有两种情况,一个是真的没有定义,一个是定义了但是没有赋值
 	 
 	Null 空对象
 	> * 空对象类型只有一个值null,代表一个空对象指针,所以用 typeof 检测时会返回 'object'
 	 
 	Boolean 布尔类型
 	> * 布尔类型有两个值:true和false
 	> * 真:true,非零数字,非空字符,非空对象,
 	> * 假:false,数字零,空字符,null,undefined
 	 
 	Number 数字类型
 	> * 用来表示数字
 	> * 可以表示整数和小数(也叫浮点数或者双精度数)
 	 
 	String 字符串类型
 	> * 用单引号或者双引号括起来的字符序列
 	> * 单引号和双引号表示的字符串完全一样
 	 
 	Object 对象类型
 	var car = {type:"Fiat", model:500, color:"white"};
 	> * 数组在ES中是对象
 	> * 函数在ES中是对象,但函数也有一些特殊的属性,所以用 typeof 检测时会返回 'function'
 	> * 对象是一组数据和功能的集合
 	> * 对象是变量的容器
 	> * 对象是属性和方法的容器。
 	> * 对象的方法定义了一个函数,并作为对象的属性存储
 	 
 	JS变量的类型由值决定,并且随着值的变化而变化
 	 
 	显式转换parseInt 和 parseFloat
 	 
 	> * 能把首位不是字符的字符串转化为数字
 	例如:'a123' 不会转化 返回一个NaN
 	'12a3' 转化为12 返回一个number类型的数字
 	 
 	> * parseInt用来转换整数,parseFloat可以转换整数和小数
 	> * 转换时忽略字符串前面的空格
 	> * 如果第一个字符不是数字或者负号加数字,会返回NaN(Not a Number)
 	> * 从左到右解析直到第一个非数字为止
 	 
 	isNaN(x) 返回true或false
 	> *由于NaN和NaN并不相等,所以用isNaN函数来判断转换后的值是不是数字
 	 
 	变量的作用域
 	全局变量 >> 定义在所有函数外面,所有的函数都可以使用的变量
 	局部变量 >> 定义在函数的内部,指定在函数内部或者函数的子函数中使用
 	> * 函数执行时依赖于变量的作用域,这个作用域时在定义的时候决定的,而不是在调用的时候决定
 	 
 	变量的提升 var
 	定义会被提升 赋值不会被提升
 	 
 	变量的类型,Undefined,Null,Boolean,Number,String
 	> * 基本类型访问的变量的实际值
 	> * 基本类型不能动态的添加属性
 	> * 基本类型变量复制时会新建一个变量并分配空间,将变量的值分配在新的空间上
 	 
 	引用类型
 	> * 引用类型主要指保存在内存中的对象,包括对象,数组,函数
 	> * 引用类型访问的是引用,引用是指向内存的一个指针
 	> * 引用类型可以动态的添加属性
 	> * 引用类型复制时不会新建空间,只是复制了一个新的引用
 	 
 	关系 > <, >,<=,>=,==,!=,===,!==
 	== 不区分类型的相等 计算时会先转换类型,再比较 <相等式>
 	!= 相等式的非形式
 	=== 区分类型的相等 计算时不做类型转变,类型不同就一定不等 <恒等式>
 	!== 恒等式的非形式
 	 
 	逻辑 与(&&),或(||),否/非(!)
 	 
 	函数的返回值
 	在函数体内通过return把函数的执行结果返回
 	> * 一个函数只能有一个返回值
 	> * 没有返回值或者只有return的函数返回值是undefined
 	> * 函数的返回值是在调用的时候获取的
 	 
 	闭包 子函数可以使用父函数中的变量
 	> * 变量的值始终保持在内存中,不会在调用后被自动清除。
 	> * 大量使用降低网页性能 ie浏览器中会内存泄露
 	> * 当在函数内部的定义变量不用var a=1;时 用a=1;时 该定义变量会成为全局定义变量
 	 
 	函数function(){}作用域
 	* 块级作用域:在代码块(花括号中的代码)中声明的变量在代码块外不可用
 	* 函数作用域:在函数内部声明的变量在函数内部以及子函数中都可以使用
 	* JS没有块级作用域,而是函数作用域
 	* JS中因为是函数作用域,所以有声明提升的现象,即JS函数中声明的所有变量(不涉及赋值)都被提前到函数的顶部
 	var a=function(){} 这种匿名函数变量a会被提升 函数内的赋值不会被提升 只有当调用时才会被初始化
 	function a(){} 这种命名函数编译后函数声明和他的赋值都会被提前。也就是说函数声明过程在整个程序执行之前的预处理就完成了,所以只要处于同一个作用域,就可以访问到,即使在定义之前调用它也可以。
 	所以匿名函数节省资源
 	 
 	递归调用
 	自己调用自己的函数
 	 
 	函数的不定参数
 	> * 每一个函数都有一个参数数组,数组的名字是arguments
 	> * 严格模式arguments.callee已被废弃
 	> * 参数数组中的值由‘调用时’传递,按照传递参数的顺序存储在数组中
 	 
 	数组的定义
 	1.var arr = new Array(1,2,3);
 	2.var arr = [1,2,3]
 	1和2的作用时一样的,方法2效率上更高一些
 	> * 可以改变数组的length属性,改变后的值是数组的实际长度,可以通过这种方法清空数组
 	 /n ==== String.fromCharCode(10) 有些地方支持js写法不支持字符串,要换行时
 	DOM节点
 	子节点包括>> 文本节点>> 元素节点
 	document.createElement('li')
 	document.getElementById('ul1')
 	document.getElementsByTagName('li') 获取一个数组
 	document.getElementsByName(elementName) 通过节点的name获取节点 返回具有同样名称的节点数组
 	document.getElementsByClassName("example");返回文档中所有指定类名的元素集合数组
 	document.querySelector('#xxx/.xxx') 可以用id, 类, 类型, 属性, 属性值等来选取元素对于多个选择器,使用逗号隔开,返回一个匹配的元素。方法返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代。
 	 
 	> * 获取子节点的方法
 	var aLi=aUl.childNodes 获取父元素的所有子节点
 	var aLi=aUl.children 获取父元素的所有元素节点 children[0]第一个
 	>> * oParentNode.childNodes,返回一个数组,包含父节点中的所有文本节点和元素节点
 	>> * 通过nodeType属性来判断节点的类型,1为元素节点,3为文本节点
 	>> * oParentNode.children,返回一个数组, 包含父节点中的所有元素节点
 	 
 	> * 获取父节点的方法
 	var oBox2.parentNode 获取子元素的父节点
 	var oBox2.offsetParent 获取参考绝对定位贴靠的元素节点
 	> * oNode.parentNode,子节点的父节点对象
 	> * oNode.offsetParent,子节点绝对定位时,获取参考的父节点对象
 	 
 	> * xxx的第一个子节点 xxx.firstChild,
 	> * xxx的第一个元素子节点 xxx.firstElementChild,
 	> * xxx的最后一个子节点 xxx.lastChild
 	> * xxx的最后一个元素子节点 xxx.lastElementChild,
 	 
 	> * 兄弟节点
 	> * 下一个兄弟节点nextSibling,
 	下一个兄弟元素节点nextElementSibling
 	> * 前一个兄弟节点previousSibling,
 	前一个兄弟元素节点previousElementSibling
 	 
 	获取节点的值
 	获取dom节点之后,是一个对象 对象上有childNodes、innerHTML、innerText 等好多属性
 	获取dom节点数组 childNodes是一个数组包含元素节点和文本节点
 	获取一个dom节点 比如<p>4545</p> childNodes数组里只有文本节点
 	节点.innerHTML html
 	节点.innerText 文本值
 	 
 	获取样式函数
 	> * 获取行间样式 elem.style[attr] css样式表中的获取不到
 	> * 获取系统已定义过的参数 与行间样式 getComputedStyle(obj,false)[attr]
window.getComputedStyle()方法返回一个对象,返回的style是实时的,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值
window.getComputedStyle(elem,null).getPropertyValue("height")
 	 
 	obox.offsetLeft/Top/Width/Height 获取obox的left值 offsetLeft 获取的是相对于父对象的左边距
 	obox..style.left 获取或设置相对于 具有定位属性(position定义为relative)的父对象 的左边距
 	1. style.left 返回的是字符串,如28px,offsetLeft返回的是数值28
 	2. style.left是读写的,offsetLeft是只读的,所以要改变div的位置,只能修改style.left
 	 
 	操作属性
 	> * 获取属性的值:getAttribute(名称),有属性获取值,没有属性返回null
 	> * 设置属性:setAttribute(名称,值) 例如xxx.setAttribute('value','123')
 	> * 删除属性:removeAttribute(名称)
 	 
 	创建元素 var node=document.createElement('li')
创建纯文本var node=document.createTextNode('文本内容')
追加元素 parentNode.appendChild(node) //在父元素所有子元素的末尾插入名字为node的子元素
* 在不创建node的时候会把页面已经存在的node添加到parentNode里
插入元素 parentNode.insertBefore(node1,node2), 把node1插入在node2之前
删除元素 parentNode.removeChild(node)
 	给p、div等一些非表单元素的标签加上contenteditable="true"能使该标签变为可编辑模式
 	* textarea差不多 区别在没有滚动条而是内容在撑起高度 placeholder不可用
 	* 双向绑定数据 编辑 直接就能获取到值
 	定时器 按照异步类型执行
 	* setInterval(fn,时间) 开启循环型定时器
 	* setTimeout(fn,时间) 开启延迟型定时器
 	* clearInterval(定时器) 关闭循环型定时器
 	* clearTimeout(定时器) 关闭延迟型定时器
* 循环型定时器在定时器关闭前会一直按照设定的间隔时间执行,延迟型定时器只执行一次
* 定时器中指定的时间指的是该时间后把代码加入到执行队列中,如果队列空闲就立即执行
 	
 	窗口可视高度 window.innerHeight 随窗口拉伸变化 移动端可表示手机的CSS像素 物理像素*dpr(2)=document.documentElement.clientHeight
document.body 页面的body节点
- document.body.clientHeight 页面body的高 不算页面最上面的margin-top和页面最下面的margin-bottom
 - document.body.scrollTop 滚动距离-最后一屏到顶部的距离
 - document.body.clientHeight 页面可视窗口的高
 
document.documentElement 页面的html节点
- document.documentElement.scrollHeight HTML总高
 - document.documentElement.scrollTop 滚动距离-最后一屏到顶部的距离
 - document.documentElement.clientHeight 页面可视窗口的高
 
 >> * document.body.scrollTop 滚动距离,safari用
 	>> * document.documentElement.scrollTop 滚动距离,chrome/ff...用
 	>> * window.onresize事件,窗口大小发生变化时触发
 	>> * window.onscroll事件,滚动条变化时触发
//滚动距离 兼容写法
				function getScrollTop() {
  var scrollTop =  0, bodyScrollTop = 0, documentScrollTop = 0;
  if (document.body) {
    bodyScrollTop = document.body.scrollTop;
  }
  if (document.documentElement) {
    documentScrollTop = document.documentElement.scrollTop;
  }
  scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;
  return scrollTop;
				      // return $(window).scrollTop()
				}
			 
				//可视窗口高度
				function getWindowHeight() {
  var windowHeight = 0;
  if (document.compatMode == "CSS1Compat") {
    windowHeight = document.documentElement.clientHeight;
  } else {
     windowHeight = document.body.clientHeight;
   }	    
  return windowHeight;
				      // return $(window).height()
				}
			 
				//文档总高度
				function getScrollHeight() {
				      var scrollHeight = 0, bodyScrollHeight = 0, documentScrollHeight = 0;
				      if (document.body) {
				        //     bodyScrollHeight = document.body.scrollHeight;
				      }
				      if (document.documentElement) {
				       documentScrollHeight = document.documentElement.scrollHeight;
				      }
				      scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
				      return scrollHeight;
				      // return $(document).height()
				}
页面触底事件
window.onscroll = function (){
      var marginBot = 0;
      if (document.documentElement.scrollTop){
            var X=document.documentElement.scrollHeight;
            var Y=document.documentElement.scrollTop+document.body.scrollTop;
            var Z=document.documentElement.clientHeight;
            marginBot=X-Y-Z;
      } else {
            var J=document.body.scrollHeight;
            var I=document.body.scrollTop;
            var K=document.body.clientHeight;
            marginBot=J-I-K;
      }
      if(marginBot<=0) {
        //do something
      }
用jq
var dy = $(document).height();
var sy = $(window).scrollTop();
var wy = $(window).height();
if (dy - wy - sy <= 0) {
}
}
 	节点的宽高
 	elem.style.width :行间样式-写在HTML的样式的元素 内容的宽高
 	elem.offsetWidth/offsetHeight:内容+内边距(padding)+边框+滚动条宽度
 	getComputedStyle(elem,false)['width'] : 内容的宽高
 	 
 	 
 	* window代表一个浏览器对象
 	* window对象是一个全局对象,因此在全局作用域中声明的变量函数会变成window对象的属性和方法
 	 
 	window.open() > 打开一个新窗口并进入新打开的窗口对象
 	* window.open("about:blank","_blank");
 	* window.open("about:blank");默认blank
 	* window.open("about:blank","_self");
 	* window.open("http://www.kuazhu.com");
 	 
 	window.close() * 不能关闭用户打开的窗口
 	 
 	window.navigator.userAgent * 当前浏览器的信息
 	 
 	window.location 当前页面的相关信息对象,可以读取和赋值
 	* document.location和window.location是同一个对象
 	* window.location.href 属性代表当前页面的完整url
 	* window.location.assign(url),assign方法会打开url,如果把location.href或者location设置为一个url值,也会调用assign方法
 	* location的其他属性
 	 
 	window.histroy * 用户上网的记录,从窗口被打开的那一刻算起
 	history.go(-1) == history.back()
 	history.go(1) == history.forward()
 	 
 	交互
 	var res = prompt("请输入你的姓名?");
 	确定 res为输入的文字 无内容确定为空'' 取消为null
 	 
 	var res = confirm("你确定删除吗?");
 	确定为true 取消为false
 	 
 	然后逐级向上传播事件 为冒泡
 	从事件传递的最上面逐级向下传播 为捕获
 	阻止事件冒泡 event.stopPropagation()
 	 
 	鼠标事件
 	> event.clientX 和 event.clientY是鼠标的当前可视区坐标 不包括滚动的距离
 	> obj.onmousedown 当鼠标按下去时
 	> obj.onmouseup 当鼠标按键被松开
 	> document.onmousewheel 鼠标滚轮事件
 	> oEvent.wheelDelta 向下滚滚轮为正值向上滚滚轮为负值
 	 
 	键盘事件
 	* 键盘按下 obj.onkeydown
 	* 键盘抬起 obj.onkeyup
 	* 键盘代码 event.keyCode event.keyCode==12 值为数字
 	* 辅助键 event.ctrlKey event.shiftKey event.altKey
 	 
 	默认行为是浏览器的自带行为
 	document.oncontextmenu 右键菜单
 	阻止默认行为
 	> * 方法一 return false
 	> * 方法二 event.preventDefault()
 	 
 	事件
 	* 事件是用户或者浏览器执行的某中动作,如click/mouseover
 	* 事件处理程序是响应事件的函数,事件处理程序以on开头,如onclick/onmouseover
 	 
基本事件绑定 obj.addEventListener(事件名,函数,false) > 事件名没有on
自定义事件绑定
1.先定义一个new一个命名事件,detail里面可以写参数,也可为空
var myEvent = new CustomEvent('event_name', { 
	      detail: { title: 'This is title!'},
	});
2.在dom元素上绑定该自定义名字的事件,然后回调为要触发的函数
dom.addEventListener('event_name', function(event){
  to do something....
	});
3.设定触发时机,当什么时候触发该自定义的事件
	window.onresize=function(){
		  dom.dispatchEvent(myEvent);		
	}
 	事件移除 obj.removeEventListener(事件名,函数,false)
 	> 移除事件监听只能是移除有函数名的,不能移除匿名函数的
 	 
 	事件委托 利用事件冒泡来达到委托的效果
 	 
 	event对象常见的属性和方法总结
 	* event.type 当前事件类型
 	* event.target 事件源对象,直接点击的对象
 	* event.currentTarget 绑定事件的对象
 	* event.clientY/event.clientX 可视区(浏览器)的内沿到鼠标的距离
 	* event.pageY/event.pageX 可视区(浏览器)的内沿加滚动距离到鼠标的距离
 	* event.screenY/event.screenX 显示器屏幕内沿到鼠标的距离
 	* event.preventDefault() 阻止默认行为
 	* event.stopPropagation() 阻止冒泡
 	* event.keyCode 键盘编码
 	* event.ctrlKey event.shiftKey event.altKey 辅助键
 	 
 	事件种类
 	onload、onscroll、onresize、onclick、onmouseover/onmouseenter
dom.onscroll=function(){}
 	> * 鼠标穿过事件源对象或其子元素时触发onmouseover,对应的有onmouseout
 	> * 鼠标穿过事件源对象时触发,无视冒泡行为onmouseenter,对应的有onmouseleave
 	onmouseout/onmouseleave
 	onmousemove
 	onmousedown
 	onmouseup
 	onkeydown
 	onkeyup
 	表单事件
 	onfocus 表单获取焦点触发
 	onblur 表单失去焦点触发
 	onchange 页面内容有改动,失去焦点执行
 	onkeypress 键按下去触发,键不抬起会一直触发
 	onkeyup 键抬起触发,包括功能键
 	oninput 输入后触发,不包括功能键
 	onsubmit form表单提交事件
 	onreset form表单重置事件
 	 
 	对象就是一个可以提供特定功能的黑盒子,使用者不用关心功能的具体实现,只要知道怎么用就可以了
 	 
 	什么是面向对象的程序设计 > 开发具有特定功能的黑盒子
 	 
 	对象的特点
 	> * 封装 把具体的功能实现包起来,对外不公开
 	> * 抽象 根据具体的业务需求把需要的属性和方法抽取出来
 	> * 继承 子类具有父类的方法和属性,然后子类再开发自己特有的方法和属性
 	> * 多态 把子类赋给父类,赋值后的父类具有子类的特性
 	 
 	* 对象的组成 >属性(变量) >方法(函数)
 	对象的属性不能重复
 	 
 	js对象和json的区别
 	var json='{"name":"tom","age":18}';
 	var json='[{"name":"tom","age":18},{"name":"ammy","age":20}]';
 	>> * json是一种数据传输格式,js对象是类的实例,不能直接传输
 	>> * json的键必须添加双引号,值不能是函数,js对象键不用加双引号,值可以是任意类型,如果js对象的属性不是一个合法的变量名时需要加双引号
 	>> * json可以通过JSON.parse(jsonstr)转换为js对象,js对象可以用JSON.stringify(jsobj)转换为json
 	 
 	构造函数创建
 	1.用系统自带的对象创建对象
 	>> * 缺点:会有把系统自带的方法和属性覆盖掉的风险
 	 
 	2.用Object对象来创建对象
 	>> * Object是所有对象的父类
 	>> * 创建的对象方法和属性不能共用
 	 
 	3.用工厂模式的函数创建对象
 	>> * 不能用new来创建对象
 	>> * 方法不能被实例共享,每个对象实例都生成一个相同的方法
 	 
 	4.用new关键字创建对象 - 构造函数
 	>> * new 的作用,函数会在一开始创建一个对象,并且这个对象就是this,最后会把这个this对象返回出去
 	>> * 直接用new后可以把用工厂模式函数中创建对象和返回对象省略,但是方法还是不能被实例共享
 	>> * 用new后,把工厂模式函数可以看做是类,类名一般首字母大写
 	>> * 构造函数方法共享-将构造函数里面的方法指向全局函数
 	>> * 缺点1.全局函数会在其他地方调用,这时会有风险
 	>> * 缺点2.如果方法太多,就需要创建大量的全局函数
 	>> * 缺点3.违背面向对象的封装特性
 	 
 	5.构造原型模式
 	>> * 原型 prototype 是存在于构造函数上的一个对象,所有的实例对象都可以访问原型对象
 	>> * 可以在原型对象prototype添加共用的属性或者方法
 	>> * 变化的属性和方法写在构造器中
 	>> * 动态原型模式
 	>> * 可以把原型对象prototype上的定义写在构造函数中,定义之前需要唯一执行判断
 	 
 	用来创建对象的函数叫构造函数,也叫类
 	 
 	对象实例 > 由构造函数创建的一个具体的对象
 	 
 	静态方法和实例方法
 	> 添加在构造函数上的方法是静态方法,静态方法的调用方法是 构造函数.方法名()
 	> 添加在构造函数的原型对象上的方法是实例方法,实例方法的调用方法是 对象的实例.方法名()
 	 
 	原型链
 	原型就是一个对象,所有的实例共享对象上的方法和属性
 	> * 一但有构造函数,系统会自动的给构造函数添加一个原型对象prototype
 	> * 系统会给原型对象上添加一个constructor对象(prototype.constructor),就是构造器,整个构造器指向构造函数本身
 	> * 系统会给原型对象上添加另外一个__proto__的对象(prototype.__proto__),该对象指向Object的原型对象(Object.prototype)
 	> * Object的原型对象(Object.prototype) 里面也有constructor对象和__proto__对象,constructor对象指向Object自己,__proto__对象指向null
 	> * Object的原型对象(Object.prototype) 里面除了constructor对象和__proto__对象外,还有一些系统自带的方法,比如toString(),valueOf()等等
 	> * 可以在原型对象上添加自己的方法和属性,这些方法和属性也会被所有的实例共享
 	> * 对象的实例有自己的属性和方法,同时系统会给对象实例添加__proto__对象,__proto__对象对象就是构造函数的原型对象
 	>* 实例对象的__proto__对象-->构造函数的原型对象,构造函数的原型对象的__proto__-->Object的原型对象,Object的原型对象的__proto__ -->null
 	 
 	原型链上的属性
 	添加
 	>> 在实例上添加一个实例上的同名属性会覆盖原来的
 	>> 如果在实例对象上添加了一个构造函数原型对象上的同名属性,访问时会找到实例对象上的该属性
 	删除
 	>> 通过delete 删除属性
 	>> 删除实质是判断有没有该属性,如果有删除返回真,若没有,直接返回真
 	>> 如果删除了原型上的属性,所有实例都访问不到该属性
 	判断
 	>> 判断对象上是否有自己实例上指定的属性,如obj1.hasOwnProperty('name')
 	>> 判断对象的原型链上是否有指定的属性,如"LEGS" in obj1;
 	>> 判断属性只在原型上有
 	function hasPrototypeProperty(obj,name){
 	return !obj.hasOwnProperty(name) && (name in obj);
 	}
 	 
 	属性的定义
 	定义单个属性
 	Object.defineProperty(
 	对象,
 	属性名,
 	{value:属性值,
 	enumerable:true,//是否可以枚举,默认是false
 	writable:true,//是否可写(赋值),默认是false
 	configurable:true//是否可删除,是否可以修改属性的权限,默认是false}
 	);
 	 
 	定义多个属性
 	Object.defineProperties(对象,{
 	属性名1:{value:属性值,writable:true},
 	属性名2:{value:属性值,enumerable:true},
 	属性名3:{value:属性值}
 	});
 	 
 	查看属性的权限
 	Object.getOwnPropertyDescriptor(对象,属性名)
 	 
 	继承
 	> 改变函数内部的this指向
 	>> 调用函数时,函数名.call(参数1,参数2....),call 第一个参数是被调用函数里面的this,后面是对应的参数列表
 	>> 调用函数时,函数名.apply(参数1,[]),apply 第一个参数是被调用函数里面的this,第二个是参数接受一个数组做为参数列表
 	>> 函数名.bind(参数),bind会返回一个函数,函数内部的this就是bind的参数
 	 
 	继承1
 	function 子类(属性1,属性2,属性3){
 	父类.call(this,属性1,属性2);//属性的继承
 	this.属性3 = 属性3; //子类的属性
 	}
 	子类.prototype = 父类.prototype; //方法的继承
 	子类.prototype.方法 = function(){} //子类的方法
 	> 缺点:由于方法的继承是引用赋值,所以父类也会有子类的方法
 	 
 	继承2
 	function 子类(属性1,属性2,属性3){
 	父类.call(this,属性1,属性2);//属性的继承
 	this.属性3 = 属性3; //子类的属性
 	}
 	//方法的继承
 	for(i in 父类.prototype){
 	子类.prototype[i] = 父类.prototype[i];
 	}
 	子类.prototype.方法 = function(){} //子类的方法
 	> 缺点:如果父类的方法是不可枚举的,子类就继承不到
 	 
 	继承3
 	function 子类(属性1,属性2,属性3){
 	父类.call(this,属性1,属性2);//属性的继承
 	this.属性3 = 属性3; //子类的属性
 	}
 	//方法的继承
 	子类.prototype = new 父类();//子类的prototype指向父类的一个实例
 	子类.prototype.constructor = 子类;
 	子类.prototype.方法 = function(){} //子类的方法
 	> 缺点:调用两次父类的构造函数,同时在子类的原型上产生了不必要的父类的属性
 	 
 	继承4
 	function 子类(属性1,属性2,属性3){
 	父类.call(this,属性1,属性2);//属性的继承
 	this.属性3 = 属性3; //子类的属性
 	}
 	//方法的继承
 	子类.prototype = Object.create(父类.prototype);
 	子类.prototype.constructor = 子类;
 	子类.prototype.方法 = function(){} //子类的方法
 	Object.create(参数)会创建一个新对象,新创建对象的__proto__对象就是参数
 	 
 	分组
 	str.match(/\d+/g);
 	以()内正则为标准 把字符串str分组
 	 
 	替换字符
 	var reg = /is/g;
 	str.replace(reg,"**");
 	 
 	var reg = /\bis\b/g;
 	str.replace(reg,"**");
 	 
 	var reg = /淘宝|京东/g;
 	str.replace(reg,"**");
 	 
 	var reg = /<[^<>]+>/g;
 	str.replace(reg,"**");
 	 
 	邮箱校验
 	var reg = /^\w+@[0-9a-z-]+\.[a-z]+$/i;
 	reg.test(value)
 	 
 	是否有汉字
 	var reg = /[\u4e00-\u9fa5]+/g;
 	reg.test(value)
 	 
 	计算汉字的长度
 	function getLength(str){
 	return str.replace(/[\u4e00-\u9fa5]/g,"aa").length;
 	}
 	 
 	* URL解析
 	var reg = /(\w+):\/\/([\w\.]+)\/(\w*)/;
 	str.match(reg)
* 截取字符串
正则截取字符串某部分的内容:(?<=左).*(?=右)
字符串123456789,截取456:(?<=123).*(?=789)
截取包括某部分左右两侧的内容:左(.*?)右
字符串123456789,截取23456:23(.*?)56
 	创建正则对象
 	* 方法一(构造函数): new RegExp(规则,修正模式) 如:new RegExp('a','g')
 	* 方法二(字面量): /规则/修正模式 如:var reg = /a/
 	 
 	原子(正则中的最小匹配单位)
 	* 可见原子-键盘输出后可以看得见的字符,如符号,英文,数字等
 	> 注意,以下字符具有特殊含义,如果要使用原本的字符意思,需要在前面添加\来转义
 	> > . * + ? $ ^ | \ () {} []
 	* 不可见原子-键盘输出后看不见的字符,如换行(\n),回车(\r),制表符(\t),垂直制表符(\v) 换页符(\f)
 	 
 	原子筛选
 	* | 竖线两边任意匹配 相当于或
 	* [] 括号中任意一个原子,可以写区间(闭区间),如[a-z0-9]
 	* [^] 括号中任意一个原子之外的原子
 	* 注意:一般情况下,正则中的一个字符对应字符串中的一个字符, 例如:/ab\t/表示字符串中连续出现字符 ab制表符
 	[]内是单独的字符 /[ab]/代表 a或b ;/ab/代表 ab 相当于/(ab)/
 	 
 	原子集合
 	* . 除了回车和换行外的任意字符 等价[^\r\n]
 	* \d 任意数字,等价[0-9], \D 任意非数字 等价[^0-9]
 	* \w 任意数字,字母,下划线 等价[0-9a-zA-Z_],\W 任意非数字,字母,下划线 等价[^0-9a-zA-Z_]
 	* \s 空白符 等价于[\t\n\f\r],\S 非空白符 等价于[^\t\n\f\r]
 	 
 	量词(限定前面原子出现的次数)
 	* {n} 前面原子恰好出现n次
 	* {n,} 前面原子最少出现n次
 	* {n,m} 前面原子最少出现n次,最多出现m次
 	* + 前面原子最少出现1次 等价{1,}
 	* ? 前面原子最少出现0次,最多出现一次 等价{0,1}
 	* * 前面原子最少出现0次 {0,}
 	 
 	'abcdeaada'.replace(/a{0,1}/g,'*');输出// "**b*c*d*e***d**"
 	'abcdeaada'.replace(/a{0,}/g,'*');输出// "**b*c*d*e**d**"
 	 
 	匹配模式
 	* 贪婪模式-尽可能多的匹配(默认)
 	'12345'.replace(/\d{2,4}/,'X');
 	"X5"
 	* 非贪婪模式-尽可能少的匹配(在量词后添加?)
 	'12345'.replace(/\d{2,4}?/,'X');
 	"X345"
 	 
 	边界控制
 	* ^ 匹配字符串开始的位置,限制必须以其后面的原子开头,前面不能有任何东西
 	* $ 匹配字符串结尾的位置,限制必须以其前面的原子结束,后面不能有任何东西
 	* \b 单词边界 /is/ 表示为任何形式存在的is /\bis\b/ 表示为单独存在的is
 	* \B 非单词边界
 	* () 把括号里面的正常表达匹配的结果当作一个原子来看,起到分组的效果,分组后可以通过反向引用来取得分组后的值,反向引用从$1开始
 	 
 	//匹配四个一个小写字母加一个数字的字符串
 	'a1b2c3d4aaaa'.replace(/([a-z]\d){4}/,"*"); //"*aaaa"
 	//将年月日替换成月日年
 	'2018-05-09'.replace(/(\d{4})-(\d{2})-(\d{2})/,'$2/$3/$1'); //"05/09/2018"
 	 
 	修正模式
 	* i(ignoreCase) 忽略大小写,默认区分大小写,可以通过正则对象上的global属性查看
 	* g(global) 匹配所有的,默认只找到第一个,可以通过正则对象上的ignoreCase属性查看
 	 
 	前瞻
 	* 正则从文本头部向文本尾部解析,文本尾部成为"前",前瞻就是向前(文本尾部)检查是否符合断言
 	 
 	* 正向前瞻 exp(?=assert)
 	匹配到exp的内容后(再看文本的前/内容的后)符合不符合assert,符合的话就匹配exp的内容
 	 
 	字符后面是数字的字符
 	'a2*3b&'.replace(/\w(?=\d)/g,'X') //X2*3b&
 	 
 	* 负向前瞻 exp(?!assert)、
 	匹配到exp的内容后再看(再看文本的前/内容的后)符合不符合assert,不符合的话就匹配exp的内容
 	 
 	//字符后面不是数字的字符
 	'a2*3b&'.replace(/\w(?!\d)/g,'X') //"aX*XX&"
 	 
 	> lastIndex 当前正则匹配内容的最后一个字符的下一个位置
 	> source 正则的文本字符串
 	 
 	* RegExp.prototype.test(str);
 	检验str是否符合reg的规则
 	> test方法测试字符串是否有匹配到正则的字符串,有返回true,没有返回false
 	> 如果全局匹配时,每一次匹配后正则对象上的lastIndex属性会更改,改为匹配内容的最后一个字符的下一个位置,所以结果会不可靠,一般使用test方法时建议不要全局匹配
 	> 如果非全局匹配时,lastIndex始终是0,也就是说始终从第0个元素开始查找
 	 
 	var reg = /\w/g;
 	console.log("0::",reg.lastIndex);//0
 	console.log("1::",reg.test('ab'));//true
 	console.log("2::",reg.lastIndex);//1
 	console.log("3::",reg.test('ab'));//true
 	console.log("4::",reg.lastIndex);//2
 	console.log("5::",reg.test('ab'));//false
 	console.log("6::",reg.lastIndex);//0
 	 
 	* RegExp.prototype.exec(str);
 	> exec方法对字符串执行搜索,并更新正则对象上的lastIndex属性,如果没有匹配的返回null,有的话返回一个数组:
 	>> * 数组的第0个元素是匹配的内容,如果有分组,从下标是1开始是对应分组的内容
 	>> * index 是匹配内容第一个字符的位置
 	>> * input 是被搜索的字符串
 	> * 如果非全局匹配时,lastIndex始终是0,也就是说始终从第0个元素开始查找
 	 
 	var reg = /(\d{4})-(\d{2})-(\d{2})/g;
 	var str = 'a2018-05-10b';
 	console.log(reg.lastIndex);//0
 	console.log(reg.exec(str));//["2018-05-10", "2018", "05", "10", index: 1, input: "a2018-05-10b", groups: undefined]
 	console.log(reg.lastIndex);//11
 	console.log(reg.exec(str));//null
 	console.log(reg.lastIndex);//0
 	console.log(reg.exec(str));//["2018-05-10", "2018", "05", "10", index: 1, input: "a2018-05-10b", groups: undefined]
 	 
 	字符串方法中使用正则
 	*String.prototype.search(reg)
 	('x') 或 (/x/);返回找到第一个X字符的下标
 	> * 从字符中检索于正则相匹配的字符串,返回第一个匹配结果的index,查不到返回-1
 	> * search方法不执行全局匹配,它会忽略g,并且总是从字符串开始检索
 	 
 	* String.prototype.match(reg)
 	> * 非全局匹配的结果和exec一样
 	> * 全局匹配,会找到字符串中的所有匹配字符串,如果没有匹配的话返回null,有的话返回一个()内需求的数组:
 	该数组中的每一项就是一个匹配结果,该数组和exec不一样的地方是第0元素,该数组没有匹配的内容,只有分组的内容,不接受()的识别,数组中没有index和input等属性,
 	>> * 全局匹配不需要分组
 	var reg = /(\d{4})-(\d{2})-(\d{2})/g;
 	var str = 'a2018-05-10b';
 	console.log(str.match(reg));//["2018-05-10"]
 	 
 	* String.prototype.split(reg)
 	> 根据正则匹配的内容把字符串分隔成数组
 	根据()内的规则分割,以/\d/数字为分割符
 	'a1b2c3d'.split(/\d/); //["a", "b", "c", "d"]
 	 
 	* String.prototype.replace(reg,str2)
 	> 把字符串中 经过正则reg匹配的子串 用 str2 进行替换
 	* String.prototype.replace(reg,function(经过正则reg匹配的子串,index,原值))
 	index为经过正则reg匹配的子串的下标
 	原值为String.prototype的值
 	> 把字符串中 经过正则reg匹配的子串 传递到回调函数进一步处理,用函数的返回值来替换匹配项,可以对经过正则reg匹配的子串进行更进一步的约束,达到自己需求的结果
 	var str = 'a1b2c3d4'.replace(/\d/g,function(match,index,origin){
 	return parseInt(match)+1;
 	})
 	 
 	获取表单元素
 	* document.forms 代表页面所有的表单集合
 	* document.forms[0].elements 代表某一个表单中的所有表单元素集合
 	 
 	* 获取一个表单中的元素的方法
 	> 表单元素集合[下标]
 	> 表单元素集合["元素名"]
 	> 表单元素集合.元素名
 	> 表单.元素名
 	> 同名的表单元素返回一个节点集合
 	* 表单元素.form 代表表单元素所在的form
 	 
 	表单元素的属性
 	* 禁用表单元素
 	> * 表单元素.disabled = true;
 	 
 	> * 表单元素.readOnly = true;
 	>> 只针对input(text/password)/textarea
 	>> 值会被提交
 	 
 	* 复选框选中属性 checked
 	> * 设置选中 aCheckBox[0].checked = true
 	* 单选框选中属性 checked
 	> * 设置选中 aRadio[0].checked = true
 	* 下拉框选中属性 selected
 	> * 设置某个选项选中 oSelect.options[i].selected = true
 	> * 通过选中属性获取所有选中项
 	 
 	表单元素方法
 	* 设置焦点 表单元素.focus();
 	* 移除焦点 表单元素.blur();
 	 
 	表单的提交和重置
 	1.HTML按钮默认提交
 	2.input type="submit"
 	3.input type="image"
 	4.button type="submit"
 	 
 	> * 表单被提交,数据没有发送前触发-form.onsubmit事件
 	> * 可以在该事件中通过阻止默认行为来阻止表单的提交
 	 
 	* 给普通按钮绑定事件,调用 form的submit()方法提交
 	这种form的 调用submit()函数方法不会触发 form.onsubmit事件
 	 
 	1.HTML按钮默认提交重置
 	2.input type="reset"
 	3.button type="reset"
 	> * 事件在表单重置前触发 form.onrest
 	> * 可以通过阻止默认行为来阻止重置
 	 
 	* 给普通按钮绑定事件,调用 form的reset()方法重置
 	这种form的 调用reset()函数的方法 会触发form.onrest事件
 	 
 	控制区错误提示
 	语法错误(SyntaxError)
 	> 不符合JS语法的错误,控制台会出现错误并且有行号提示
 	运行时错误(Runtime Error)
 	> JS无语法错误,在运行时发生的错误
 	* ReferenceError 变量引用异常触发的错误
 	* TypeError 类型使用时错误
 	* RangeError 递归爆栈时触发
 	逻辑错误
 	> * 在程序需要开始跟踪的地方打断点
 	>> * 在程序中需要开始跟踪的地方添加debugger关键字
 	>> * 在控制台的source面板中单击需要跟踪程序的行号
 	> * Watch 需要跟踪的变量
 	>> * 可以Watch一个表达式
 	>> * 可以在控制台中更改变量的值
 	 
 	> * Resume script execution 按钮,
 	执行脚本到下一个断点的位置
 	 
 	> * Step over next function call
 	跳过函数的内部执行,把函数当做一个语句来看
 	 
 	> * Step into next function call,
 	进入到函数的内部执行
 	 
 	> * Step out current function ,
 	跳出当前的到函数内部执行
 	 
 	> * Deactivate breakpoints/Activate breakpoints,
 	关闭和打开断点
 	 
 	> * Pause on exceptions,
 	异常处停止
 	 
 	>> * 如果选上 Pause on caught exceptions的话会在try语句中停止
 	 
 	主动触发异常
 	在程序中如果有些不可避免的错误发生时,可以主动的抛出一个异常,然后用try-catch语句来捕获异常
 	 
 	抛出异常
 	throw new Error('error msg');
 	 
 	捕获异常
 	try{
 	...//有可能出现异常的代码
 	}catch(e){
 	...//异常处理
 	}finally{
 	...//不管有没有异常都会处理,例如清理工作
 	}
 	 
 	 
 	 
 	(function(){})();
 	* 相当于该匿名函数的自我调用,封闭函数不会污染全局,变量封闭,用过一次就失效
 	* 封闭作用域,匿名函数自我调用解决变量作用域,不会污染全局变量
 	* 封闭作用域传递参数,解决i值问题
 	> * 子函数会使用作用域链中最近的变量,如果整个作用域中都没有定义,则报错
 	> * 父函数不能访问子函数中定义的变量
 	 
 	函数节流举例
 	function throttle(fn,delay){
 	var timer = null;
 	return function(){
 	clearTimeout(timer);
 	timer = setTimeout(fn,delay);
 	}
 	}
 	window.onresize = throttle(function(){
 	console.log(window.innerWidth);
 	},400)
 	 
 	 
 	* 过滤,把函数的每一次返回值为真的原数组中的值组成新的数组并返回。返回的都是满足value为真的部分
 	var newArr = arr.filter(function(value,index){
 	return value > 10;
 	})
 	 
 	* 全真判断,所有值为真的情况下返回真,否则返回假 有一个假就是假
 	var bRes = arr.every(function(value,index){
 	return value > 10;
 	})
 	 
 	* 有真判断,有一个值为真的情况下返回真,否则返回假 有一个真就是真
 	var bRes = arr.some(function(value,index){
 	return value > 10;
 	})
 	 
 	 
 	HTTP(HyperText Transfer Protocol)超文本传输协议
 	 
 	HTTP协议就是用来规范客户端(浏览器)和服务端通信规则的
 	 
 	> 常见的网络协议还有很多,如
 	> * FTP(File Transfer Protocol)文件传输协议
 	> * POP3(Post Office Protocol Version 3)邮局协议-版本3
 	> * SMTP(Simple Mail Transfer Protocol)简单邮件传送协议
 	> * TCP/IP(Transmission Control Protocol/Internet Protocol)传输控制协议/Internet协议
 	 
 	HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),安全套接字层超文本传输协议HTTPS。为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。
 	 
 	OSI(Open System Interconnection)开放式系统互联的七层架构
 	* 1 物理层(设备之间的比特流传输,物理接口)
 	* 2 数据链路层(成帧,用MAC地址访问媒介)
 	* 3 网络层(写入IP地址(数据源和数据目标的地址),选路)
 	* 4 传输层(确定是用TCP协议传输还是UDP协议传输)
 	> * 传输控制协议TCP可靠但是慢
 	> * 用户数据协议UDP不可靠但是快
 	* 5 会话层(安全协议,目录访问协议)
 	* 6 表示层(转码/解码,加密/解密)
 	* 7 应用层(提供应用数据,各种应用协议,如HTTP,FTP,SMTP...)
 	 
 	发送从应用层开始向下传输,接受从物理层开始向上传输
 	 
 	TCP/IP 4层模型
 	* 网络接口层(对应7层中的物理层和数据链路层)
 	* 网际互联层(对应7层中的网络层)
 	* 传输层(对应7层中的传输层)
 	* 应用层(对应7层中的应用层,表示层和会话层)
 	 
 	访问页面流程详解
 	* 客户在浏览器输入网址或者刷新页面
 	* 域名解析(以http://www.kuazhu.com/为例)
 	1 浏览器搜索自身的DNS缓存
 	查看浏览器缓存 chrome://net-internals/#dns
 	2 如果浏览器缓存没有或者过期,就去操作系统自身的DNS缓存查找
 	3 读取本地的HOST文件
 	windows:C:\Windows\System32\drivers\etc
 	OS:/etc/hosts
 	4 向宽带运营商服务器发起域名解析请求,宽带运营商服务器查看自身的缓存
 	5 运营商服务器发起一个迭代的DNS解析请求
 	5.1 找根域的服务器
 	5.2 根域服务器里面有com域的地址,根域让去找com域的服务器
 	5.3 com域服务器里面有kuazhu.com域的IP地址,com域服务器让去找kuazhu.com域的服务器
 	5.4 kuazhu.com域的服务器(一般是域名注册商)里面有对应的IP地址和域名的映射,找到后将IP地址发给运营商服务器
 	5.5 运营商服务器把结果返回给客户操作系统,同时操作系统将其缓存起来,
 	操作系统把结果返回给浏览器
 	 
 	* 浏览器获取IP地址后,发起TCP/IP 三次握手
 	 
 	第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
 	 
 	第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
 	 
 	第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
 	 
 	完成三次握手,客户端与服务器开始传送数据
 	 
 	* TCP/IP连接建立后,开始发送HTTP请求
 	浏览器发送请求行到服务器(请求行包括请求方法 uri 协议/版本等)
 	浏览器发送请求头到服务器,结束后发送一个空白行告诉服务器不再有请求头(请求头包含许多有关的客户端环境信息)
 	浏览器发送请求体到服务器(请求体主要是请求参数)
 	 
 	服务器应答处理并且返回响应行(响应行包括协议/版本 状态码 状态消息)
 	服务器返回响应头,结束后发送一个空白行告诉客户端不再有响应头(响应头包含许多有关的服务端环境信息)
 	服务器返回响应体(响应体主要是返回的数据)
 	 
 	关闭TCP连接
 	 
 	* 浏览器渲染服务器返回的内容
 	 
 	* HTTP一旦请求完成,连接就会断开,因此连接是没有记忆的,无状态的
 	 
 	Queued at
 	添加到处理队列的时间
 	 
 	Started at
 	开始处理的时间
 	 
 	Stalled 浏览器要发出请求到这个请求可以发出的等待时间,一般是代理协商、以及等待可复用的TCP连接释放的时间,不包括DNS查询、建立TCP连接等时间等
 	 
 	DNS Lookup
 	执行DNS查找时间
 	 
 	Initial connection
 	建立TCP连接的时间,就相当于客户端从发请求开始到TCP握手结束这一段,包括DNS查询+Proxy时间+TCP握手时间。
 	 
 	Request sent:请求的第一个字节发出前到最后一个字节发出后的时间
 	 
 	Waiting:请求发出后到收到响应的第一个字节所耗费的时间,包括数据的传输和服务器对请求的处理时间
 	 
 	Content Download:收到响应的第一个字节开始到收到响应的最后一字节结束所耗费的时间
 	 
 	HTTP的请求方法
 	GET方法
 	用于获取数据
 	请求是参数的大小有限制(400k)
 	参数以及参数的值会显示在地址栏中,安全性极低
 	 
 	POST方法
 	用于提交数据(表单的提交)
 	请求是参数的大小基本没有限制
 	参数不会显示在地址栏中,相对安全
 	 
 	URL uniform resource locator 统一资源定位器
 	可以理解为地址栏中的网址
 	 
 	URL的格式
 	完整格式:https://www.kuazhu.com:443/courseList
 	协议://域名:端口号/资源文件
 	 
 	服务器
 	安装了Web服务器软件的电脑就可以提供管理网站的服务,我们称之为Web服务器。
 	常见的Web服务器软件有:Apache,IIS,Tomcat,Nginx,NodeJs等
 	 
 	NodeJs 初识
 	* 官网 https://nodejs.org/ 下载安装,注意要下载LTS版本的
 	* NodeJs安装完成后,去终端用node -v 查看,如果有版本号说明安装成功
 	* 如果node命令找不到,Windows的用户注意环境变量的配置
 	* NodeJs安装的同时会安装npm(node package manager)
 	 
 	ajax请求流程:
 	* 客户端创建一个ajax对象
 	* 用ajax对象和服务端建立连接
 	* 用ajax对象发送请求到服务端
 	* 用ajax对象接收服务端返回的数据
 	 
 	定义变量let
 	> * let定义过的变量不能再定义,var定义过的变量可以重新定义
 	> * let定义的变量不会声明提升,var定义的变量会发生声明提升
 	> * let定义的变量在let命令所在的代码块内有效,var定义的变量在函数范围内有效
 	 
 	定义常量cons t(一旦定义,值就不能改变)
 	> * 定义常量的时候必须赋初值
 	> * 常量不可以再次赋值
 	> * const定义的常量保证的是常量的地址不可以改变
 	> * 对于简单数据来说值就保存在变量指向的那个内存地址,因此不可以再赋值
 	> * 对于复杂数据来说常量指向数据保存的地址,const保证的是这个地址不变,但地址指向的数据是可以修改的
 	> * const定义的常量在const命令所在的代码块内有效
 	> * const定义的常量不会声明提升
 	 
 	结构解析
 	* 作用:从数组或者对象中提取值然后对变量进行赋值
 	* 数组的结构解析:按照对应位置,把等号右边数组中的值赋给等号左边数组中的变量,数组可以嵌套
 	 
 	>> * 如果解构不成功,变量的值就等于undefined
 	>> * 如果等号的右边不是数组,会报错
 	>> * 可以在等号右边数组中设置默认值,当等号左边数组中对应位置的值是undefined时默认值才会生效。
 	 
 	* 对象的结构解析:按照对应属性名,把等号右边对象中的属性的值赋给等号左边对象中的同名属性
 	 
 	> * 等号左边对象中的属性的值是真正被赋值的变量名,如果属性的值省略,属性的值和属性的名称相同
 	 
 	模版字符 反引号+${}
 	`字符 ${javascript表达式}`
 	 
 	扩展运算
 	* 扩展运算符三个点...
 	* 数组的扩展运算就是将一个数组转为用逗号分隔的参数序列
 	* 数组的扩展运算的应用
 	 
 	函数调用时使用把数组转换为参数列表
 	function add(n1,n2){
 	return n1+n2;
 	}
 	let arr = [11,22];
 	add(...arr);
 	 
 	函数定义时使用把参数列表转换为数组
 	function add(...arr){
 	let result = 0;
 	for(let i = 0;i<arr.length;i++){
 	result += arr[i]
 	}
 	return result;
 	}
 	add(11,22);
 	 
 	求数组的最大数
 	let arr = [11,22,44,88,77];
 	//ES5
 	Math.max.apply(null,arr)
 	//ES6 用扩展运算
 	Math.max(...arr)
 	 
 	深拷贝数组
 	let arr1 = [11,22,44,88,77];
 	//ES5
 	let arr2 = arr1.concat();
 	//ES6 用扩展运算
 	let arr2 = [...arr1];
 	 
 	对象的扩展运算符...用于取出参数对象的所有可遍历属性,拷贝到当前对象之中
 	 
 	拷贝对象(浅拷贝)
 	 
 	let obj1 = {name:'Tom',age:18};
 	let obj2 = {...ojb1};
 	 
 	> 如果对象中有复杂数据类型,拷贝的是数据的地址
 	遍历器
 	* 遍历器(Iterator)是一种接口,实现了该接口的数据结构就可以完成遍历操作
 	* 遍历器接口主要供for...of循环来使用,也就是说实现了遍历器接口的数据类型都可以用for...of循环来遍历数据
 	 
 	Set 类似于数组,但值唯一的数据结构
 	Set对象的size属性返回Set实例的值的总数
 	 
 	Set对象的操作方法
 	> * add(value):添加某个值,返回 Set 结构本身
 	> * delete(value):删除某个值,返回一个布尔值,表示删除是否成功
 	> * has(value):返回一个布尔值,表示该值是否为Set的成员
 	> * clear():清除所有值,没有返回值
 	 
 	Set对象的遍历方法
 	> * keys():返回键名的遍历器
 	> * values():返回键值的遍历器
 	> * entries():返回键值对的遍历器
 	> * forEach(function(value,key){}):使用回调函数遍历
 	 
 	> * Set只有值没有键,所以key和value一样
 	> * Set的遍历顺序就是插入顺序
 	 
 	Map
 	* 类似于对象,但键的范围不限于字符串,各种类型的值(包括对象)都可以当作键的数据结构
 	* Map对象的size属性返回Map实例的键值对的总数
 	 
 	* Map对象的操作方法
 	> * set(key,value):设置键名key对应的键值为value,然后返回整个 Map 结构,如果key已经有值,则键值会被更新,否则就新生成该键。
 	> * get(key):读取key对应的键值,如果找不到key,返回undefined。
 	> * delete(key):delete方法删除某个键,返回true。如果删除失败,返回false。
 	> * has(key):has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
 	> * clear():清除所有键值,没有返回值
 	 
 	Map对象的遍历方法
 	> * keys():返回键名的遍历器
 	> * values():返回键值的遍历器
 	> * entries():返回键值对的遍历器
 	> * forEach(function(value,key){}):使用回调函数遍历
 	> * Map的遍历顺序就是插入顺序
 	 
 	Symbol
 	* Symbol是一种新的数据类型,表示独一无二的值
 	* Symbol值通过Symbol函数生成
 	* Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述
 	* Symbol的主要作用是用来表示对象的属性名
 	* Symbol值作为对象属性名时,不能用点运算符,在对象的内部页不可以
 	 
 	class类
 	* class类是ES6面向对象的语法糖
 	class Person{
 	constructor(name,age){
 	this.name = name;
 	this.age = age;
 	}
 	show(){
 	console.log('I am '+this.name+' and I am '+this.age+' years old');
 	}
 	showName(){
 	console.log('I am '+this.name);
 	}
 	showAge(){
 	console.log('I am '+this.age+' years old');
 	}
 	static sayHi(){
 	console.log('Hi...')
 	}
 	}
 	 
 	class Student extends Person{
 	constructor(name,age,major){
 	super(name,age);
 	this.major = major;
 	}
 	show(){
 	super.show();
 	console.log('I am from '+this.major)
 	}
 	showMajor(){
 	console.log('I am from '+this.major)
 	}
 	}
 	> * 用class定义的类也是函数
 	> * constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
 	> * 一个类必须有constructor方法,如果没有显式定义,系统默认添加一个空的constructor方法
 	> * constructor方法默认返回实例对象
 	> * 在class 中定义的方法实际上是给原型对象上添加方法
 	> * 类不存在变量提升
 	> * 静态方法前面添加static关键字,调用时用 类名.方法名 的形式调用
 	 
 	> * 父类的静态方法,可以被子类继承
 	> * 通过extends关键字实现继承
 	> * 子类必须在constructor方法中调用super方法,该super方法实际上是调用父类的constructo
 	> * 子类如果没有定义constructor方法,系统默认添加一个空的constructor方法,并且在这个方法会被默认添加一个空的super方法
 	> * 在子类的构造函数中,只有调用super之后,才可以使用this关键字
 	函数参数默认值
 	* 直接在参数定义的时候赋值来为为函数的参数设置默认值
 	function show2(x,y="world"){
 	console.log(x,y);
 	}
 	show2("hello");//hello world
 	 
 	* 参数默认值不是传值的,而是每次都重新计算默认值表达式的值
 	let x = 1;
 	function show(i=x+1){
 	console.log(i);
 	}
 	show();//2
 	x = 2;
 	show();//3
 	 
 	* 结构解析和默认参数结合
 	function show2(url,{method="GET",body="name=Tom"} = {}){
 	console.log(method,body);
 	}
 	show2();//GET name=Tom
 	show2('http://kuazhu.com');//GET name=Tom
 	>* 默认值参数应该是参数的尾部参数,否则不能省略
 	 
 	rest参数
 	* rest参数就是在函数定义时使用扩展运算(...变量名)把参数列表转换为数组
 	 
 	箭头函数
 	* 箭头函数就是使用"箭头"(=>)来定义函数
 	 
 	* 箭头函数的基本用法
 	let fn = (x,y)=>{
 	console.log(x,y);
 	return x + y;
 	}
 	* 如果函数体只有返回值,函数体的花括号和return语句可以省略,简写:
 	let fn = (x,y)=> x + y
 	* 如果只有一个参数,圆括号可以省略,简写:
 	let fn = x =>{
 	console.log(x);
 	return x + 10;
 	}
 	* 箭头函数中的this是在定义时确定的(定义时属于谁),而不是在运行时确定(谁调用)的
 	function Timer(id){
 	this.id = id;
 	setTimeout(function(){
 	console.log(this,this.id);//window 99
 	},100)
 	}
 	var id = 99;
 	let t = new Timer(100);
 	> * function 定义的函数,this是在运行时确定的,运行时函数属于谁this就是谁,上面例子中的延迟函数会在100毫秒后由window对象来调用,所以里面的this是window对象
 	> * function 定义的函数,可以通过call/bind/apply来改变函数的内部this
 	function Timer(id){
 	this.id = id;
 	setTimeout(()=>{
 	console.log(this,this.id);//Timer?{id: 100} 100
 	},100);
 	}
 	var id = 99;
 	let t = new Timer(100);
 	> * 箭头函数导致this总是指向函数定义生效时所在的对象
 	> * 上面例子中延迟函数中匿名函数在定义的时候是属于Timer的实例对象,所以里面的this就是Timer对象
 	> * 用let定义的函数不会声明提升
 	 
 	Promise的概念
 	* Promise 是一种异步编程解决方案
 	* 将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
 	* Promise对象提供统一的接口,使得控制异步操作更加容易
 	 
 	Promise的特点
 	* Promise有三种状态
 	> * pending(进行中)
 	> * fulfilled(已成功)
 	> * rejected(已失败)
 	* 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
 	 
 	* 一旦状态改变,就不会再变
 	 
 	* Promise对象的状态改变,只有两种可能:
 	 
 	>* 从pending变为fulfilled
 	>* 从pending变为rejected
 	 
 	Promise的使用
 	* Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
 	* resolve函数在异步操作成功时(从pending变为fulfilled)调用,并将异步操作的结果作为参数传递出去
 	* reject在异步操作失败时(从pending变为rejected)调用,并将异步操作报出的错误作为参数传递出去
 	* Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数,rejected状态的回调函数可以省略
 	* Promise 新建后就会立即执行
 	 
 	### Promise对象的方法
 	* then(resolved状态的回调,rejected状态的回调)
 	> * then方法返回的是一个新的Promise实例
 	 
 	* catch(回调)
 	> * 如果异步操作抛出错误,状态就会变为rejected,当then中没有指定rejected状态的回调时就会调用catch方法指定的回调函数
 	> * 如果运行中抛出错误,也会被catch方法捕获
 	 
 	* finally(回调)
 	> * 不管Promise对象最后状态如何,都会执行的操作
 	> * finally方法的回调函数不接受任何参数
 	 
 	Promise静态方法
 	* Promise.resolve()
 	> * 如果参数是Promise实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例
 	> * 如果参数是一个具有then方法的对象,resolve方法会将这个对象转为 Promise 对象然后就立即执行该对象的then方法
 	> * 如果参数参数不是具有then方法的对象,或根本就不是对象,返回一个新的 Promise 对象,状态为resolved
 	> * 不带有任何参数,直接返回一个resolved状态的 Promise 对象
 	 
 	* Promise.reject()
 	> * 返回一个新的Promise实例,该实例的状态为rejected,参数会原封不动地作为reject的理由
 	 
 	* Promise.all()
 	> * 接受一个Promise实例数组作为参数,返回一个新Promise实例
 	> * 当数组中的所有Promise实例的状态都变成fulfilled时,Promise实例的状态才会变成fulfilled,此时,返回值组成一个数组传递给新Promise实例的回调函数
 	> * 当数组中有一个Promise实例被rejected,新Promise实例的状态就变成rejected,此时第一个被reject的实例的返回值会传递给新Promise实例的回调函数
 	 
 	* Promise.race()
 	> * 接受一个Promise实例数组作为参数,返回执行最快的那个promise对象
 	 
 	 
async声明的函数
1. async声明的函数只是把该函数的return包装了,使得无论如何都会返回promise对象(非promise会转化为promise{resolve}),除此之外与普通函数没有不同,没有特殊待遇。/*因此当函数体内有语句错误时,导致运行时不会阻塞当前的线程*/
2. await声明只能用在async函数中。当执行async函数时,遇到await声明,会先将await后面的内容按照'平常的执行规则'执行完,执行完后立马跳出async函数,去执行主线程其他内容,等到主线程执行完再回到await处继续执行后面的内容。
 	//ajax 利用原生XMLHttpRequest函数创建
 	function ajax(method,url,data,fnSucc,fnFaild){
 	// 1.创建一个ajax对象
 	var oAjax = new XMLHttpRequest();
 	//post方法处理
 	if(method.toLowerCase() == 'post'){
 	oAjax.open(method,url,true);
 	//设置请求头,该方法必须在open和send中间调用
 	oAjax.setRequestHeader("Content-type","application/x-www-form-urlencoded");
 	//post发送的数据
 	oAjax.send(data);
 	}else{
 	if(data){
 	url = url+"?"+data;
 	}
 	// 2.用ajax对象建立连接
 	// oAjax.open(请求方法,请求地址,是否异步)
 	oAjax.open(method,url,true);
 	// 3.用ajax对象发送请求
 	oAjax.send();
 	}
 	// 4.用ajax对象接收数据
 	oAjax.onreadystatechange = function(){
 	// console.log(oAjax.readyState);
 	// 0 还没有初始化
 	// 1 已经初始化,但是还没有调用open方法
 	// 2 send方法已经调用
 	// 3 返回了部分数据
 	// 4 数据完全返回
 	if(oAjax.readyState == 4){//请求完成,表明所有的数据已经返回,但并不代表成功
 	if(oAjax.status == 200){//成功
 	fnSucc(oAjax.responseText);
 	}else{//失败
 	if(fnFaild){
 	fnFaild(oAjax.status);
 	}
 	}
 	}
 	}
 	}
 	跨域方案 协议,域名,端口和服务器的协议,域名,端口有一个不一致就会发生跨域
 	 
 	一般浏览器的端口号都是443 一般登录的省略了
 	* CORS(Cross-origin resource sharing)跨域方案
 	 
 	> 服务器端设置响应头
 	res.setHeader("Access-Control-Allow-Origin","*")
 	 
 	> * Access-Control-Allow-Origin设置可以跨域的域名 *代表所有
 	> * 一次只能只能设置一个值
 	 
 	> * 简单请求
 	> * 请求方法必须是 HEAD,GET,POST之一
 	> * 请求头中的字段仅限于 Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type
 	> * Content-Type 的值仅限于application/x-www-form-urlencoded,multipart/form-data,text/plain
 	 
 	* 复杂请求
 	不满足简单请求的时候就是复杂请求,复杂请求会先发一次OPTIONS方法进行预检(preflight)请求
 	 
 	例如设置如下请求头后该请求就会变为复杂请求
 	oAjax.setRequestHeader('abc','abc');
 	需要在服务器端设置如下响应头才能实现请求
 	res.setHeader("Access-Control-Allow-Headers","abc");
 	> Access-Control-Allow-Headers 表示服务端接受的跨域请求的字段
 	 
 	服务器端响应头Access-Control-Expose-Headers
 	> Access-Control-Expose-Headers表示允许客户端通过getResponseHeader方法获取的字段
 	> CORS方式下默认只能获取6个基础字段,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma
 	 
 	ES6文件的模块
 	定义 export default/export
 	引用 import from
 	export跟export default 有什么区别呢?如下:
 	1、export与export default均可用于导出常量、函数、文件、模块等
 	2、你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用
 	3、在一个文件或模块中,export、import可以有多个,export default仅有一个
 	4、通过export方式导出,在导入时要加{ },export default则不需要
 	这样来说其实很多时候export与export default可以实现同样的目的,只是用法有些区别。注意第四条,通过export方式导出,在导入时要加{ },export default则不需要。使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名。
 	var name="李四";
 	export { name } import { name } from "/.a.js"
 	可以写成:
 	var name="李四";
 	export default name import name from "/.a.js" 这里name不需要大括号
 	 
 	ES5文件的模块
 	定义
 	module.exports ={
Home:'xxxxx',
toString(){}
}对象上添加属性导出值
 	exports对象和module.exports对象是同一个对象,导出的始终是module.exports指向的对象
 	引用
var xxx=require('文件名'),执行对应的文件并且返回该文件对应的modeule.exports对象
 	 xxx.Home/xxx.toString()
 	>* ES5和ES6文件模块混用也能用
 	 
 	 
 	 
 	本地存储
 	cookie的设置
 	document.cookie = 'key1=value1';
 	document.cookie = 'key2=value2';
 	 
 	cookie有效期的设置
 	var oDate = new Date();
 	oDate.setDate(oDate.getDate() + 14);
 	document.cookie = "name=Tom;expires="+oDate;
 	 
 	cookie的特点:
 	>* cookie是document对象上的一个属性
 	>* cookie的大小限制是4k
 	>* cookie会存在于请求头中
 	>*主域名中的cookie会在子域名中存在
 	 
 	Storage
 	localStorage 和 sessionStorage的api相同
 	 
 	设置 window.localStorage.setItem('username',value)
 	获取 getItem(key)
 	删除 removeItem(key)
 	清除所有 clear()
 	内容个数 length
 	获取key的值 key(num)
 	 
 	localStorage 和 sessionStorage的存储时效不同
 	>* localStorage 持久化
 	>* sessionStorage 网页会话结束失效
 	 
 	localStorage 和 sessionStorage的存储容量不同
 	>* localStorage 2-5Mb左右
 	>* sessionStorage 2-10Mb左右,部分浏览器 没有限制
 	 
 	>* Storage仅能存储字符串
 	>* Storage的数据不能在不同的域中共享
 	 
 	Buffer是用来存放二进制数据的容器
 	 
 	stream流是一种处理数据的抽象接口,是将数据分割成一段一段的来处理,提高效率
 	 
 	fs读写文件的模块
 	 
 	http模块 http.createServer((req,res)=>{}) 创建一个服务器实例
 	req 它实现了 可读流 接口
 	res 它实现了 可写流 接口
 	 
 	querystring模块
 	字符串转obj
 	querystring.parse(带&的字符串)
 	 
 	path模块
 	path.normalize(path)//规范路径
 	path.extname(path)//获取文件名后缀 如.jpg
 	 
 	url模块
 	req.url地址为www.127.0.0.1:3000/user/load/xxx.html?abc=123&ddd=444
 	pathname = url.parse(req.url,true).pathname;//为 /user/load/xxx.html
 	query = url.parse(req.url,true).query; //{abc:123,ddd:444
 	 
 	SQL数据库
 	Oracle ,SQL Server,DB2,Sybase
 	MySQL,PostgreSQL,sqlite
 	NoSQL(not only sql)数据库
 	MongoDB
 	CouchDB
 	HBase
 	Redis
 	SQL数据库结构化,适合中大型系统
 	NoSQL数据库数据模型比较简单,但操作比较灵活,适合微架构
 	SQL数据库和NoSQL数据库不是二选一的关系,而是相互辅助和补充的关系
 	 
 	$ pm2 logs 显示所有进程日志
 	$ pm2 stop all 停止所有进程
 	$ pm2 restart all 重启所有进程
 	$ pm2 reload all 0秒停机重载进程 (用于 NETWORKED 进程)
 	$ pm2 stop 0 停止指定的进程
 	$ pm2 restart 0 重启指定的进程
 	$ pm2 startup 产生 init 脚本 保持进程活着
 	$ pm2 web 运行健壮的 computer API endpoint (http://localhost:9615)
 	$ pm2 delete 0 杀死指定的进程
 	$ pm2 delete all 杀死全部进程
 	 
 	运行进程的不同方式:
 	$ pm2 start app.js -i max 根据有效CPU数目启动最大进程数目
 	$ pm2 start app.js -i 3 启动3个进程
 	$ pm2 start app.js -x 用fork模式启动 app.js 而不是使用 cluster
 	$ pm2 start app.js -x -- -a 23 用fork模式启动 app.js 并且传递参数 (-a 23)
 	$ pm2 start app.js --name serverone 启动一个进程并把它命名为 serverone
 	$ pm2 stop serverone 停止 serverone 进程
 	$ pm2 start app.json 启动进程, 在 app.json里设置选项
 	$ pm2 start app.js -i max -- -a 23 在--之后给 app.js 传递参数
 	$ pm2 start app.js -i max -e err.log -o out.log 启动 并 生成一个配置文件
                    
                
                
            
        
浙公网安备 33010602011771号