1、*****Object:
1、*****继承:父对象的成员(属性和方法),子对象可以直接使用、
为什么:代码重用!节约内存空间!提升网站的性能!
何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中
2、***如何找到父对象(原型对象):保存一类子对象共有属性和共有方法的父对象:2种
1、子对象.__proto__;//前提:必须先有一个对象
2、构造函数名.prototype;//构造函数名,几乎人人都有,除了Math/Undefined/Null
3、*面试题:两链一包:
作用域链:查找变量
闭包:保护一个可以反复使用的局部变量的一种词法结构
原型链:每个对象都有一个属性:__proto__,可以一层一层的找到每个人的父亲,形成的一条链式结构,
就称之为叫做原型链
可以找到所有父对象的成员(属性和方法),作用:查找属性和【方法】
最顶层是Object的原型,上面放着我们眼熟的toString,怪不得人人都可以使用toString
JS种万物皆对象
4、有了原型对象,设置共有属性和共有的方法
1、原型对象.属性名=属性值
2、原型对象.方法名=function(){}
***笔试题1:判断自有和共有:
1、判断自有:
obj.hasOwnProperty("属性名");
如果结果为true,说明一定是自有,如果结果为false,可能是共有可能是没有
2、判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in 会自动在
整条圆形脸上进行查找,找到结果为true,找不到结果为false
说明是共有
}else{
说明是没有
}
完整版公式:
if(obj.hasOwnProperty("属性名")){
自有
}else{
if("属性名" in obj){
共有
}else{
没有
}
}
***笔试题2:修改/删除自有和共有
自有:修改:obj.属性名=新值;
删除:delete obj.属性名;
共有:修改:obj.__proto__.属性名=新值;
删除:delete obj.__proto__.属性名;
共有千万不要操作本地:
修改:会在本地添加同名属性
删除:没有效果
***笔试题3:如何为老IE的数组添加indexOf方法:如何为一类人添加某个方法
原理:
if(Array.prototype.indexOf===undefined){//老IE
Array.prototype.indexOf=function(key,starti){
starti===undefined&&(starti=0);
for(var i=starti;i<this.length;i++){
if(key==this[i]){
return i;
}
}
return -1;
}
}
***笔试题4:判断x是不是一个数组:4种方式
1、判断x是不是继承自Array.prototype:
Array.prototype.isPrototypeOf(x);
2、判断x是不是由Array这个构造函数创建的
x instanceof Array
3、只有数组可用:ES5提供的一个叫Array.isArray(x);
4、最麻烦:输出【对象的字符串】形式
在Object的原型上保存着最原始的toString方法
最原始的toString方法输出:[object 构造函数名]
***多态:子对象觉得父对象的成员不好用,在本地定义了同名成员,覆盖了父对象的成员
如果我们这道题能够跳过数组的爸爸,拿到数组的爷爷上面的toString也就能判断了
固定套路:借用:Object.prototype.toString.apply(x);
***笔试题5:实现自定义继承:
1、两个对象之间的继承:
子对象.__proto__=父对象
2、多个对象之间设置继承:
构造函数名.prototype=父对象
注意时机:一定要在创建对象之前
1、ES5带来了新特性:带来了一些新的API操作
1、保护对象:保护对象的属性和方法
如何保护:2种方式
1、四大特性:每一个属性都有四大特性
{
value: 1001, //实际保存值的地方
writable: true,//开关,控制着此属性是否可以被修改
enumerable: true,//开关,控制着此属性是否可以被for in循环遍历到
configurable: true,//开关,控制着此属性是否可以被删除
}
如何设置四大特性:
Object.defineProperties(对象名,{
"属性名":{四大特性},
...
})
2、三个级别:
1、防扩展:禁止给对象添加属性
Object.preventExtensions(obj);
2、密封:禁止给对象添加属性和删除元素
Object.seal(obj);
3、冻结:禁止给对象添加属性和删除元素和修改元素
Object.freeze(obj);
其实保护对象对于我们程序员来说可有可无:
1、如果你用的是面向过程,你保护个屁
2、别人基本不可能知道我们的对象叫什么名字
3、前辈们几乎都没有保护过对象,你保护个屁
2、*****数组的新的API:3组6个
1、判断:2个:
1、every 每一个 - 要求每一个元素都要满足我们的条件,结果才为true,
只要有一个不满足结果就为false,类似于&&
var bool=arr.every(function(val,i,arr){
return 判断条件
})
val - 当前元素
i - 当前元素的下标
arr - 数组本身,前辈们提供了3个,不代表3个对我都有用
2、some 有一些 - 要求只要一个元素都要满足我们的条件,结果就为true,
只要全部不满足结果就为false,类似于||
var bool=arr.some(function(val,i,arr){
return 判断条件
})
2、遍历:把每一个元素拿出来执行相同 或 相似的操作:2个
1、forEach:遍历数组,直接修改原数组
arr.forEach(function(val,i,arr){
操作
})
2、Map:遍历数组,不修改原数组,返回一个新数组
var newArr=arr.map(function(val,i,arr){
return 操作
})
3、汇总和过滤:
过滤:不会修改原数组,但是会得到你过滤出来的新数组
var subArr=arr.filter(function(val,i,arr){
return 判断条件;
})
汇总:把数组中的每一个元素汇总到一起
var sum=arr.reduce(function(prev,val,i,arr){
return prev+val;
},基础值)
以上6个API底层都是for循环,目的 - 简化for循环,暂时可能还会用到一些for循环
2、ES6:简化ECMAScript - 语法较大的变化
1、*模板字符串:可以在字符串中放入变量 - 不需要再做字符串拼接,在字符串中实现了一个简单的js的环境
语法:`我的名字叫${name}`
2、*块级作用域:尽量以后【优先】使用let创建变量
let 变量名=值;
作用:1、禁止声明提前
2、添加了块级作用域,一个{}就是一个块
3、记录着当前触发事件的元素的下标
3、***箭头函数:简化回调函数:
公式:去掉function,()和{}之间添加=>,形参如果只有一个,则省略掉(),函数体如果只有一句话,省略{},
函数体只有一句话并且是return,return和{}都省略
特殊:千万不要将事件也简化为箭头函数 - 暂时
4、for...of循环:
for(var v of 数组名){
v;//value当前值
}
缺点:1、不能修改原数组,只能返回新数组
2、不能遍历hash数组,意味着也不能遍历对象,只能遍历索引数组
1、什么是DOM:Document Object Model(文档对象模型) - 操作HTML文档
将每个元素/标签/文本/属性/注释都会看作是一个DOM节点/元素/对象
面试题:HTML/XHTML/DHTML/XML?
1、HTML - 网页
2、XHTML - 更严格的网页
3、DHTML - Dynamic:动态的网页,其实并不是新技术,也不是新概念,而是现有技术的一个整合统称:
让我们的网页再离线版也能具有动态效果
DHTML:HTML+CSS+JS
4、XML - 全部自定义,数据格式:淘汰了:JSON数据格式
DOM:原本是可以操作一切结构化文档的 HTML 和 XML,后来为了方便各类开发者分为了3个方向
1、核心DOM:【无敌】,既可以操作HTML也可以操作XML
缺点:API比较繁琐,getAttribute/setAttribute()
2、HTML DOM:只能操作HTML,API简单:缺点:自定义的东西操作不了
3、XML DOM:只能操作XML - 不会学习他
开发建议:优先使用HTML DOM,HTML DOM实现不了再用核心DOM补充
2、DOM树:树根:document - 不需创建,一个页面只有一个document,由js解释器自动创建
作用:通过树根,可以找到想要的DOM元素/节点/对象
3、每个DOM元素都有三大属性:
1、elem.nodeType:描述节点类型
document 节点:9
element 节点:1
attribute 节点:2
text 节点:3
以前有用:判断xx是不是一个页面元素 - 因为以前我们的方法和你们现在的方法不一样
2、elem.nodeValue:获取【属性节点】的值
3、***elem.nodeName:获取节点名称/标签名
注意:返回的是一个全大写组成的标签名
4、*通过 关系 获取元素
父:xx.parentNode
子:xx.children - 只能找到儿子
第一个儿子:xx.firstElementChild;
最后一个儿子:xx.lastElementChild;
前一个兄弟:xx.previousElementSibling;
后一个兄弟:xx.nextElementSibling;
5、*****递归:简单来说就是函数中再次调用了函数本身,迟早有一天会停下来
何时使用:遍历DOM树,专门用于【遍历层级不明确】的树状结构
如何使用:
function 函数名(根){
1、第一层要做什么直接做
2、判断它有没有下一级,如果有下一级,则再次调用此函数,但是传入的实参是自己的下一级
}
函数名(实际的根)
算法:深度优先!优先遍历当前节点的子节点,子节点遍历完才会跳到兄弟节点
缺点:同时开启大量的函数调用,浪费的内存,只有一个情况:【遍历层级不明确】
递归 vs 循环
递归:优点:直观,易用
缺点:性能较差
循环:优点:性能较好
缺点:难得一批
6、遍历层级不明确的API:TreeWalker:一个在DOM树上行走的人
缺点:只能遍历层级不明确的DOM树,不能遍历层级不明确的数据
如何使用:2步
1、创建TW
var tw=document.createTreeWalker(根元素,NodeFilter.SHOW_ELEMENT);
2、反复调用tw的nextNode函数找到节点
while((node=tw.nextNode())!=null){
node要干什么
}
7、*直接找元素:
1、通过HTML的一些特点找元素
你会的:id/class/标签
新的:通过name找元素:var elems=document.getElementsByName("name值")
2、通过css选择器查找元素:2个方法 - 更适合用于复杂查找(多句才能找到最终元素)
1、var elem=document.querySelector("任意css选择器");
只会找到一个元素,如何同时匹配多个,也只会返回第一个
没找到null
2、var elem=document.querySelectorAll("任意css选择器");
找到了是一个集合
没找到是一个空集合
面试题:getXXXX和queryXXXX的区别?
返回的结果不一样:
1、getXXXX:返回的是一个动态集合HTMLCollection
特点:每一次DOM树修改过后,js都会悄悄的再次查找元素,保证数据和页面对应,
效率相对较低
2、queryXXX:返回的是一个静态集合Nodelist
特点:只管查找的一次找出来的结果,后续DOM树的修改,我们的数据也不会变化,
效率相对较高
优点:1、查找简单
2、还支持forEach
总结:找元素的方式:
1、直接找元素:getXXX、queryXXX
2、通过节点的关系
3、层级不明确的情况 - 递归
操作元素
1、元素的内容
1、*elem.innerHTML:获取或者设置开始标签到结束标签之间的HTML代码,没有兼容性问题,可以识别标签
获取:elem.innerHTML
设置:elem.innerHTML="新内容"
2、elem.textContent:获取或者设置开始标签到结束标签之间的纯文本,但是有兼容性问题,不可以识别标签
获取:elem.textContent
设置:elem.textContent="新文本"
特殊:老IE才叫elem.innerText;//第一见到小三上位,反而所有的主流浏览器来将就了老IE
3、*input.value:获取或设置单标签(input)的内容准备的
获取:input.value
设置:input.value="新值"
2、元素的属性:
1、*获取属性值:
核心DOM:elem.getAttribute("属性名")
HTML DOM:elem.属性名;
2、*设置属性值:
核心DOM:elem.setAttribute("属性名","属性值");
HTML DOM:elem.属性名="新值";
3、删除属性值:
*核心DOM:elem.removeAttribute("属性名")
HTML DOM:elem.属性名="" - 虽然简单,但是有的情况会删不干净,有的属性删不干净依然会有功能比如:href
4、判断有没有 - 垃圾
核心DOM:elem.hasAttribute("属性名");
HTML DOM:elem.属性名!="";
返回的结果是一个布尔值,只能判断有没有,不能判断是什么
HTML DOM:有两个小缺陷:
1、class需要写为className
2、一切自定属性不能操作
3、删除删不干净,依然会留下属性节点
3、元素的样式:
1、内联样式:
获取:elem.style.css属性名
设置:elem.style.css属性名="css属性值"
特殊:
1、css属性名如果有横线要省略,变为小驼峰命名法
2、获取的时候只能获取到内联样式,这个小缺陷可以忽略不计
2、样式表: - 不推荐
//获取到你想要操作的某个样式表
var sheet=document.styleSheets[i];
//获取样式表中所有的样式规则
var rules=sheet.cssRules;
//选出自己想要操作的某个规则
var rule=rules[i];
//操作
获取:console.log(rule.style.css属性名);
设置:rule.style.css属性名="css属性值"
为什么更推荐内联:
1、不会牵一发动全身
2、优先级一定是最高的
1、创建元素&渲染页面:3步
1、先创建空标签
var elem=document.createElement("标签名");
2、为其添加必要属性和事件
elem.属性名="属性值";
elem.on事件名=function(){操作}
3、渲染DOM树/页面:3种
*1、父元素.appendChild(elem);//elem追加到父元素里面,当最后一个儿子
2、父元素.insertBefore(elem,已有子元素);//elem追加到父元素里面,插入在已有子元素的前面 - 影响其他元素的下标,不推荐
3、父元素.replaceChild(elem,已有子元素);//elem追加到父元素里面,新元素替换掉已有子元素 - 不推荐
2、删除元素:elem.remove();
HTML DOM:简化核心DOM开发,核心语法太繁琐,提供了一些常用的对象
1、image对象:垃圾,仅仅只是简化了创建部分
创建:var img=new Image(); - 不是人人都可以简化为构造函数创建方式
2、form对象:垃圾,仅仅只是简化了查找部分
查找form元素:var form=document.forms[i];
以及找表单控件:var inp=form.elements[i];
3、*select对象:牛逼:提供了2个属性,2个方法,1个事件
属性:
1、select.options === select.children; 获取select里面的所有的option
2、*select.selectedIndex - 获取当前选中项的下标,一定是搭配联动一起使用
方法:
1、*sel.add(option); - 完全相当于appendChild
2、elem.remove(i); - 当时当remove删除元素出现过后,他就当场淘汰了
专属事件:onchange - 选中项发生了变化才会触发
4、*option对象:仅仅只是简化了创建部分
创建:var opt=new Option("innerHTML","value")
一句话完成4个操作:sel.add(new Option("榴莲","榴莲"));
1、创建了空的option
2、为option设置了innerHTML
3、为option设置了value
4、上树
用户确认框:var bool=confirm("提示文字");