Object面向对象
*****继承
- 父元素的成员(方法和属性),子对象可以直接使用
- 为什么要继承:代码重用,节约内存空间
- 何时继承:只要多个子对象公用的属性和方法,都要集中定义在父对象之中
JS面向对象是基于原型的
- 原型:保存一类子对象共有属性和共有【方法】的父对象(原型对象),每一个对象天生就是一个原型
- 获取原型对象:2种
- 对象名
.__proto__必须先创建出一个对象,才可以使用此方法- 注意,‘_’是两个
- 构造函数名.prototype
- 构造函数名:Array、Function、Date、RedExp....哪怕没有创建过任何对象也能找到原型
- *****两链一包
- 作用域链:一函数EC的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构
- 作用:查找变量的,带来了变量的使用规则---优先使用自己的,自己没有找全局
- 闭包:保护一个可以反复使用的局部变量的此法结构
- 原型链:每一个对象都有一个
.__proto__的属性,可以不断的连续,找到父亲->爷爷....形成的一条链式结构- 最顶层:Object.prototype是对象的原型
- 作用:查找属性和方法,自己没有的属性和方法可以顺着原型链进行查找,所以任何人都可以使用toString
- 获取到原型对象则可以设置共有的属性和方法
- 原型对象.属性名=属性值;//共有属性
- 原型对象.方法名=function(){};//共有方法
- 自有属性和共有属性
- 共有:保存在父(原型)对象的属性,所有子对象都可以使用
- 笔试题:
-
如何判断自有和共有
- 判断自 有:obj.hasOwnProperty("属性名");
- 返回的是一个布尔值:true说明是自有,false可能是共有也可能是没有
- 判断共有:2个条件
-
不是自 有:obj.hasOwnProperty("属性名")==false;
-
自动在原型链检查:属性名 in 对象名 -完整的写法:
if(obj.hasOwnProperty("属性名")==false && "属性名"in 对象名){ 有}else{没有}
-
- 判断自 有:obj.hasOwnProperty("属性名");
-
*修改或删除属性
- 修改和删除自有属性
- 修改:obj.属性名 = 新值
- 删除:delete obj.属性名
- 修改和删除共有属性
- 修改:原型对象.属性名=新值
- 删除:delete 原型对象.属性名
- 修改和删除自有属性
-
*****为旧版本IE浏览器的数组添加indexOf方法,(这题不是固定的,为某一类设置一个方法),代码如下:
if(Array.prototype.indexOf===undefined){ //indexOf的执行原理 Array.prototype.indexOf=function(key,starti){ //说明用户没有传入开始位置,我们给用户设置为从0下标开始查找 starti===undefined && (starti=0); //从卡死位置处,循环数组后面的每一个文字和用户输入的关键字进行匹配 for(var i=starti;i<this.length;i++){ if(this[i]==key){ return i; } } return -1; } } -
*****判断一个对象x是不是对象? 4种
- 判断x是不是继承自Array.prototype
- Array.prototype.isProtopypeOf(x);
- 如果为true,则说明是数组,否则不是数组
- 判断X是不是由构造函数Array创建的
- x instanceof Array
- ES5提供了一个API:Array.isArray(x);
- 此方法不是人人都有,而且ES5以上的东西,老IE都不支持
- 判断x是不是继承自Array.prototype
-
***输出对象的字符串形式
- 在Object的prototype原型上放着最原始的toString
- 原始的toString,默认输出[object构造函数名]
- *****多态(override)/重写:子对象对父对象的成员不好用,可以在本地定义同名哈数,覆盖父对象之中的成员
- 同一个函数,不同人来使用,效果是不同的,其实根本是同一个函数
- Object.prototype.toString.apply(x)==="[Object Array]"
-
- 实现自定义继承
- 实现两个对象之间的继承
- 子对象.
__proto__= 父对象
- 子对象.
- 直接匹配设置继承
- 构造函数名.prototype = 父对象
- 时机:先设置好父对象,再创建父对象
- 实现两个对象之间的继承
- 作用域链:一函数EC的scope chain属性为起点,经过AO逐级引用,形成的一条链式结构
- 对象名
ES5&ES6:就是在ES3的基础添加了一些新特性,新语法,新API--简化ES3
ES5
- 保护对象:保护对象的属性和方法
- 1、四大特性:每个属性都有四大特性
- value 实际保存属性值的地方
- writable 开关:控制着是否可以被修改
- enumeiable 开关:控制着是否可以被for in循环
- configurable 开关:控制在是否可以被删除,总开关,一旦设置false不可逆,也不可以再修改其他特性
- 修改四大特性
- Object.defineProperties(obj,{"属性名":{四大特性}})
- 2、三个级别
- 防扩展:禁止给对象添加新属性
- Object.preventExtension(obj);
- 密封:禁止给对象添加任何新属性,也不能删除属性
- Object.seal(obj);
- 冻结:禁止给对象添加任何新属性,也不能删除属性,也不能修改属性
- Object.freeze(obj);
- 防扩展:禁止给对象添加新属性
- 1、四大特性:每个属性都有四大特性
- 2、*****数组的新的API:3组6个
- 判断:判断数组中的原始是否符合要求
- every:每一个,判断数组中的每个元素【都】要符合要求最后结果才为true,类似于&&,只有一个不满足,结果则为false
- 语法:arr.every(function(val,i,arr){val 当前元素 i 当前元素的下标 arr当前数组})
- some:有一些,判断数组中是否【包含】符合要求的元素,只要有一个最后结果则为true,类似||,只要有一个满足,则为true,只有全都不满足,结果false
- arr.some(function(val,i,arr){return 判断条件})
- every:每一个,判断数组中的每个元素【都】要符合要求最后结果才为true,类似于&&,只有一个不满足,结果则为false
- 遍历
- forEach:直接修改原数组
- arr.forEach(function(val,i,arr){操作});
- map:不修改原数组
- arr.map(function(val,i,arr){操作});
- forEach:直接修改原数组
- 过滤和汇总
- 过滤:筛选出原数组中符合条件的元素组成一个新数组,原数组不变
- arr.filter(val,i,arr){return 判断条件});
- 汇总:将数组中每个元素,取出来整合成一个最终结果
- arr.reduce(function(pre,val,i,arr){return pre+val;},基础值);
- 过滤:筛选出原数组中符合条件的元素组成一个新数组,原数组不变
- 判断:判断数组中的原始是否符合要求
- Object.create()方法:直接用父对象创建子对象,并且子对象扩展自有属性
- var 子对象 = Object.create(父对象,{"自有属性名":{四大特性}})
- 严格模式:很严格
- 如何开启:"use strict"可以放在任何一个作用域的顶部
- 禁止给未声明的变量赋值-解决了全局污染
- 将静默失败升级为了错误
- call、apply、bind
- call和apply:临时替换函数中的this
- 差别:
- call:要求传入的实参必须单独传入
- apply:要求传入函数的实参必须是一个数组
- 语法:
- 要借用的函数.call(借用的对象);
- 要借用的函数.apply(要借用的对象,arr)----apply除了有借用的功能,还会打散数组
- 差别:
- bind:【永久替换函数中的this】
- 语法:var 新函数 = 老函数.bind(指定的对象)
- 3件事
- 创建了一个和原函数功能完全一样的新函数
- 将新函数中的this永久绑定为指定的对象
- 将新函数中的部分参数永久固定
- 强调:bind绑定在新函数中的this,无法被call和apply再次替换
- 总结:
- 如果临时调用一个函数,立刻执行时===call/apply
- 如果创建一个函数提前绑定this,不希望立刻执行===bind
- 使用场景:
- 比较数组中的最大值和最小值
Math.max/min.apply(Math.arr)
- 得到Object最原始的toString
- Object.prototype.toString.call.apply(arr)
- 将类数组对象转为普通数组
- Array.prototype.slice.call.apply(类数组对象)
- ES5简化版:Array.from(类数组对象)
- Array.prototype.slice.call.apply(类数组对象)
- 比较数组中的最大值和最小值
- call和apply:临时替换函数中的this
ES6新的语法
- 模板字符串:简化字符串拼接,支持在模板字符串中书写遍历
- 语法:``在字符串中实现了一个简单的JS环境
我的名字叫${name}
- 语法:``在字符串中实现了一个简单的JS环境
- *let 关键字:创建遍历,以后优先使用let,再考虑var
- let 变量名 = 值
- 优点:
- 解决了声明提前
- 添加了块级作用域,一个{}就是一个块
- 如果绑定了事件时,用到了let来遍历,那么let会记录住当前元素的下标,就不需要自定义下标
- *箭头函数:简化一切回调函数
- 去掉function,() 和{} 添加=>,形参只有一个可以省略()
- 函数体只有一句话,省略{}
- 函数体只有一句话,并且是return,省略function和return
- for....of
- for(var v of arr){v 直接拿到值}
- 不能修改原数组
- 不能遍历hash数组和对象
DOM
- 什么是DOM:Document Object Model(文档对象模型)
- 将每一个标签/属性/注释/元素,都看作是一个DOM元素/节点/对象提供了一些操作元素的属性和方法
- 面试题
- HTML/XHTML/DHTML/XML分别是什么
- HTML 网页
- XHTML 更严格的HTML,HTML->XTML->HTML4.01
- DHTML 动态的网页,D=Dynamic 其实并不是新技术、新概念、是将现有技术的整合统称,在离线时,网页也具有动态效果
- DHTML:html+css+js(dom)
- XML 未知的标记语言,一切的标记都是自定义,数据格式
- DOM:原本时可以操作以恶结构化文档的HTML和XML,后来为了方便各类开发者分为了3部分
- *核心DOM:【无敌】,既可以操作HTML,又可以操作XHTML
- 缺点:API比较繁琐
- *HTML DOM:只能操作HTML,API简单,缺陷:比如部分属性只能访问标准属性,不能访问自定义属性
- XML DOM:只能操作XML,XML已经淘汰了---现在最流行的数据格式是JSON
- 开发建议:优先使用HTML DOM,HTML DOM 实现不了再用核心DOM进行补充
- *核心DOM:【无敌】,既可以操作HTML,又可以操作XHTML
- HTML/XHTML/DHTML/XML分别是什么
DOM树
- 树根-document,不需要创建,,一个页面只有一个document对象,由浏览器的JS解释器自动创建
- 作用:可以通过树根找到页面上的每一个DOM元素/节点/对象
每个DOM元素都有三大属性
- elem.nodeType:描述节点的类型
- document节点:9
- element节点:1
- attribute节点:2
- text节点:3
- elem.nodeValue:描述节点的值
- 以前有用:先拿到属性节点,再去用此属性去获取属性值
- ***elem.nodeName:描述节点的名字 e.target
- 拿到当前元素的标签名,判断xxx是什么标签
- 注意:返回的是一个全大写的标签名
*通过关系获取元素
- 父:xx.parentNode
- 子:xx.children --集合:只能找到儿子
- 第一个儿子:xx.firstElementChild
- 最后一个儿子: xx.lastElementChild
- 前一个兄弟:xx.previousElementSibling
- 后一个兄弟:xx.nextElementSibling
递归
- 简单来说就是函数中,又一次调用了函数自己
- 如何使用:遍历DOM树,专门用于遍历层级不明确的情况,既可以遍历层级不明确的DOM树,也可以遍历层级不明确的数据
- 如何使用:
-
样例
function 函数名(root){ 1、第一层要做什么直接做 2、判断有无下一级,若有再次调用此函数,但传入的实参是他的下一句元素 } 函数名(实际的根); -
算法:深度优先,优先遍历当前元素的子节点,子节点遍历完才会跳到兄弟节点
-
缺点:同时开启大量的函数调用,大量消耗内存,只有一个情况采用:【遍历层级不明确】
-
递归 VS 循环
- 递归:优点:直观、易用;缺点:性能比较低,尽量在层级不明确的时候使用
- 循环:优点:几乎不占有内存;缺点:难
-
专门遍历层级不明的DOM树API
- 步骤:2步
- 1、先创建出tw
- var tw=document.createTreeWalker(根元素,NodeFilter.SHOW_ELEMENT/SHOW_ALL)
- 2、tw对象过后,你会得到-个方法,反复调用nextNode方法找到下一个节点,迟早有一天会等于null,说明没找到
-
while((node=tw.nextNode0)!=nul){node.style.border="1px solid # 000";}
- 1、先创建出tw
- 缺陷:
- 自动的跳过根元素,根元素是不会做任何操作的
- 仅仅只能遍历层级不明确的DOM树,不能遍历层级不明确的数据
API直接找元素
- 根据HTML的特点去找元素
- ID :varelem = document.getElementById("id值");
- 标签名和className和Name:var elem = document.getElementsByTagName/ClassName/Name("标签名/类名");
- 根据CSS选择器找元素
- 单个元素
- document.querySelector("任意的css选择器")
- 强调:万一选择器匹配到多个,只会返回第一个,没找打返回null
- ***多个元素
- document.querySelectorAll("任意的css选择器")
- 强调:找到了返回集合,没找到返回空集合
- 单个元素
- 面试题:getXXX和querySelectorAll有什么区别
- getXXX:返回的是要个动态集合HTMLCollection
- 缺点:每次DOM树进行修改,都会悄悄再次查找元素,效率相对较低
- 优点:数据始终和DOM树实时挂钩
- querySelectorAll:返回的是要给动态集合NodeList
- 优点:每次不会悄悄查找,效率较高,而且还支持使用forEach
- getXXX:返回的是要个动态集合HTMLCollection
元素的内容
- elem.innerHTML: 获取或者设置开始标签到结束标签的HTML代码,没有兼容性问题的,可以识别标签
- 获取: elem.innerHTML
- 设置:elem.innerHTML="新内容"
- elem.textContent:获取或设置开始标签到结束标签之间的纯文本,有兼容性问题的(老IE不支持),不能识别标签
- 获取: elem.textContent
- 设置:elem.textContent="新内容"
- 老IE:elem.innerText 某次浏览器更新后,现在主流浏览器也支持此属性
- 为什么老IE不将就主流?–微软的,PC端只有windows系统和MAC系统,windows系统的使用的人多
- *input.value:获取或者设置表单控件的值----做正则验证
- 获取:input.value
- 设置: input.value = "新值"
元素的属性
- 获取属性值
- 核心DOM:elem.getAttribute("属性名")
- HTML DOM:elem.属性名
- 设置属性值
- 核心DOM:elem.setAttribute("属性名");
- HTML DOM: elem.属性名 = "属性值";
- 删除属性值
- 核心DOM:elem.removeAttribute("属性名");
- HTML DOM:elem.属性名=""–删除不推荐使用HTML DOM,删除不干净属性节点,有的属性光有属性名就已经具有功能了
- 判断有没有属性值
- 核心DOM:elem.hasAttribute("属性名")===仅仅只能判断有没有这个属性,不能判断出属性值是什么
- HTML DOM: elem.属性名!="";
- HTML DOM的缺陷
- 1、class需要写为class Name
- 2、不能操作自定义属性
- 开发中:优先使用HTML DOM ,HTML DOM 满足努努力再用核心DOM
元素的样式
-
内联样式:优先级最高,一定会覆盖其他样式,仅仅当前元素可用,不会牵一发动全身
- 获取样式:elem.style.css属性名;
- 设置样式:elem.style.css属性名="css属性值";
- 唯一的缺陷:获取样式时,只能获取到内联样式
-
样式表中的样式
//1、找到你想要操作的样式表 var sheet=document.styleSheets[1]; //2、获取样式表中所有的样式规则 var rules=sheet.cssRules; //3、找到自己想要操作的样式规则 var rule=rules[i]; //4、要么获取要么设置 console.log(rule.style.属性名); rule.style.属性名="属性值";
创建元素并渲染DOM树:3步
- 1、创建空标签
- var elem=document.createElement("标签名")
- 2、添加必要的属性和事件
- elem.属性名="属性值";
- elem.on事件名=function(){操作}
- 3、上树:将js内存中的新标签放到DOM树上
- 父元素.appendChild(elem) ----将elem追加到父元素里面作为最后一个孩子
- 父元素.insert Before(elem,已有子元素),将elem追加到父元素的已有子元素的前面,缺点:会影响到其他元素的下标
- 父元素.replaceChild(elem,已有子元素);将elem追加到父元素里面,但是会替换已有子元素
删除元素 elem.remove()
HTML DOM
- image对象:仅仅只是简化了创建语句
- 创建: var img=new Image() 《===》 var elem=document.createElement("img");
- 注意:不是人人都有构造函数创建方式
- form对象:简化查找元素
- 查找form元素 var form=document.forms[i];
- 查找form元素中的表单空间:var ip = form.elements[i];
- *专属事件: form.onsubmit=function(){//提交事件:只会在提交的一瞬间执行 return false //阻止提交}
- *select对象
- 属性:
- 1、select.options //得到select下的所有option标签,完全等效于xx.children();
- 2、select.selectedIndex;/得到当前选中项的下标,当时做二级联动就用到了他
- 方法:
- 1、select.add(option) ; //完全等效于appendChild
- 2、select.remove(i) //删除下标为i的option
- 专属事件:select.onchange=function()U//只有选中项发生变化了才会触发}
- 属性:
- *option 对象:仅仅只是简化了创建语句,但是非常牛逼
- 创建: var opt=new Option(innerHTML,value);
浏览器一共提供了3种弹出框
-
1、警告框:alert();
-
2、用户输入框:var user=prompt("提示文字","默认值");
-
3、用户输入框:var bool=confirm("提示文字");