1.正则表达式: 2. String中的正则API: 查找:
查找一个固定的关键词出现的位置: var i=str.indexOf(“关键词”[,starti]) 在str中从starti位置开始找下一个"关键词"的位置 如果省略starti,则默认从0位置开始向后找 返回: “关键词”第一字所处位置的下标 如果找不到,返回-1 问题: 只支持查找一个固定不变的关键词用正则表达式查找一个关键词的位置: var i=str.search(/正则/i); 在str中查找符合"正则"要求的敏感词 返回值: 关键词的位置 如果找不到,返回-1 问题: 正则默认区分大小的! 解决: 在第2个/后加后缀i,表示ignore,意为:忽略大小写 问题: 只能获得关键词的位置,不能获得关键词的内容 解决: matchmatch 1.查找一个关键词的内容和位置: var arr=str.match(/正则/i); 在str中查找符合"正则"要求的敏感词的内容和位置 返回值: 数组arr:[ “0”:“关键词”, “index”: 下标i ] 如果找不到: 返回null 问题: 只能查找第一个关键词,不能查找更多关键词 2.查找所有关键词的内容: var arr=str.match(/正则/ig) //g global 全局/全部 返回值: 保存多个关键词内容的数组 问题: 只能找到内容,无法获得位置即获得每个关键词的内容,又获得每个关键词的位置 reg.exec() 替换: 将找到的关键词替换为指定的新值 2种: 1.简单替换: 将所有关键词替换为统一的新值 str=str.replace(/正则/ig,“新值”) 查找str中所有符合“正则”要求的关键词,都替换为统一的新值。 问题: 所有字符串API都无权修改原字符串,只能返回新字符串。 解决: 如果希望替换原字符串,就必须自己手动赋值回原变量中 2.高级替换: 根据每次找到的关键词不同,动态选择要替换的新值 str=str.replace(/正则/ig, function(kword){ 根据kword的不同,动态生成新值 return 新值 }) 查找str中所有符合“正则”要求的关键词 每找到一个关键词,就自动调用一次回调函数 每次调用回调函数时自动传入本次找到的关键词给kword 回调函数中根据每次收到kword的不同,动态返回新值给replace函数 replace函数自动将回调函数返回的新值,替换到字符串原关键词位置。 切割:替换: 衍生操作: 删除关键字: 其实将关键词替换为"" 切割: 将一个字符串,按指定的切割符,切割成多段子字符串 2种: 1.简单切割: 切割符是固定的 var arr=str.split(“切割符”) 将str按指定的"切割符",切割为多段子字符串,保存在数组arr中 固定套路: 打散字符串为字符数组 var chars=str.split("") 2.复杂切割: 切割符不是固定的 var arr=str.split(/正则/i)
什么是: 保存一条正则表达式,并提供了用正则表达式执行验证和查找的API 的对象 何时: 只要在程序中保存和使用正则表达式,都要用RegExp对象 如何: 创建:
用/创建(直接量): var reg=/正则/ig 何时: 如果正则表达式是固定不变的
用new创建: var reg=new RegExp(“正则”,“ig”) 何时: 如果正则表达式需要在运行时才动态生成时 API: 1.验证: var bool=reg.test(str) 用正则reg,检测str是否符合正则的格式要求 问题: 正则默认只要找到部分内容与正则匹配就返回true 解决: 必须从头到尾完整匹配,才返回true 只要验证,必须前加^后加$,表示从头到尾的意思 2.查找: 获取每个关键词的内容和位置: var arr=reg.exec(str) 在str中查找下一个符合reg要求的关键词的内容和位置 如果反复调用reg.exec(),则自动会向后找下一个。 返回值: arr:[ “0”:“关键词”, “index”: 关键词位置 ]
Function 什么是函数: 封装一项任务的步骤清单代码段的对象,再起一个名字。 为什么: 重用! 何时: 只要一段代码可能被反复使用,都要创建函数。 如何: 创建: 见PPT function1
重载(overload): 什么是: 相同函数名,不同形参列表的多个函数,在调用时,可自动根据传入实参的不同,选择对应的函数调用 为什么: 减少函数名的数量,减轻维护的负担 何时: 一件事,可能根据传入的参数不同,执行不同的操作时 如何: 问题: js语法默认不支持重载 因为js不允许多个同名函数同时存在 如果存在,最后一个函数会覆盖之前所有 解决: 使用arguments对象变通实现 什么是arguments对象: 每个函数内自动创建的,准备接受所有传入函数的实参的 类数组对象 自动创建: 不用自己创建,就可直接使用 接受所有实参: 类数组对象: 长的像数组的对象 vs 数组: 相同: 1. 下标 2. length 3. 遍历 不同: 类型不同,API不通用 何时: 只要不确定将来传入函数的参数个数时,就不定义形参列表,而是用arguments接住所有的实参值。
匿名函数: 什么是: 定义函数时,不写名的函数 何时: 如果一个函数只用一次,不会反复使用,就不起函数名 为什么: 节约内存!——使用一次后,自动释放! 如何: 2种场景:
回调函数: 自己定义的函数,自己不调用,而是传给其它对象或函数,被别人调用。 arr.sort(function(a,b){return a-b}) xhr.onreadystatechange=function(){ … } pool.query(sql,[参数],function(err,result){ … })匿名函数自调: 定义函数后,立刻自己调用自己 为什么: 避免使用全局变量,造成全局污染 何时: 所有js代码都应该封装在一个匿名函数自调中 如何: (function(){ … })()//调用后,匿名函数内的局部变量都释放了作用域和作用域链 闭包
什么是对象: 程序中,描述现实中一个具体事物的程序结构 为什么: 便于维护 什么是面向对象: 程序中,都是先将多个事物的属性和功能,封装为多个对象,再按需调用对象的成员 何时: 今后,几乎所有程序,都用面向对象方式实现的 如何: 封装,继承,多态——三大特点 封装:创建一个对象,集中保存一个具体事物的属性和功能 为什么: 便于大量数据维护 何时: 只要使用面向对象编程,都要先封装对象,再按需使用对象的成员 如何: 3种: 1. 用{}: var obj={ 属性名: 值, … : … , 方法: function(){ … this.属性名… }, … : … } 访问对象的成员: =属性+方法 属性其实就是保存在对象中的变量 对象.属性 方法其实就是保存在对象中的函数 对象.方法() this: 见this.wmv 什么是: 在函数调用时,自动指向.前的对象的关键词 为什么: 避免在对象的方法中写死对象名,形成紧耦合。 何时: 只要对象自己的方法,想访问自己的成员时,都要加this. 强调: 鄙视时:
this和定义在哪儿无关,只和调用时.前的对象有关全局函数调用,没有., this默认指window2.用new创建:2步走
var obj=new Object(); obj.属性名=值; ... = ...; obj.方法名=function(){ ... this.属性名 ...}揭示: js中一切对象底层,都是关联数组
访问不存在的成员,不报错,返回undefined强行给不存在的成员赋值,不报错,而是强行赋值新成员同样可用for in循环遍历一个对象中的所有成员访问下标: 2种: 1. obj[“下标”] 如果属性名需要动态获得 2. obj.下标 如果属性名是写死的问题: 一次只能创建一个对象,如果反复创建多个相同结构的对象时,代码会很冗余 解决: 用构造函数创建对象: 3. 用构造函数反复创建多个相同结构的对象: 什么是构造函数: 描述同一类型所有对象的统一结构的函数 何时: 反复创建多个相同结构的对象 如何: 定义构造函数:
function 类型名(形参1,形参2,...){ this.属性名=形参1; this. ... =形参2; this.方法名=function(){ ... this.属性名 ...} } 反复调用构造函数,创建多个相同类型的对象 ` var lilei=new 类型名(实参,...);` new 4件事: 1. 创建一个新的空对象: {} 2. ? 3. 用新对象调用构造函数: 自动将构造函数中的this->new 通过强行赋值新属性的方式,自动添加规定的属性到新对象中,并将参数值,保存到新对象的对应属性中 4. 返回新对象的地址给变量 构造函数优点: 重用结构 缺点: 无法节约内存!继承: 什么是: 父对象的成员,子对象无需重复创建就可直接使用 为什么: 重用代码,节约内存 何时: 只要在多个子对象中包含部分相同的成员时 如何: /****** 不用你做 *******/ js中的继承都是继承原型对象(prototype) 什么是原型对象: 集中保存所有子对象共有成员的父对象 创建原型对象: 买一赠一 每创建一个构造函数,就附赠一个空的原型对象 构造函数.prototype 何时继承: new的第2步: 让新对象自动继承构造函数的原型对象: 新对象._ proto _=构造函数.prototype
封装:3种
自有属性和共有属性: 自有属性: 保存在当前对象本地,仅归当前对象自有的属性 共有属性: 保存在原型对象中,归多个子对象共有的属性 取值/访问时: 对象.成员名 修改时: 修改自有属性: 子对象.属性=值 修改共有属性: 原型对象.共有属性=值 如果强行用子对象.共有属性=值 后果: 为子对象自己添加一个同名的自有属性,从此子对象与父对象再无关系。——错误!
内置对象的原型对象: 内置对象: ES标准中规定的,浏览器已经实现了的,咱们可以直接使用的对象 js内置对象: 11个: String Number Boolean Array Date RegExp Math Error Function Object global 其实,每种内置对象(除Math和global外)都是一种类型: 都由两部分组成: 1. 构造函数: 创建该类型的子对象 2. 原型对象: 保存该类型共有的函数
什么是: 多级原型对象逐级引用形成的链式结构 作用: 1. 保存了一个对象可用的所有成员 2. 控制着成员的使用顺序: 先自有,再共有
什么是: 一个函数在不同情况下表现出不同的状态 2种:
重载:重写(override): 子对象中定义了和父对象中同名的成员 何时: 只要子对象觉得父对象的成员不好用,就要定义自有的,来屏蔽父对象的。自定义继承: 见1_自定义继承.pptx
静态(static)方法: 什么是实例(instance)方法: 必须先有一个实例对象,才能调用的方法 比如: var arr=[1,2,3]; arr.sort() var str=“Hello”; str.toUpperCase() 限制: 只有当前类型的子对象,才能使用的方法 什么是静态方法: 不需要任何实例,就可用类型名直接调用的方法 比如: Object.setPrototypeOf() 何时: 2种: 1. 不确定使用该方法的对象的类型时 2. 调用函数时,暂时无法确定要使用该函数的对象是什么 如何定义: 定义实例方法: 将方法添加到原型对象中 定义静态方法: 将方法添加到构造函数对象上 构造函数.静态方法=function(){ … }
保护对象: 为什么: js中的对象毫无自我保护能力 何时: 如果不希望别人擅自修改对象的属性和结构时 如何: 保护属性: 将所有属性划分为2大类: 命名属性: 可用.访问到的属性 又分为2类: 数据属性: 直接存储属性值的属性 访问器属性: 不实际存储属性值,仅负责提供对另一个数据属性的保护。 内部属性: 不能用.访问到的属性
**数据属性:** ES5规定,每个数据属性,其实是一个缩微的小对象 每个属性对象其实包含四个特性: { value: 实际存储属性值, writable: 控制是否可修改, enumerable: 控制是否可被for in遍历,但用.依然可以访问 configurable: 控制是否可删除该属性 控制是否可修改其它两个特性 默认: 三个开关都是true 获取一个属性的四大特性: var attrs=Object.getOwnPropertyDescriptor(obj,"属性名") 获得obj对象的指定"属性"的四大特性 打开和关闭开关: Object.defineProperty(obj,"属性名",{ 重新定义obj的指定"属性"的开关 开关: true/false, ... : ... }) 问题: 一次只能修改一个属性的四大特性 解决: Object.defineProperties(obj,{ 属性:{ 开关:true/false, ... : ... }, 属性:{ ... ... } }) 问题: 无法使用自定义规则保护属性 解决: **访问器属性:** 何时: 只要使用自定义规则保护一个数据属性时 如何: 前提: 必须先有一个隐藏的数据属性,实际存储属性值 定义访问器属性: 使用访问器属性:保护结构: 禁止添加/删除对象中的属性 3个级别: 1. 防扩展: 禁止添加新属性 Object.preventExtensions(obj) 禁止给obj对象添加任何新属性 原理: 每个对象中都有一个内部属性: extensible:true preventExtensions()将对象的extensible:false 2. 密封: 在兼具防扩展同时,再禁止删除现有属性 Object.seal(obj) 禁止向obj中添加新属性 禁止删除obj中现有属性 原理: extensible:false 每个属性的configurable:false 3. 冻结: 在兼具密封的基础上,同时禁止修改所有属性值 Object.freeze(obj) 禁止向obj中添加新属性 禁止删除obj中现有属性 禁止修改任何属性的值 原理: 自动将每个属性的writable改为false
Object.create() 什么是: 创建一个新对象,让新对象继承指定的父对象 何时: 在没有构造函数的情况下,也想创建子对象继承父对象时 如何: var child=Object.create(father,{ 自有属性:{ value:值, 三个开关… } })
替换this:
临时调用一次函数,并临时替换一次this: call: 传入函数的每个实参必须作为一个单独的参数传入 apply: 传入函数的每个实参必须放在一个数组中整体传入 何时: 如果所有实参是放在一个数组中给你的不调用函数,而是创建一个原函数的副本,但永久绑定this和部分参数值: bind 何时: 修改回调函数的this时只能用bind数组API:
查找: indexOf: 同String中的indexOf 何时: 在数组中查找一个指定元素的位置时
判断: 判断数组中的元素是否符合要求
判断数组中的元素是否都符合要求 var bool=arr.every(function(elem, i, arr){ return 判断结果 }) every会自动拿着回调函数在每个元素上执行一次: 参数: elem自动得到当前元素值 i 自动得到当前位置 arr 自动得到当前数组对象 返回值: 利用获得的参数,判断当前元素是否符合要求,并返回判断结果。 只有回调函数在每个元素上执行都返回true时,才整体返回true。只要碰到一个false,就返回false判断数组中是否包含符合要求的元素 var bool=arr.some(function(elem, i, arr){ return 判断条件 })遍历API: 对数组中每个元素执行相同的操作
遍历原数组中每个元素,执行相同的操作: arr.forEach(function(elem, i, arr){ 对原数组中的元素值,执行操作 })依次取出原数组中每个元素,执行相同的操作后,放入新数组中返回: var newArr=arr.map(function(elem,i,arr){ return 新值 })过滤和汇总: 过滤: 复制出数组中符合条件的元素,组成新数组返回 var subArr=arr.filter(function(elem,i,arr){ return 判断条件 }) 汇总: 对数组中每个元素的值进行统计,得出一个汇总的结果。 var result=arr.reduce( function(prev,elem,i,arr){ //prev: 获得截止目前的临时汇总值 return prev+elem }, base//起始时的基数 )
let: 代替var用于声明变量 var的缺点:
声明提前:没有块级作用域:let的优点:
阻止了声明提前让let所在的块({…})也变为一级作用域参数增强:
默认值: ES6中可以给形参提前设置一个默认值,调用时,如果没有给实参,就自动启用默认值代替。 如何: function fun(形参1, 形参2,…, 形参n=默认值){} 强调: 带默认值的形参必须出现在参数列表的末尾剩余参数: 代替arguments: arguments的问题: 不是纯正的数组类型,而是类数组对象,导致数组的所有API,arguments不能使用只能接住所有参数,不能有选择的接住部分参数 如何使用剩余参数: function fun(形参1, 形参2,…数组名){ //数组中就接住了除形参1,形参2以外的剩余的实参 //且"数组"是纯正的数组类型,可以使用所有数组家的API } 剩余参数的优点: 1. 是纯正的数组,可使用所有数组家API 2. 可有选择的获得剩余参数 散播(spread): 代替apply,用于专门打散数组类型参数为单个值 apply的问题: 其实apply的主要功能是替换this,顺便打散数组类型参数 何时: 只要单纯希望打散数组类型参数为单个值时 如何: 调用时: fun(…数组名) 先把数组打散后,再分别传给fun 相当于: fun(数组[0],数组[1],数组[2],…)箭头函数: 简写一切匿名函数
去function变=>如果只有一个参数,可省略()如果函数体只有一句话,可省略{} 如果仅有的一句话是return… ,则必须省略return 特性: 内外this通用! 如果和this无关时,或希望内外this通用时,可改箭头函数 如果不希望内外this通用时,就不能用箭头函数解构: 提取出一个大的对象中的部分成员,单独使用。
数组解构: 下标对下标: var arr=[elem1, elem2,…]; || || var [变量1,变量2,…]=arr; 变量1=elem1 变量2=elem2
对象解构: 属性对属性 var obj={属性1:值1, 属性2:值2, … } || || var {属性1: 变量1, 属性2:变量2, … }=obj 变量1=值1; 变量2=值2;
参数解构: 其实是对象解构在函数传参时的应用 何时: 多个形参都不确定是否有值时 如何: 1. 定义函数时: 将所有形参都定义在对象结构中 function fun({ url:url, type:type, data:data, dataType:dataType }){
} 可简写为: function fun({url, type, data, dataType}){
2.调用时: 所有实参都要放在一个对象结构中整体传入 fun({ url:“http://localhost:3000/index”, type:“get”, //data:, dataType:“json” }) 结果: 形参url ="http://localhost:3000/index 形参type=“get” 形参data=undefined 形参dataType=“json” 优点: 1. 与参数个数无关 2. 与参数顺序无关
for of: 遍历索引数组
for: for(var i=0;i<arr.length;i++){ arr[i] //当前元素 }forEach: arr.forEach( (elem,i,arr)=>{ elem //当前元素值 }) 不灵活: 不能控制顺序不能控制步调 for of for(var elem of arr){ elem //当前元素值 } 不灵活: 只能获得元素值,不能获得元素位置 vs for in: for of: 可遍历数字下标的索引数组或类数组对象 for in: 只能遍历非数字下标的关联数组或对象class: 对整个面向对象的简化:
对单个对象直接量的简化: var obj={ 属性1: 值1, 属性2 : 变量, //如果属性名刚好和变量名相同,则只写一个 方法名:function(){//所有方法,不再需要:function … … } }对一种类型定义的简化: class1.用class{}包裹构造函数和原型对象方法 2. 将构造函数名提升为类型名,构造函数统一更名为constructor 3. 所有原型对象方法不用再添加到Prototype中,而是直接写在class内,与构造函数平级(不要逗号) class Plane { constructor (fname,speed,score){ this.fname=fname; this.speed=speed; this.score=score; } fly(){ … } getScore(){ … } }
继承:
让子类型继承父类型: class Child extends Father{ extends代替了Object.setPrototypeOf(…)子类型构造函数中必须先借用父类型构造函数: class Child extends Father{ constructor(…){ super(参数,…)//借父类型的构造函数 this.xxx=xxx; } } super代替了Father.call(this,…) super中不要加this!访问器属性: class 类名{ constructor(…, age){ … … 半隐藏的_age属性 this.age=age; } get age(){ return this._age;} set age(value){验证value并赋值} }
静态方法: class 类名{ constructor(){ } //必须使用当前类型的子对象才能调用的方法,称为实例方法。 实例方法(){ … } //不需要使用当前类型的子对象,就可用类型名直接调用的方法 static 静态方法(){ … } } 调用时: //静态方法不需要提前创建任何该类型的子对象,就可用类型名直接调用 类型名.静态方法()
var obj=new 类型名() //实例方法要求必须先创建该类型的子对象,才可用子对象调用实例方法。 obj.实例方法()
DOM: 专门操作网页内容的API的标准——W3C JS=ES(核心语法)+ DOM(专门操作网页内容的API)+ BOM(专门操作浏览器软件的API) 为什么: 为了统一所有浏览器的操作网页的API标准 何时: 只要操作网页的内容,都要用DOM 包括: 增,删,改,查,事件绑定
什么是DOM Tree: 内存中保存一个网页中所有内容的树形结构 为什么: 因为树形结构是最容易保存复杂的上下级包含关系的结构 如何: 形成: 浏览器在加载一个HTML网页时,都会创建一棵DOM数。包括: 唯一的根节点对象: document 每个网页内容(元素、属性、文字)都会成为树上的节点对象 每个节点对象都有三个属性: 1. node.nodeType: 节点类型 何时: 需要判断节点类型时 值是一个数字: document 9 element 1 attribute 2 text 3 问题: 只能区分节点类型,不能更细致的区分元素的名称 2. node.nodeName: 节点名 何时: 判断当前节点的元素名时 包括: document #document element 全大写的标签名 attribute 属性名 text #text 3. node.nodeValue: 节点值——几乎不用 包括: document null element null attribute 属性值 text 文本内容
练习: 查找一个节点下的所有后代节点: 2步:
先定义函数,仅遍历直接子元素:
在函数内,对每个直接子元素,调用和父元素完全相同的当前函数本身。
按HTML特征查找: 4种:
按id查找一个元素: 何时: 当要查找的元素身上有id属性时,都首选用id查找 如何: var elem=document.getElementById(“id名”) 强调: getElementById只能用document调用按标签名查找多个元素: 何时: 当元素上没有id,name,class时,就可用标签名查找 如何: var elems=任意父元素.getElementsByTagName(“标签名”) 强调: 1. 可用任意父元素找 2.不仅查找直接子元素,而是在所有后代中查找符合条件的。按name属性查找多个元素:按class属性查找多个元素:内容: 3种:
获取或修改原始的HTML片段内容: elem.innerHTML获取或修改纯文本内容: elem.textContent 比innerHTML多做两件事: 翻译特殊符号为正文去掉内嵌的子标签,只保留文字 表单元素的值: elem.value 属性: 3种:HTML标准属性: 2种:核心DOM API: 4个 获取属性值: var value=elem.getAttribute(“属性名”) 修改属性值: elem.setAttribute(“属性名”,“新值”) 移除属性: elem.removeAttribute(“属性名”) 判断是否包含属性: var bool=elem.hasAttribute(“属性名”)HTML DOM API: 对常用核心DOM API的简化 HTML DOM提前将所有HTML标准属性,定义在内存中的元素对象上: elem.属性名 特例: class是ES标准中的关键字 DOM中不允许再使用class作为属性名 class一律都要改为className DOM中的className属性等于HTML中的class状态属性: enabled disabled selected checked 值都是bool类型,不是字符串类型,不能用核心DOM API修改。 只能用HTML DOM的.来访问补充: CSS3中有一种特殊的选择器: 状态伪类: :enabled :disabled :checked :selected 3. 自定义扩展属性: 什么是: HTML标准中没有规定的,程序员自行添加的属性 何时: 2种: 1. 用自定义扩展属性作为条件,选择要绑定事件的元素 为什么不用id,class,元素 选择器 id只能选择一个元素 class是定义样式用的,经常变化 元素选择器限制太死。实现一种效果,可能用不同的元素都行。 使用自定义扩展属性作为条件绑定事件的好处: 不受个数,样式,元素名的干扰! 2. 在客户端元素上临时缓存业务数据 为什么: 避免重复请求服务端,造成延迟
属性: 自定义扩展属性: 定义自定义扩展属性: <ANY 自定义属性名=“值”> HTML5标准中: <ANY data-自定义属性名=“值” 获取或修改自定义扩展属性: 1. 核心DOM API: .getAttribute() .setAttribute() .removeAttribute() .hasAttribute() 强调: HTML DOM API不能操作自定义扩展属性 因为自定义扩展属性是后天自定义的,HTML标准中没有。所以不包含在元素对象中。所以不能用.直接访问。 2. HTML5标准中: elem.dataset //可自动获得所有data-*开头的属性 .自定义属性名 //使用dataset访问自定义属性时,不用data-前缀
样式: 1.修改内联样式: elem.style.css属性名=“值” 等效于: <ELEM style=" css属性名:值" 强调: 1. css属性名中如果带-,需要去横线变驼峰: z-index => zIndex list-style => listStyle background-color => backgroundColor 2. 如果是带单位的数字属性: 修改时: 必须手动拼接单位到结尾: .style.width=12+“px”; 获取时: 必须去掉结尾的px,才能做计算 width=“12.5px” parseFloat(width) => 12.5 问题: elem.style 仅代表内联样式: 修改时,如果elem.style,优先级最高! 获取时,只能获取内联样式,无法获取外部样式表中的样式。
获取样式: 不能用style 应该获取计算后的样式: 最终应用到元素上的所有样式的集合。 如何: 2步: 1. 先获得计算后的样式的集合对象: var style=getComputedStyle(elem) 2. 获取一个css属性的值: style.css属性 强调: 因为计算后的样式属性来源不确定,所以都是只读的。
问题: elem.style修改样式,一句话只能修改一个css属性 如果同时修改多个css属性,代码会很繁琐 解决: 今后,只要批量修改css属性,都要首选class方式修改
添加: 3步:
创建一个空元素对象 var a=document.createElement("a") a: <a></a> 设置关键属性 a.href="http://tmooc.cn"; a.innerHTML="go to tmooc"; a: <a href="http://tmooc.cn"> go to tmooc </a> 将新对象挂载到DOM树上指定位置 3种:在当前父元素下的结尾,追加一个新元素: 父元素.appendChild(a)在父元素下的某个子元素之前插入: 父元素.insertBefore(a, child)替换父元素的某个子元素: 父元素.replaceChild(a, child)优化: 尽量减少修改DOM树的次数 因为每修改一次DOM树,浏览器都会重绘页面 页面加载过程: html -> DOM树 ↓ 加载树 -> 排版 -> 绘制 ↑ 非常耗时 css -> COM模型 每次修改DOM树都会导致重排重绘 如何: 2种: 1. 如果同时添加父元素和子元素时,应该先在内存中将子元素添加到父元素中,最后再一次性将父元素添加到DOM树 2. 如果父元素已经在页面上了,要同时添加多个平级子元素时。先将多个子元素临时加入文档片段对象中。再一次性将文档片段对象添加到DOM树上。 文档片段对象将子元素送到DOM树后,自动释放。 文档片段: 内存中,临时保存多个平级子元素的,虚拟的父元素。 何时: 同时添加多个平级子元素到DOM树时 如何: 1. 先创建一个文档片段对象: var frag=document.createDocumentFragment(); 2. 将子元素添加到frag中 frag.appendChild(child) 3. 将frag整体添加到DOM树 父元素.appendChild(frag)
父元素.removeChild(child)
Image Select/option Table/… Form/…
Image: var img=new Image();
Select对象: 代表页面上一个<select> 属性: .selectedIndex 快速获得当前选中项的位置 .options 快速获得select下所有option的集合 .options.length 获得select下option的个数 .length => .options.length .value 获得select中当前选中项的值 如果选中项没有value,则用内容作为value 方法: .add(option) 向select中添加一个option 问题: 不支持文档片段 .remove(i) 移除select中i位置的option
Option对象: 代表select中每个option元素 创建: var opt=new Option(text,value)
Table对象: 代表页面上一个<table>元素 管着行分组: 添加行分组: var thead=table.createTHead() var tbody=table.createTBody() var tfoot=table.createTFoot() 删除行分组: table.deleteTHead() table.deleteTFoot() 获取行分组: table.tHead table.tFoot table.tBodies[i]
行分组管着行: 添加行: var tr=行分组.insertRow(i) 在当前行分组中i位置,插入一个新行 固定用法: 1. 行分组.insertRow(0) 开头插入 2. 行分组.insertRow() 末尾追加 删除行: 行分组.deleteRow(i) 删除行分组内的i位置的行 强调: i是相对于行分组内的下标 问题: 行分组内的下标位置无法自动获得 解决: 今后只要删除行,都用: table.deleteRow(tr.rowIndex) 其中: tr.rowIndex可获得tr在整个表中的下标位置 获取行: 行分组.rows[i] 获得当前行分组中的第i行
行管着格: 添加格: var td=tr.insertCell(i) 固定用法: tr.insertCell() 在行末尾追加新格 问题: 只能创建td,不能创建th 删除格: tr.deleteCell(i) 获取格: tr.cells[i]
Form对象: 代表页面上一个表单元素 获取: var form=document.forms[i]; 属性: .elements 可获得表单中所有表单元素的集合 .elements.length 获得表单中所有表单元素的个数 .length => .elements.length 方法: form.submit() 手动调用程序控制提交表单
表单元素: 获取: .elements[i/id/name] 如果表单元素上有name属性: form.name属性值 方法: elem.focus() 让当前表单元素获得焦点 elem.blur() 让当前表单元素失去焦点
BOM: 专门操作浏览器窗口/软件的一套API 问题: 没有标准 何时: 希望操作浏览器窗口或读取浏览器软件的信息时 包括: window: 2个角色:
代替ES中的global充当全局作用域对象包含所有ES,DOM和BOM的API 又包括: history, location, document, navigator, screen, event获取窗口大小: 2组:
完整的窗口大小: window.outerWidth window.outerHeight文档显示区大小: window.innerWidth window.innerHeight 打开和关闭窗口: 打开窗口: window.open() 4种:在当前窗口打开,可后退: html:<a href="url" target="_self"> js: open("url", "_self"); 2. 在当前窗口打开,禁止后退: js: location.replace("url") 3. 在新窗口打开,可打开多个: html:<a href="url" target="_blank"> js: open("url", "_blank"); 4. 在新窗口打开,只能打开一个: html: <a href="url" target="自定义窗口名"> js: 原理: 浏览器内存中,每个窗口都有一个唯一的窗口名 打开窗口时,也可通过target属性,为新窗口指定自定义的窗口名 浏览器规定同名的窗口只能打开一个。 后打开的同名窗口会自动将先打开的同名窗口覆盖掉 内置窗口名: _self: 自动获取当前窗口自己的名字,作为新窗口的名字。 _blank: 不指定窗口名,在运行时,浏览器会自动随机分配窗口名。关闭窗口: window.close()
history对象: 内存中保存当前窗口打开后,成功访问过的url的历史记录栈 每成功访问一个url,就会向history中push一个url记录 何时: 用程序模拟前进,后退或刷新时 如何: history.go(1) 前进一步 history.go(-1) 后退一步 history.go(-2) 后退两步 history.go(0) 刷新
location对象: 保存当前窗口正在打开的url的对象 属性: location.href 完整url location.protocol 协议 location.host 主机名+端口号: 比如localhost:3000 location.hostname 主机名: 比如localhost location.port 端口号: 3000 location.pathname 相对路径 location.hash #锚点地址 location.search ?查询字符串 方法:
也可实现在当前窗口打开,可后退 location.assign(“新url”) location.href=“新url” location=“新url”实现禁止后退: location.replace(“新url”) 原理: 用新url替换history中旧的url刷新: 2种: 普通刷新: 优先从浏览器本地缓存中获取资源。缓存中没有或过期,才去服务器下载新的。 F5 history.go(0) location.reload()强制刷新: 跳过浏览器缓存,总是从服务器下载最新的资源 location.reload(true) true表示强迫navigator对象: 保存浏览器配置信息的对象 何时: 只要想获得浏览器的配置信息时 包括:
cookieEnabled: 判断当前浏览器是否启用了cookie 什么是cookie: 在客户端本地持久保存用户私密信息的小文件。 为什么: 程序中的数据,都是临时的。程序退出后,都释放。 何时: 只要希望程序关闭,数据也不丢失时
plugins: 保存浏览器安装的所有插件信息的集合 plugin: 插件,为浏览器提供新功能的小软件
userAgent: 保存浏览器名称和版本号的字符串 何时: 只要判断浏览器的名称和版本号时
什么是事件: 浏览器自动触发的或人为触发的页面内容状态的改变 什么是事件处理函数: 当事件发生时自动执行的函数 浏览器允许在事件发生之前,就提前为一个元素的事件属性绑定一个处理函数。 如何绑定事件:
在HTML中: <ANY on事件名=“js语句”> 当事件发生时,自动执行提前规定的js语句在js中绑定: 赋值方式 elem.on事件名=function(){ //this->当前触发事件的.前的元素对象本身 } 问题: 一个事件属性,只能绑定一个处理函数在js中绑定: 添加事件监听对象的方式: elem.addEventListener(“事件名”,处理函数) 事件监听对象: 封装一组:事件名+元素+处理函数的组合的对象 浏览器中包含一个巨大的事件监听对象队列 每添加一个监听对象,都是加入到浏览器的监听对象队列中 如何查看事件监听对象: F12->Elements->选中元素->Event Listener->展开click 移除监听对象: elem.removeEventListener("事件名",原处理函数) 强调: 如果一个处理函数有可能被移除,则绑定时,就要用有名字的函数绑定。移除时才能使用函数名找到原处理函数。事件模型: 事件发生时到触发完所有处理函数的执行过程 所有浏览器的开发者认为,点在内层元素上,也等效于同时点在外层元素上。 3个阶段:
捕获: 由外向内依次记录各级父元素上的处理函数 只记录,不执行目标触发: 优先触发目标元素上的处理函数 目标元素: 最初点击的那个元素冒泡: 由内向外依次执行捕获阶段记录的各级父元素上的处理函数event对象: 什么是事件对象: 当事件发生时,自动创建的保存事件信息和API的对象 何时: 2种:
如果要获得事件相关的信息时: 比如: 获得目标元素, 获得鼠标的位置如果希望改变事件的行为时: 比如: 阻止冒泡如何:
获得事件对象: 事件对象总是自动作为处理函数的第一个实参传入。 event对象 ↓ elem.on事件名=function( e ){
}
API:
取消冒泡: e.stopPropagation()利用冒泡: 优化: 尽量减少事件监听的个数 为什么: 因为浏览器触发事件时是采用遍历监听队列的方式找到符合条件的监听对象并执行处理函数。 监听对象的个数,就决定了遍历的速度。 如何: 当多个子元素需要绑定相同的事件时,其实只要在父元素上绑定一次即可。所有子元素通过冒泡共用! 2个难题: 如何获得实际点击的目标元素: this不行: this->父元素 e.target -> 目标元素 鉴别目标元素是否想要的: 通过: class, 标签名, …阻止默认行为: e.preventDefault()
获得事件发生时,鼠标的位置: 3组:
相对于显示屏左上角: e.screenX, e.screenY相对于文档显示区左上角: e.clientX, e.clientY相对于事件发生的元素左上角: e.offsetX, e.offsetY