难点
Function.prototype.bind.apply(Date, [Date].concat(Array.prototype.slice.call(arguments)))= Date(arguments)function.toString() //返回函数内容复制代码
/* [] --> "", {} --> "[object object]" 字符串+字符串,拼接得 */[] + {} // "[object object]""/* {}被识别为代码块, 剩下+[] --> +"" --> 0 */{} + [] //0复制代码
- 判断类型:
typeof //判断基本类型Object.prototype.toString.call() //判断对象类型复制代码
- 字符串剪切
slice(start,end) //返回不包括end的新字符串substring(start,end) //包括end的新字符串substr(start,length) //返回start开始length长度新字符串复制代码
技巧
防抖:
let timer = null;function throttle(fn,delay,...args){ _self = this; return function(){ if(timer) clearTimeout(timer); timer = setTimeout(function(){ fn.apply(_self,args); },delay); }}复制代码
节流: 方式一:
let isExcute = true;function throttle(fn,delay,...args){ let _self = this; if(isExcute === true) return function(){ isExcute = false; timer = setTimeout( () => { isExcute = true; fn.apply(_self,args); },delay); }}复制代码
方式二:
let timeCache = 0;function throttle(fn,delay,...args){ let _self = this; let time = Date.now(); if(time - timeCache > delay) return function(){ timeCache = time; setTimeout(() => { fn.apply(_self,args); },delay); }}复制代码
类型转换
- 显式强制类型转换
- Number() --> number
- Boolean(): (null, undefined, false, "", NaN, +0、-0) -->false 其他为true。
- !!val --> boolean, +val --> number, val+"" --> string
- 隐式强制类型转换
-
if
,while
,for
,会隐式强制转换
-
==
比较
- 2.1 boolean与其它基本类型比较,会转换成数字,即
true
--> 1, 'false' --> 0 - 2.2 string与数字比较,会转换成数字。
- 2.3 对象(包括包装对象)先用
valueOf
转换成基本类型值,如果没有valueOf
则toString
返回的值再与其他 基本类型的值比较,如果都没有则返回TypeError
- 全局
isNaN()
遇到非数字和NaN都会返回false, 所以该用Number.isNaN()
方法
编译阶段确定作用域
词法作用域
无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置所决定。
var a=4;function baz(){ console.log(a);}(function foo() { var a=2; function bar(){ console.log(a); } console.log(a); //2 bar(); //2 baz(); //4})();复制代码
执行上下文
函数被调用时便会创建执行上下文,创建执行上下文分为两个阶段:
一、创建阶段
执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向。
graph LR当前执行上下文-->变量对象VO当前执行上下文-->作用域链ScopeChain(非包含关系)当前执行上下文-->this复制代码
创建变量对象流程
- 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。
- 检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
- 检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。
变量提升
- function 的「创建」「初始化」和「赋值」都被提升了。
- var 的「创建」和「初始化」都被提升了。
- let 的「创建」过程被提升了,但是「初始化」没有提升。
- const 只有「创建」和「初始化」,没有「赋值」过程。
- var
function test() { console.log(a); //undefined var a = 1;}复制代码
var
a 创建并初始化成undefined
,遇到var a = 1
赋值为1
- let, const
(function(){ console.log(a); let a = 2; // ReferenceError: a is undefined const b = 3;})();复制代码
let
a创建但未初始化,所以有临时性死区,直到let a = 2
语句才初始化为undefined
且赋值为2 const
b创建且初始化成3,但没赋值
创建作用域链
根据该函数所引用的变量,如果在该作用域找不到引用变量,便会到上层作用域查找,由此建立起作用域链。
闭包
闭包指一个封闭作用域(()通常为一个函数),能在外部通过它的内部函数访问该作用域的变量。闭包只在访问
确定this指向
var a = 20;var obj = { a: 10, c: this.a + 20, fn: function () { return this.a; }}var fn=obj.fn;console.log(obj.c); //40console.log(obj.fn()); //10console.log(fn()); //20 引用同一函数,但单独引用指向window或undefined复制代码
二、执行阶段
创建完成之后,就会开始执行代码,这个时候,会完成变量赋值,函数引用,以及执行其他代码。
函数调用栈Call Stack
function greeting() { // [1] Some codes here sayHi(); // [2] Some codes here}function sayHi() { return "Hi!";}// Invoke the `greeting` functiongreeting();复制代码
- 遇到
greeting();
,便会将函数greeting
推入Call Stack
栈顶,执行greeting
函数内的代码。 - 直到遇到
sayHi();
,便会将sayHi
推入栈,执行sayHi
函数内的代码,执行完毕后便将sayHi
推出栈,继续执行greeting
剩余的代码。 - 执行完毕后将
greeting
推出栈。
事件循环 Event Loop
task queue
将函数推入Call Stack
,函数执行时遇到异步的推进job queue
,等Call Stack
清空了,再将job queue
依次推入Call Stack
。则完成一轮循环。
语句:
continue和break
foo:for(var i=0;i<5;i++){ for(var j=0;j>i;j++) { if (/*...*/) break foo; //跳出foo循环 else continue; //没标签,继续该循环的下一轮循环 } if (/*...*/) break foo; else continue foo;}复制代码
continue
执行标记所在循环的下一轮循环。
break
跳出标记所在循环。 原型和继承
graph LR[继承]-->A[不使用Object create]A-->[原型链继承]-->|组合为|E[组合继承]A-->[构造函数继承]C-->|组合为|E[组合继承]D-->|组合为|EE-->F[寄生组合继承]继承-->B[使用Object create]复制代码
new运算符流程
- 创建一个新对象,新对象的
[[prototype]]
(或__proto__
)指针指向构造函数的prototype
(constructor
属性在构造函数的prototype
上) - 将构造函数的作用域赋给新对象(
this
绑定到新对象) - 执行构造函数代码(为新对象添加属性)
- 返回新对象
原型链继承
function SuperFunc(){ /*...*/}function SubFunc(){ /*...*/}SubFunc.prototype = new SuperFunc();SubFunc.prototype.constructor = SubFunc;var instance = new SubFunc();复制代码
优点:引用的方法能够复用 缺点:不能传递参数
构造函数继承
function SuperFunc(){ /*...*/}function SubFunc(){SuperFunc.call(this)}var instance = new SubFunc();复制代码
优点:父类引用属性不会共享,能传递参数 缺点:父类方法不能复用
组合继承
function SuperFunc(){ /*...*/}Super.prototype.method = function(){ /*...*/};function SubFunc(){SuperFunc.call(this)}SubFunc.prototype=new SuperFunc();SubFunc.prototype.method = function(){ /*...*/};var instance = new SubFunc();复制代码
优点:父类方法能够共享复用,引用属性不会共享 缺点:调用了两次SuperFunc构造函数,造成多余性能消耗
原型式继承
基于一个已有对象创建新对象
function cloneObj(obj){ function Func{} Func.prototype = obj; return new Func();}var clone = cloneObj(proto); /*clone.__proto__ == Func.prototype == proto */Object.create(obj, prop) /* 可加prop*/复制代码
寄生式继承
在原型继承基础增加属性或方法
function inherit(obj){ var clone = cloneObj(obj); clone.method = function(){}; return clone;}var clone = inherit(prototype);复制代码
寄生组合继承
function cloneObj(obj){ function Func{} Func.prototype = obj; return new Func();}function inherit(SubFunc,SuperFunc){ var prototype = cloneObj(SuperFunc.prototype); /*prototype.__proto__ == SuperFunc.prototype*/ prototype.constructor = SubFunc; SubFunc.prototype = prototype; /* SubFunc.prototype.__proto__==SuperFunc.prototype */}function SuperFunc(){ this.prop = something;}SuperFunc.prototype.method = function(){};function SubFunc(){ SuperFunc.call(this); this.anotherProp = something;}inherit(SubFunc,SuperFunc);SubFunc.prototype.anotherMethod = function(){};var instance = new SubFunc();复制代码
与原型链相关API总结
- prototypeObj.isPrototypeOf(obj); //调用对象是否在obj原型链上- obj instanceof constructor; //constructor.prototype是否存在调用对象的原型链上- Object.getPrototypeOf(obj); //返回obj对象的[[prototype]](或__proto__)属性。ES6中,如果obj不是对象,则强制转为对象。- Object.setPrototypeOf(obj, thePrototype); //设置obj的[[prototype]](或__proto__)属性为thePrototype- obj.hasOwnProperty(prop); //如果prop为自身属性,返回true- in //包含原型链上的字符串属性或symbol属性,则返回true复制代码
DOM相关:
DOM对象继承链: EventTarget --> Node --> document/Element/Attribute/...
html/body/frame api:
window.document //返回对当前窗体所引用的document的引用window.frameElement //返回嵌入的窗体比如
node
node属性
node.childNodes //包含全部子元素的数组(包含空字符文本节点和没标签括起来的文本节点)node.children //只包含标签节点/*以上返回即时更新的nodelist对象 (可能需要缓存)。*/node.firstchild = node.childNodes[0]node.lastchildnode.parentNodenode.previousSiblingnode.nextSiblingnode.nodeType //节点属性类型 1.元素节点2.属性节点3.文本节点node.nodeName //如果是元素节点则nodeName==tagName复制代码
node方法
parentNode.appendChild(childNode); return childNode //在父元素末尾插入子元素parentNode.removeChild(childNode); return childNodeparentNode.replaceChild(newChild,oldChild); //new取代oldparentNode.contains(childNode); return boolean//parentNode是否包含childNodeparentNode.insertBefore(insertEl,targetEl); return insertEl//在目标元素前面插入要插入的元素复制代码
document
document方法
document.getElementsByTagName(tagName);document.getElementsByClassName(className);document.getElementsByName(name); //name属性document.getElementById(id);document.querySelectorAll(selector) //返回non-live的nodelistdocument.querySelector(selector)document.createElement(tagName); //创建元素节点,比如divdocument.createTextNode(textValue); //创建文本节点复制代码
element
element属性
element.idelement.tagNameelement.className //空格隔开的类名element.innerHTML //元素内部内容element.outerHTML //包含元素本身的内容 element.textContent //元素内所有节点及子节点的文本内容(无论有无标签)复制代码
element方法
element.hasAttribute('attr'); return booleanelement.getAttribute('attr'); return string:value of attrelement.setAttribute('attr','value');element.removeAttribute('attr','value');复制代码
CSS/样式相关:
获取样式
element.style.styleName //内联样式,style属性设置的css属性,驼峰样式window.getComputedStyle(element[,null或者伪类]) //实时改变。权威指南P432复制代码
元素边长/高/宽:
/*以下都是返回long int num类型*/element.clientLeft/Top //元素左/上border大小element.scrollLeft/Top //出现滚动条时,左/上方向已滚动的像素,否则为0element.offsetWidth //元素可视区域padding+width+borderelement.clientWidth //元素可视区域padding+widthelement.scrollWidth //元素实际大小padding+width/*以下返回double float num类型*/element.getBoundingClientRect().width //实际渲染可视的宽度(content+padding)复制代码
事件对象相对位置
MouseEvent.clientX //相对窗口的x坐标 MouseEvent.offsetX //事件对象与目标节点的内padding的x偏移量 MouseEvent.pageX //相对文档页面x边缘的偏移量MouseEvent.screenX //相对屏幕x边缘的偏移量复制代码
事件相关
dataTransfer
event.dataTransfer.effectAllowed = type; //none、copy、move、link、linkMove、copyLink、copyMove、all默认为all,设置在源对象dragstart事件上,其他事件无效,dragenter和dragover的值将等于dragstart的值event.dataTransfer.dropEffect = type; //none、copy、move、link目标对象的操作,可定义在drop,dragenter,dragover事件上复制代码
- 如果
effectAllowed
属性是定为none
,则不允许拖放元素。 - 如果
dropEffect
属性设定为none
,则不允许被拖放到目标元素中。 - 如果
effectAllowed
属性设定为all
或不设定,则dropEffect
属性允许被设定为任何值。并且按指定的效果显示。 - 如果
effectAllowed
属性设定为具体的效果,dropEffect
属性也设定了具体视觉效果,则两个具体效果之必须完全相等,否则不允许将被拖放元素拖放到目标元素中。
IO:
XMLHttpRequest(ajax):
//创建XHR对象var xhr=new XMLHttpRequest();//发送请求xhr.open("get"/"post",URL[,false/true]); //true异步xhr.responseType = type; //""(默认,字符串)、"ArrayBuffer"、"blob"、"document""json"、"text"(字符串)xhr.withCredentials = true; //跨源时true为可以发送凭据(cookie、HTTP认证及客户端SSL证明等)xhr.send([request data]);//接收回应/* responseText 响应文本 responseXML 响应XML DOM文档 status 响应HTTP状态 statusText 响应HTTP状态内容 readyState 请求/响应过程的当前活动阶段: (0:未调用open 1:已调用open,未send 2:已send,未收到回应 3:开始接收回应 4:完成接受回应)*///服务器回应成功xhr.onreadystatechange = function(){ if(xhr.readyState == 4 && xhr.status == 200){ console.log(xhr.responseText); } else{ console.log("no response!!"); }}//收到回应前取消异步请求xhr.abort();复制代码
坑
当xhr.withCredentials = true
时,服务端的Access-allow-control-origin
不能设置为'*'
FormData
可通过xhr.send()
异步发送二进制文件
var data = new FormData([formElement]);data.append(DOMString name,DOMString/Blob/File value[,filename]); //插入键值对,value可为DOM String、Blob或File对象(File继承于Blob)复制代码
FileReader
可异步读取指定的blob
或Files
对象
var reader = new FileReader();复制代码
属性
error
:读取时的异常
onload
:完成readystate
: 常量名 |值| 描述EMPTY |0| 还没有加载任何数据.LOADING |1| 数据正在被加载.DONE |2| 已完成全部的读取请求.复制代码
result
:操作完成时的文件内容
方法
readyAsArrayBuffer(blob)
:启动读取,result
包含ArrayBuffer对象
readyAsDataURL(blob)
:启动读取,result
包含DataURL(Base64编码)字符串readyAsText(blob[, encoding /*编码方式*/ ])
:启动读取,根据特殊的编码方式转化为字符串 SSE(服务器发送):
var source = new EventSource("URL");source.onmessage=function(){ //data的数据后有空行才触发onmessage var data=event.data;}source.close(); //断开连接不重新链接复制代码
WebSockets:
var sockets= new WebSocket("URL" /* ws://或者'wss:// */); //绝对URLsocket.send("str")//只能发送纯文本//接收消息socket.onmessage=function(event){ vara data=event.data;}//另外3个事件open:成功链接触发error:错误。通信不能持续 //event额外有三个属性wasClean,code状态码,reason服务器信息close 连接关闭时触发复制代码
Web Worker
页面里:
var worker=new Worker("xx.js");//发送数据worker.postMessage("data"); //可传递任何对象数据);//错误worker.onerror = function(err){ err.filename //错误文件名 ,err.lineno //错误行号 ,err.message //完整错误信息}//接收Worker发来数据复制代码
worker.onmessage=function(){ var data=event.data;};//停止工作worker.terminate();复制代码
Worker里
//接收数据self.onmessage=function(){ var data=event.data;};//发数据到页面self.postMessage();self.close(); //Worker内部停止工作,跟terminate一样。复制代码
Canvas
绘制
var canvas = canvasElement.getContext("2d"); //生成画布canvas.fillStyle=""; //填充样式canvas.fillRect(dx,dy,width,height); //填充矩形canvas.strokeRect(dx,dy,dWidth,dhHeight); //描边矩形canvas.drawImage(image,dx,dy); //源图片canvas.drawImage(image,dx,dy,dWidth,dHeight);canvas.drawImage(image,sx,sy,sWidth,sHeight,dx,dy,dWidth,dHeight);复制代码
image
:
绘制到上下文的元素。允许任何的canvas
图像源(CanvasImageSource),例如:HTMLImageElement
,HTMLVideoElement
或HTMLCanvasElement
。
var image = new Image();imgae.src='...';复制代码
dx
: 目标画布在目标canvas上X轴的位置。dy
: 目标画布在目标canvas上Y轴的位置。dwidth
: 在目标画布上绘制图像的宽度dheight
: 在目标画布上绘制图像的高度sx
: 源图像矩形选择框的左上角x坐标sy
: 源图像矩形选择框的左上角y坐标sWidth
: 源图像选择框宽度sHeight
: 源图像选择框高度
转换
var canvas = canvasElement.getContext("2d"); //生成画布canvas.toBlob(callback(blob/*转换的blob对象*/)[, type/*图片格式,如image/png*/][,encoderOptions/*图片格式为image/jpg、image/webp时指定图片质量,值为0-1*/]);canvas.toDataURL([type][, encoderOptions]); //返回包含dataURI的DOMString复制代码
正则
reg.prototype.exec()
- 如果匹配到则始终返回第一个匹配到的文本,如果有括号匹配的则放在后面,否则返回null
- 如果
reg
对象是全局查找(/g),则每次迭代exec都会另reg
的lastIndex属性更新。
var reg1 = /abc/;var reg2 = /abc/g;var reg3 = /a(bc)/;var reg4 = /a(b)(c)/;var reg5 = /a(bc)/g;var str = "3abc4,5abc6";console.log(reg.exec(str));console.log(reg2.exec(str));console.log(reg3.exec(str));console.log(reg4.exec(str));console.log(reg5.exec(str));["abc", index: 1, input: "3abc4,5abc6", groups: undefined]["abc", index: 1, input: "3abc4,5abc6", groups: undefined]["abc", "bc", index: 1, input: "3abc4,5abc6", groups: undefined]["abc", "b","c", index: 1, input: "3abc4,5abc6", groups: undefined]["abc", "bc", index: 1, input: "3abc4,5abc6", groups: undefined]复制代码
2.str.prototype.match()
不是全局则跟exec一样,全局则返回所有匹配到的文本
var reg = /abc/;var reg2 = /abc/g;var reg3 = /a(bc)/;var reg4 = /a(bc)/g;var str = "3abc4,5abc6";console.log(str.match(reg));console.log(str.match(reg2));console.log(str.match(reg3));console.log(str.match(reg4));VM180:6 ["abc", index: 1, input: "3abc4,5abc6", groups: undefined]VM180:7 (2) ["abc", "abc"]VM180:8 (2) ["abc", "bc", index: 1, input: "3abc4,5abc6", groups: undefined]VM180:9 (2) ["abc", "abc"]复制代码