Object:
继承:
父对象的属性和【方法】,子对象可以直接使用;
为什么要:代码重用,节约内存!提升网站的性能!
何时使用:只要多个子对象公用的属性和方法,都要集中在父对象。
如何找到父对象(原型对象):
保存一个类型的属性和方法有两种:
1.子对象.__proto__;前提是必须要有一个子对象。
2.构造函数名.prototype;构造函数名,几乎人人都有,除了undefined/null/Math。
面试题:两链一包
闭包:保护一个可以反复使用的局部变量的词法结构。
作用域链:作用域变量的是使用规则,查找变量。
原型链:每个对象都有一个属性:__proto__,可以一层一层的找到每层的父级,形成的一条链式结构,就叫做原型链。
作用:可以找到父级所有的属性和【方法】
最顶层是Object,上面放着熟悉的toString,所以所有人都可以使用toString;
js中万物皆对象。
有了原型对象,设置共有属性和共有的方法;
1,原型对象.属性名=属性值;
2,原型对象.方法名=function(){}
笔试题:判断共有和自有:
1,判断自有:
对象名.hasOwnProperty("属性名");
结果为true,说明一定是自有,结果是false,可能是共有,也能是没有。
2,判断共有:
对象名.hasOwnProperty("属性名")==false&&("属性名" in 对象名)?说明是共有:没有;
3,完整版判断共有和自有:
if(对象名.hasOwnProperty("属性名")==true){
自有
}else {
if("属性名" in 对象名){
共有
}else{
没有
}
}
笔试题:修改/删除自有和共有
自有:修改:对象名.属性名=新值;
删除:delete 对象名.属性名;
共有:修改:对象名.__proto__.属性名=新值
删除:delete 对象名.__proto__.属性名;
共有千万不要操作本地:
修改:会在本地添加同名属性;
删除:没有任何效果。
笔试题:为老IE添加indexOf方法:也可以是为一类人添加某个方法
原理:
if(Arrar.prototype.indexOf===undefined){ ->判定为true时说明是老IE
Arrar.prototype.indexOf=function(key,starti){
starti==undefined&&starti=0;
for(var i=0;i<this.length;i++){
key==this[i]&&return i;
}
return -1;
}
}
笔试题:判断某个对象X是不是数组; 4种方法:
1,判断X是不是继承自Array.prototype:
Array.prototype.isPrototypeOf(X);
2,判断X是不是由这个构造函数创建的:
X instanceof Array;
3,只有数组可用:
Array.isArray(X);
4,最麻烦:输出【对象的字符串】形式:
在Object上保留着最原始的toString方法
用原始的toString方法输出的结果:[object 构造函数名]
多态:子对象觉得父对象的成员不好用,就在本地定义了同名成员,覆盖了父对象的成员;
如果这里我们可以跳过数组的父对象,拿到数组的顶级对象上的toString也就能判断了
固定公式:借用: Object.prototype.toString.apply(X);
ES5: 给我们带来了新的API
保护对象:保护对象的成员(属性和方法)
如何保护:
1.四大特性:
Object.defineProperties(对象名,{
"属性名":{
value:实际保存的值,
writable:true/false 开关 -> 控制着这个对象能否被修改
enumerable:true/false 开关 -> 控制着这个对象能否被for in 遍历
configurable:ture/false 开关 -> 控制着这个对象能否被删除 这一句是总开管,一旦设置为false,其他特性不可被修改,一旦设置为false不可逆。
}
}
2,三个级别
1、防拓展:禁止给对象添加新属性;
Object.preventExtensions(对象名);
2,密封:禁止给对象添加和删除属性;
Object.seal(对象名);
3,冻结:禁止给对象添加,删除,修改属性;
Object.freeze(对象名);
其实保护对象对我们没什么意义:
1,如果你是面向过程开发,对象都没有你保护个p
2,别人根本不可能知道我们的对象名是什么
3,前辈们的代码都没有保护,你保护个寂寞
数组的API: 3组 6个
1、判断:
判断的结果一定是一个boolea值;
语法:var bool=arr.every(function(val,i,arr){
return 判断条件;
})
val:当前值 i:当前下标 arr:数组本身
every:每一个 -> 要求每一个元素都要满足,只要有一个满足着为false;都满足才为true。类似于我们之前的&&
语法:var bool=arr.some(function(val,i,arr){
return 判断条件;
})
some:有一些 -> 只要有一个元素满足,则结果为true;都不满足结果为false。类似我们之气的||
2、遍历:
将数组中的每一个元素拿出来执行相同 或者 相似的操作;
forEach:遍历数组,直接修改原数组。
语法:arr.forEach(function(val,i,arr){
直接做操作
})
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循环
Object.create(): 根据父对象创建子对象,继承已经设置好了
语法:var 子对象=Object.create(父对象,{
"自有属性名":{
四大特性;
...
}
});
面试题:严格模式
开启:在你的任何作用域之前加上一句:"use strict";
功能:1、禁止给为声明的变量赋值 - 解决全局污染;
2、把静默失败升级为报错。
call/apply/bind:不是自己的方法也可以使用,笔试面试很容易遇到。
call/apply :暂时替换了函数中this的指向 - 借用
语法:函数名.call(借用对象,实参,...) 单独传入每一个实参;
函数名.apply(借用对象,[实参,...]) 只能传入一个数组参数,apply会悄悄地将数组打散。
强调:call/apply,相当于立即调用函数,立即执行;
bind:永久的替换了函数中this的指向 - 买
语法:var 新函数名=函数名.bind(指定对象,永久实参,...)
注意:1、函数中this的指向会永久的指向【指定对象】,别人都借不走。
2、相当于创建了一个和原函数一摸一样功能的新函数。
3、可以将函数中的部分参数永久固定住。
4、不是立即执行的,需要调用
强调:bind绑定的值不能别call/apply替换,借用。
个人更推荐call/apply,不会创建新的函数,可以节约内存。
固定套路:
Math.max/min.apply(Math.arr);
Object.prototype.toString.call/apply(arr);
类数组转换成普通数组:
类数组名称=Array.prototype.slice.cll/apply(类数组);
ES6:简化ECMAScript - 语法有较大的变化
1,模板字符串 - 可以在字符串中放入变量 - 不需要再拼接字符串,在字符串中实现了一个简单的js执行环境;
语法:\`我的名字叫${name}\`
2,块级作用域: 以后能用let就用let声明
语法:let 变量名=值;
作用:1、禁止声明提前;
2、添加了块级作用域,一个{}就是一个块级作用域;
3、记录着当前触发事件的元素的下标;
3,箭头函数:简化回调函数;
公式:去掉function,在(){}之间添加=> :()=>{},
如果形参只有一个可以省略小括号(),
如果操作只有一句话可以省略大括号{},
如果操作只有一句话且这句话是return,那么return和大括号{}都省略。
特殊:千万不要将事件也转化成箭头函数(暂时),会有this指向问题。
4,for...of...循环 ---- 垃圾
for(var val of 数组名){
val==当前值;
}
为什么垃圾:有三个缺点;
1、不能修改原数组,只会返回一个新数组。
2、不能遍历hash数组,也就意味着不能遍历对象,只能遍历索引数组。
3、不能获得当前下标。
DOM
什么是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,后来为了方便各类开发者,就分为了三个部分;
1、核心DOM:【无敌】,即可操作HTML也可以操作XML
缺点:API比较繁琐
2、HTML:只能操作HTML,优点:API简单; 缺点:自定义的东西操作不了;
3、XML:只能操作XML,不会学习它。
开发建议:优先使用HTML,HTML实现不了的,再用核心DOM。
DOM树:树根:Document 不许要我们创建,一个页面只有一个Document,由JS解释器自行创建。
作用:通过树根,我们可以找到任何想要的DOM元素/节点/对象。
每个DOM都有三个特性:
1、elem.nodeType:描述节点的类型;
document 节点:9
element 节点:1
attribute 节点:2
text 节点:3
以前有用,可以判断某个XX是不是页面元素,现在又新的方法。
2、elem.nodeValue:获取【属性节点】的值;
3、elem.nodeName:获取节点【名称/标签名】;
!!!注意:返回的是一个全**大写**组成的标签名。
通过关系找元素; 前提是必须先找到一个元素
1、找到父元素: 元素名.parentNode;
2、找到所有子元素: 元素名.children;
3、找到第一个子元素: 元素名.firstElementchild;
4、找到最后一个子元素: 元素名.lastElementchild;
5、找到上一个同级元素: 元素名.previousElementSibling;
6、找到下一个同级元素: 元素名.nextElementSibling;
递归: 简单来说就是在函数中再次调用函数本身,满足条件后停止。
何时使用:遍历DOM树,专门用于【层级不明确】的树状结构;
如何使用:
function 函数名(根元素){
1、要做什么就直接做;
2、判断它有没有下一级,如果有下一级,则再次调用此函数,并将此函数的参数设置为这个元素的下一级;
}
函数名(实际的根);
算法:深度优先,优先遍历当前节点的子节点,子节点遍历完再跳到i兄弟节点;
缺点:同时开启大量的函数调用,浪费内存;只有一个情况会使用到【层级不明确】
面试:递归和纯循环的区别
递归:直观,易用 但是会 浪费内存,效率较低;
循环:难用的一B,但是相对效率较高;
遍历层级不明确的API:TreeWalker -> 行走再DOM树上的人
缺点:只能遍历层级不明确的DOM树,不能遍历层级不明确的数据;
如何使用:2步;
1、创建TW:
var tw=document.creartTreeWalker(根元素,NodeFiltes.SHOW_ELEMENT)
2、反复调用:
while((node=tw.nextNode())!=null){
node要干什么
}
直接找元素:
1、通过HTML属性找元素:
之前教过:class/id/标签名
新的:通过name找元素:var 变量名=document.getElementsByName("Name值")
2、通过css选择器找元素:
1、var 变量名=document.querySelector("任意CSS选择器")
只会找到一个元素,如果同时匹配到多个,也是会返回第一个;
没有找到返回的是null;
2、var 变量名=document.querySelectorAll("任意CSS选择器")
找的所有匹配倒是元素,找到了是一个集合;
没有找到返回的是一个空集合;
面试题:getXXX和quetyXXXX的区别?
返回的结果不一样;
1、getXXXX:返回的是一个动态集合HTMLCollection
特点:每一次DOM树修改后,js都会悄悄地再次查找元素,保证数据和页面相对应,效率相对较低;
2、queryXXX:返回的是一个静态集合Nodelist
特点:只管第一次查找出来的结果,后续DOM树的修改,我们的数据也不会跟着变化,效率相对较高;
优点:1、查找简单
2、还支持forEach
创建元素&渲染页面:
核心DOM_渲染页面
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追加到父元素里面,新元素替换掉已有子元素 - 不推荐
删除元素:elem.remove();
核心DOM学习完毕,你已经无敌了:
总结一句话DOM可以干什么:
增删改查DOM元素(元素、文本、属性、样式)
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("提示文字");