《javascript高级程序设计》核心知识总结

您所在的位置:网站首页 js高级教程第四版 《javascript高级程序设计》核心知识总结

《javascript高级程序设计》核心知识总结

2024-01-04 00:46| 来源: 网络整理| 查看: 265

此文是对js高级程序设计一书难点的总结,也是笔者在看了3遍之后的一些梳理和感想,希望能借此巩固js的基础和对一些核心概念有更深入的了解。

摘要 js基本的数据类型和关键点 变量,作用域和内存问题 垃圾回收机制 面向对象的程序设计 实现类与继承的经典方式 BOM和DOM对象 DOM扩展与高级API介绍 高级编程技巧 跨文档消息传递和ajax封装 web worker基本实现与demo 一. Number类型关键点讲解 1.进制问题 八进制字面量在严格模式下无效,会导致支持该模式的js引擎抛出异常 十六进制字面量的前两位必须是0x,后根任何十六进制数字(0-9及A-F) 在进行算术计算时,所有以八进制和十六进制表示的数值最终将被转换成十进制数值 2.浮点数注意点

浮点数值的最高精度是17位小数,但在进行算术计算时精度远远不如整数。例如 0.1 + 0.2 === 0.300000000000004(大致这个意思,具体多少个零请实际计算) 所以永远不要测试某个特定的浮点数值

3.数值 使用isFinite(num)来确定一个数字是否有穷 ECMAScript能够表示的最小值保存在变量 Number.MIN_VALUE 中,最大值保存在 Number.MAX_VALUE 中。 NaN表示非数值。在ECMAScript中,任何数值除以非数值会返回NaN,因此不会影响其他代码的执行。 isNaN()用来确定传入的参数是否为"非数值"。会对参数进行转化,不能被转化为数值的则返回true。 4.数值转换

parseFloat主要用于解析有效的浮点数字,始终会忽略前导的零,可识别所有的浮点数格式,但是十六进制格式的字符串始终会被转换成零。

二. 字符串 1. toString() 转换为字符串 let num = 10; num.toString(n) n表示进制,可选,如2,8,10,16 三.循环 1. break和continue break语句会立即退出循环,强制执行循环后面的语句 continue语句是退出当前循环,继续执行下一循环 // 结合label,更精确的控制循环 outerMost: for(var i=0;i name return o } 3.继承(原型链是实现继承的主要方式) 1.原型链的问题 1.包含引用类型值的原型属性会被所有实例共享,在通过原型实现继承时,原型实际上会变成另一个类型的实例,原先的实例属性变成了现在的原型属性。 2.在创建子类型的实例时,无法向父类构造函数传递参数 2.借用构造函数(在子类型构造函数的内部调用父类构造函数) //此时实例不会共享属性 function Parent(name){ this.colors = [1,3,4]; this.name = name; } function Child(name){ Parent.call(this, name); this.age = 12; } // 存在的问题: 1.函数无法复用 2.父类的原型对于子类是不可见的 3.组合继承(使用原型链继承原型属性和方法,使用借用构造继承实例属性) ---最常用的继承模式 缺点:无论如何都会调用两次父类构造函数 // 父类 function Parent(name){ this.name = "xujaing"; this.age = 12; }; Parent.prototype.say = function() { console.log(this.age) }; // 子类继承父类 function Child(name){ Parent.call(this, name); this.age = 13; } Child.prototype = new Parent(); Child.prototype.constructor = Child; Child.prototype.say = function() { alert(this.age) }; 4.原型式继承 实现1. function object(o){ function F(){}; F.prototype = o; return new F() } 实现2.通过Object.create(prototype, properties) // 第一个参数为创建新对象原型的对象,第二个参数为对新对象定义额外属性的对象(和defineProperties方法的第二个参数格式相同) Object.create(person, { name: { value: "xujiang" } }) 5.寄生组合式继承(通过借用构造函数继承属性,通过原型链混成的方式继承方法)---最理想的继承范式 function inheritPrototype(sub,sup){ let prototype = Object.create(sup.prototype); prototype.constructor = sub; sub.prototype = prototype; } function Sup(){} Sup.prototype.say = function(){} function Sub(arg){ // 关键 Sup.call(this,arg); } // 关键 inheritPrototype(Sub, Sup); 七.函数表达式 闭包与变量 闭包只能取得包含函数中任何变量的最后一个值 解决方案 function createFunction(){ let arr = []; for(let i=0; i< 10; i++){ arr[i] = function(num){ return num }(i) } return arr } this对象

在全局函数中,this等于window,而当函数被当作某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window

(object.say = object.say)() 此时函数内部this指向window,因为该赋值表达式的值是函数本身,所以this的值不能得到维持

内存泄漏 1.如果闭包的作用域链中保存着一个html元素,那就意味着该元素永远无法销毁。 2.闭包会引用包含函数的整个活动对象,而其中包含着html,因此有必要把其设置为null function a(){ let el = $("#el"); let id = el.id; el.click(function(){ alert(id) }) // 清空dom,释放内存 el = null; } 八.BOM对象 1.window BOM的核心对象是window,他表示浏览器的一个实例。 全局变量不能通过delete操作符删除,而直接定义在window对象上的属性可以删除 2.窗口位相关属性

窗口位置(不同浏览器实现不一样,所以位置获取的不精确和统一)

let leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX; let top = (typeof window.screenTop == "number") ? window.screenTop : window.screenY; // 获取页面视口 let pageWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 3.系统对话框 // 显示打印对话框 window.print() 4.location对象 // location即是window对象的属性也是document对象的属性 1. hash // "#contents" 返回url的hash,如果不包含返回空 2. host // "www.wrox.com:80" 返回服务器名称和和端口号 3. hostname // "www.wrox.com" 返回不带端口号的服务器名称 4. href // 返回当前加载页面的完整url 5. pathname // "/a/" 返回url中的目录或文件名 6. port // "8080" 返回url中指定的端口号 7. protocol // "http" 返回页面使用的协议 8. search // "?q=java" 返回url中查询字符串,以问号开头 // 获取查询字符串 function queryObj(){ let qs = (location.search.length > 0 ? location.search.substring(1) : ''), arg = {}, items = qs.length ? qs.split('&') : [], item = null, name = null, value = null, i = 0, len = items.length; for(i;i -1; system.ipod = ua.indexOf("iPod") > -1; system.ipad = ua.indexOf("ipad") > -1; system.nokiaN = ua.indexOf("NokiaN") > -1; // windows mobile if (system.win == "CE") { system.winMobile = system.win; } else if (system.win == "Ph") { if (/Windows Phone OS (\d+.\d+)/.test(ua)) { system.win = "Phone"; system.winMobile = parseFloat(RegExp["$1"]); } } // 检测ios版本 if (system.mac && ua.indexOf("Mobile") > -1) { if (/CPU (?:iphone)?OS (/d+_\d+)/.test(ua)) { system.ios = parseFloat(RegExp.$1.replace("_", ".")); } else { system.ios = 2; //不能正确检测出来,只能猜测 } } // 检测android if (/Android (\d+\.\d+)/.test(ua)) { system.android = parsentFloat(RegExp.$1); } // 游戏系统 system.wii = ua.indexOf("Wii") > -1; system.ps = /playstation/i.test(ua); // 返回检测对象 return { engine: engine, browser: browser, system: system } }(); 十. DOM 1.将NodeList对象转换为数组 let arrayNodes = Array.prototype.slice.call(someNode.childNodes, 0); 2.hasChildNodes() ---在节点包含一或多个子节点的情况下返回true 3.操作节点 1.appendChild() //用于向childNodes末尾添加一个节点,返回新增的节点,如果节点已存在,那么就是从原来的位置移动到新位置 2.insertBefore() //将节点插入指定位置,接收两个参数,要插入的节点和作为参照的节点,返回插入的节点 3.replaceChild() //替换指定节点,接收2个参数,要插入的节点和要替换的节点,返回被移除的节点 4.removeChild() //移除节点,返回被移除的节点 5.cloneNode([true]) //参数为true,执行深复制,复制节点及整个子节点,为false时复制节点本身。cloneNode不会复制节点的javascript属性,但IE在此存在一个bug,所以建议在复制之前最好先移除事件处理程序 4.访问节点 Node.firstChild[lastChild | parentChild | nextSibling | previousSibling] 5.Document类型 1. document的节点类型nodeType的值为9; 2. document.documentElement // 取得对的引用 3. document.body // 取得对body的引用 4. document.title // 取得文章标题 5. document.title = "xxx" //设置文章标题 6. document.URL //取得完整的url 7. document.domain //取得域名 8. document.referrer //取得来源页面的url 6.Element类型 1.nodeType值为:1 2.nodeName的值为元素标签名 3.tagName // 元素标签名,返回大写值,比较时一般采用 element.tagName.toLowerCase() 4.取得元素属性 getAttribute() / setAttribute() / removeAttribute() // 注:自定义属性通过点语法访问时会返回undefined 5.attributes // 获取元素的属性集合,访问方法: element.attributes[i].nodeName / element.attributes[i].nodeValue 6.创建元素 // document.createElement("div" | "aaa") 7.创建文本子节点 // document.createTextNode("Hello world") 7.DocumentFragment类型 1.nodeType值为:11 2.创建文档片段 document.createDocumentFragment() // let fragment = document.createDocumentFragment() 十一.DOM扩展 1.选择符 querySelector() // 参数为css选择符,返回与该模式匹配的第一个元素,没有找到返回null querySelectorAll() // 返回所有匹配的元素,底层实现类似于一组元素的快照 2.元素遍历(不包含文本节点和注释) // ie9+支持 1.childElementCount // 返回子元素的个数 2.firstElementChild // 指向第一个子元素 3.lastElementChild // 指向最后一个子元素 4.previousElementSibling // 指向前一个同辈元素 5.nextElementSibling // 指向后一个同辈元素 3.与类相关的扩充 classList 1.classList.length // 返回包含元素的个数 2.classList.remove() //接收一个类名,从列表中删除给定类名 3.classList.toggle() //如果列表中存在给定的值,删除它,否则添加它 4.classList.add() //将给定的字符串添加到列表中,如果已经存在,就不添加 5.classList.contains() //表明列表中是否存在给定的值,存在则返回true,否则返回false 4.焦点管理

元素获得焦点的方式有: 页面加载,用户输入,在代码中调用focus

1.document.activeElement //始终会引用dom中获得焦点的元素,文档刚刚加载完成时,保存的是document.body元素的引用,文档加载期间的值为null 2.document.hasFocus() //用于确定文档是否获得了焦点,是则返回true 5.HTMLDocument的变化 readyState属性 1.loading //正在加载文档,可以在onload外使用 2.complete //文档加载完毕。只能在onload内获取 // 例子 if(document.readyState == "complete") { // 执行操作 } 6.插入标记 insertAdjacentHTML() // 1.作为前一个同辈元素被插入 el.insertAdjacentHTML('beforebegin', '

hello world

'); // 2.作为第一个子元素被插入 el.insertAdjacentHTML('afterbegin', '

hello world

'); // 3.作为最后一个子元素被插入 el.insertAdjacentHTML('beforeend', '

hello world

'); // 4.作为后一个同辈元素被插入 el.insertAdjacentHTML('afterend', '

hello world

'); 7.children // 获取元素集合,只包含元素节点 el.children.length | el.children[i] 8.contains() 判断某个节点是否是另一个节点的后代 // 例子 parentEl.contains(childEl); // 如果childEl是parentEl的后代,则返回true 十二.DOM2和DOM3 1.框架的变化 // 访问内联框架的文档对象,如果内联框架来自不同域或者不同协议,访问该文档时会报错 let iframe = document.getElementById("iframe"); let iframeDoc = iframe.contentDocument || iframe.contentWindow.document; 2.元素大小 1.偏移量 1.offsetHeight/offsetWidth // 元素宽高,包括滚动条,边框 2.offsetLeft/offsetTop // 元素外边框到包含元素内边框的距离 3.offsetParent //保存着包含元素的引用(具有大小的包含元素的引用) // 获取元素在页面中的偏移量 function getElLeft(el){ let actualLeft = el.offsetLeft; let current = el.offsetParent; while(current !== null){ actualLeft += current.offsetLeft; current = current.offsetParent; } return actualLeft } // 注: 这些偏移量都是只读的,每次访问都要重新计算,因此最好将其保存到局部变量里,以提高性能 2.客户区大小clientWidth/clientHeight(元素内容及内边距所占据的空间) 获取视口大小 clientW = document.body.clientWidth || document.documentElement.clientWidth; 3.滚动区大小 1.scrollHeight //在没有滚动条的情况下,元素内容总高度(内容+内边距) 2.scrollWidth 3.scrollLeft //被隐藏在内容区域左侧的像素数 4.scrollTop //被隐藏在内容区域上方的像素数,通过设置该值可以让滚动条滚动到响应位置 *** 确定文档总高度兼容方案 let scrollH = document.documentElement.scrollHeight || document.body.scrollHeight; let clientH = document.documentElement.clientHeight || document.body.clientHeight; let docHeight = Math.max(scrollH, clientH); 4.确定元素大小 getBoundingClientRect() 该方法返回一个矩形对象,包括left,top,right,bottom属性,表示元素在页面中相对于视口的位置 十三.事件 1.事件对象(event) 1. 属性或方法 type // 被触发的事件类型 target // 事件的目标 currentTarget // 事件处理程序当前正在处理事件的那个元素 注: 在事件处理程序内部,对象this始终等于currentTarget的值,而target只包含事件的实际目标 *** 一个函数处理多个事件可以使用switch(event.type)的方式 event.preventDefault() // 阻止事件的默认行为 event.stopPropagation() // 阻止事件冒泡 2.事件类型 1.鼠标和滚轮事件 1.客户区坐标位置clientX/clientY //表示事件发生时鼠标指针在视口中的水平和垂直位置 2.页面坐标位置 pageX/pageY //表示事件在页面中发生的位置 3.屏幕坐标位置 //获取事件发生时在屏幕中的位置 2.修改键(如果用户在触发事件时按下了shift/ctrl/alt/Meta,则返回true) event.shiftkey | event.altKey | eventaKey | event.ctrlKey 3.鼠标按钮(event.button) // 对于mousedown和mouseup,其event中存在一个button属性,值为0表示主鼠标按钮,1表示中间鼠标按钮,2表示次鼠标按钮 4.鼠标滚轮事件(mousewheel) 1.兼容方案: let getWheelDelta = function(event){ let wheelDelta = event.wheelDelta ? event.wheelDelta : (-event.detail * 40); return wheelDelta } *** 注:document在普通浏览器中通过mousewheel监听鼠标滚轮事件,在火狐中使用DOMMouseScroll监听 5.键盘与文本事件 6.变动事件 1.DOMSubtreeModified | DOMNodeInserted | DOMNodeRemoved *例子 el.addEvent("DOMSubtreeModified", fn1) 7.HTML5事件 1.contextmenu事件(自定义上下文菜单) 2.DOMContentLoaded事件(在形成完整dom树之后就触发,不理会图像,js文件,css文件等资源是否下载完成) 3.hashchange事件(在URL的参数列表发生变化【即#号后面的所有字符串】时触发) 注:必须要把hashchange添加给window对象,event对象包含两个属性oldURL和newURL,分别保存着参数列表变化前后的完整URL // 例子 window.addEvent("hashchange", function(event){ // oldURL和newURL存在兼容问题,最好用location.hash代替 console.log(event.oldURL, event.newURL); }) 3.性能与内存

如果在页面写在之前没有清理干净事件处理程序,那他们就会滞留在内存中,每次加载完页面再卸载时,内存中滞留的对象就会增加,因为事件处理程序占用的内存并没有被释放。 【解决方案】再页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。但是使用onunload时页面不会被缓存bfcache(即往返缓存)中。

十四.表单脚本 1.选择文本inputEl.select() [用于选择文本框中的所有文本,不接受参数,可以在任何时候调用] 2.选择事件(select) //ie9+ 用户选择了文本并释放鼠标时触发 3.取得选择的文本 // ie9+ 为被选择的元素添加了两个属性,selectionStart和selectionEnd,保存的是基于零的数值,表示所选的文本范围 function getSelectedText(textbox){ return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd) } 4.选择部分文本 // 所有文本框都有一个setSelectionRange(startIndex, endIndex) textbox.setSelectionRange(0, 3) 5.过滤输入 1.屏蔽字符 // 通过阻止键盘按压事件的默认行为来屏蔽字符 el.addEvent("keypress",function(event){ let charCode = event.charCode; // String.fromCharCode(charCode) 将字符编码转换为字符串 if(!/\d/.test(String.fromCharCode(charCode))){ event.preventDefault(); } }, false) 6.富文本编辑

1.使用contenteditable属性 1.有三个属性: true,false,inherit 2.例子:

2.操作富文本document.execCommand()

三个参数: 要执行的命令的名称,表示浏览器是否为当前命令提供用户界面的一个布尔值,执行命令必须的一个值(如果不需要值,则为null)

3.表单与富文本 *** 要想将富文本中的值传递给表单,则可在表单内创建一个隐藏的表单字段,将富文本的值赋给该表单字段的值

十四.HTML5脚本编程 1.跨文档消息传递

主要指来源于不同域的页面间的消息传递,主要利用iframe

// 源页面 window.onload = function(){ // 获取源页面iframe的内容window对象 var iframeWindow = document.querySelector("#iframe").contentWindow; // 向iframe发送消息,并指定源的地址,两个参数必填 iframeWindow.postMessage("xujiang", "http://127.0.0.1:5500"); var mesWrap = document.querySelector(".mes-wrap"); // 接收iframe传来的消息 window.addEventListener("message",function(e){ // alert(e.data); mesWrap.innerHTML = e.data; iframeWindow.postMessage("你叫什么?", "http://127.0.0.1:5500"); },false); } // iframe页面,监听其他域传来的消息 window.addEventListener("message",function(e){ // 向发送消息的域反馈消息,event对象的属性如下: // data 传入的字符串数据 // origin 发送消息的文档所在的域 // source 发送消息的文档的window的代理 e.source.postMessage("hello", "http://127.0.0.1:5500"); },false); 2.原生拖放 3.自定义媒体播放 // 使用video,audio元素的play()和pause()方法,可以手工控制媒体的播放 // 根据媒体元素的属性,我们可以自己实现一个视频,音频播放器 十五.ajax和comet // ajax var xhr = new XMLHttpRequest(); // 创建xhr对象 // 第一个方法:open(get | post等, "exam.php", false) 参数为请求类型,请求url,是否异步的boolean xhr.open("get","exam.php", false); // 调用该方法并不是真正的请求,而是请求一个请求以备发送 // 发送真正的请求,接收一个参数,即作为请求主体要发送的数据,不发送数据时必须传递null,因为对于某些浏览器来说该参数是必须的 xhr.send(null) // 检验响应的状态--->针对同步 if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var data = xhr.responseText; }else{ console.log(xhr.status); } // 异步方案 xhr.onreadystatechange = function(){ // xhr.readyStatus表示请求/响应过程的当前活动阶段 // 0 未初始化,还没调用open() // 1 启动,已调用open()方法但未调用send() // 2 发送, 已调用send()方法,但未收到响应 // 3 接收,已接收到部分响应数据 // 4 完成,已接受到全部响应数据 if(xhr.readyStatus == 4){ if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var data = xhr.responseText; }else{ console.log(xhr.status); } } } xhr.open("get","exam.php", false); xhr.send(null); // 在接收到响应之前还可以取消异步请求 xhr.abort() // 在停止请求之后还应该进行解引用操作,防止内存堆积 // 设置http请求头,必须放在open和send中间 xhr.open("get","exam.php", false); xhr.setRequestHeader("accept", "application/json; ") xhr.send(null); // 获取响应头信息 xhr.getResponseheader("accept"); xhr.getAllResponseHeaders(); // get请求:向现有url中添加查询字符串 function addUrlParam(url, name, value){ url += (url.indexOf("?") == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" + encodeURIComponent(value); } // post请求:模拟表单提交 xhr.open("get","exam.php", false); // 设置提交时的内容类型 xhr.setRequestHeader("content-Type", "application/x-www-form-urlencoded") // 假设表单form对象已获取 xhr.send(serialize(form)); // XHR2级 -- formData --序列化表单以及创建和表单格式相同的数据(用于通过xhr传输) var data = new FormData(); data.append(key,value); // 也就可以用表单元素的数据预先填入数据 var data = new FormData(document.forms[0]); //使用FormData的好处在于不必明确地在xhr上设置请求头部 xhr.send(new FormData(form)); // 进度事件 loadStart/progress/error/abort/load // 跨域资源共享CORS 核心思想: 使用自定义的http头部让浏览器和服务器进行沟通,从而决定请求是成功还是失败 原理: 1.请求头指定源:Origin: http://www.baidu.com 2.如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部回发相同的源信息 Access-Control-Allow-Origin:http://www.baidu.com (如果是公共资源,可以回发“*”) 3.如果没有这个头部,或者有这个头部但是源信息不匹配,浏览器就会驳回请求 // 主流浏览器对cros的实现方式: 在url中使用绝对路径,但有限制:不能设置自定义头部,不能发送和接收cookie,获取不到getAllResponseHeaders()的返回值 // 带凭据的请求 withCredentials属性设置为true // 服务器接收到带凭据的请求后,会用下面的头部来请求,如果响应不包含这个头部,浏览器将不会把响应数据交给js Access-Control-Allow-Credentials: true // 跨浏览器的cros function createCORSRequest(method,url){ var xhr = new XMLHttpRequest(); if("withCredentials" in xhr){ xhr.open(method,url,true); }else if(typeof XDomainRequest != "undefined"){ xhr = new XDomainRequest(); xhr.open(method,url); }else{ xhr = null; } return xhr } var req = createCORSRequest("get","http://www.baidu.com/page/"); if(req){ req.onload = function(){ // 对响应数据进行处理 }; req.send(); } // 以上提供的公共方法有 // abort() 用于停止正在进行的请求 // onerror 用于替代onreadystatechange检验错误 // onload 用于替代onreadystatechange检验成功 // responseText 用于取得响应内容 // send() 用于发送请求 // 其他跨域技术 1.图像ping---常用于跟踪用户点击页面和动态广告曝光数,只能get请求 var img = new Image(); img.onload = img.onerror = function(){ // 操作 } img.src = "http://baidu.com?name=xujaing"; 2.JSONP---可以直接访问响应文本,可以在浏览器和服务器之间进行双向通信,但有安全隐患 function handleResponse(data){ console.log(data); } var script = document.createElement("script"); script.src = "http://a.net/json/?callback=handleResponse"; document.body.insertBefore(script, document.body.firstChild); 3.Comet (服务器推送SSE) 常用的技术有长轮询和流 4.Web Sockets 十六.高级技巧 1.高级函数 //安全类型检测 function isArray(value){ return Object.prototype.toString.call(value) == "[object Array]"; } // 注:在ie中在以COM对象形式实现的任何函数,isFunction()都将返回false function isFunction(value){ return Object.prototype.toString.call(value) == "[object Function]"; } // 使用作用域安全的构造函数 // 惰性载入函数 // 函数绑定 会占用更多内存,所以只在必要时使用 function bind(fn, context){ return function(){ return fn.apply(context, arguments); } } // ES5提供了原生的绑定方法:obj.bind(this); // 函数柯里化 function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return fn.apply(null, finalArgs) } } // 使用 function add(n1,n2){ return n1 + n2 } var curriedAdd = curry(add, 5); console.log(curriedAdd,5); 2.防篡改对象 // 不可扩展对象,使用该方法可以让传入的对象禁止添加属性和方法 Object.preventExtensions(obj); // 使用Object.isExtensible(obj)可以判断对象是否可扩展 Object.isExtensible(obj); // 密封的对象,不可扩展,不能删除,但可以修改 object.seal(obj); // 使用Object.isSealed()可以确定对象是否密封 Object.isSealed(obj); // 冻结的对象,不可扩展,密封,不能修改,访问器属性可写 Object.freeze(obj); 3.高级定时器 // 函数节流 function throttle(method,context){ clearTimeout(method.tId); method.tId = setTimeout(function(){ method.call(context); }, 100) } 4.自定义事件 function EventTarget(){ this.handlers = {}; } EventTarget.prototype = { constructor: EventTarget, addHandler: function(type, handler){ if(typeof this.handlers[type] == "undefined"){ this.handlers[type] = []; } this.handlers[type].push(handler); }, fire: function(event){ if(!event.target){ event.target = this; } if(this.handlers[event.type] instanceof Array){ var handlers = this.handlers[event.type]; for(var i=0,len=handlers.length;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3