JavaScript详细解析
Web API:
- API应用程序编程接口,系统或他人事先定义好的函数和方法,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组历程的能力。
- Web API是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)
BOM浏览器对象模型
,通过BOM可以操作浏览器窗口,比如弹出框,控制浏览器跳转,获取分辨率等。DOM文档对象模型
,提供一套操作页面元素的API,DOM处理可扩展标记语言,基于文档树的API,处理过程中整个文档都表示在存储器中。
DOM:
- 获取元素:如若id没写则返回null,获取的属性不存在返回undefined。
⑴var a=document.getElementById("id");
⑵var b=document.getElementsByTagName("div");
伪数组,元素的集合HTMLCollection。
⑶var c=document.getElementsByName("name");
放在表单的标签元素需要写name属性。节点的集合Nodelist,如果获取某一项的触发事件需要c[0].onclick
。
⑷var d=document.getElementsByClassName("classname");
类选择器。
⑸var e=document.querySelector(".e");
query查询Selector选择器,H5新增,只查找返回第一个。
var es=document.querySelectorAll(".e");
var texts=document.querySelectorAll
("input[type=text]");
属性选择器在IE8中都返回Nodelist集合。
console.dir(a);
打印对象,最下方就是对象类型,所有元素都派生于htmlElement
-
操作元素:设置元素的属性或调用元素的方法。
⑴元素的属性包含了标签对应的属性。★
元素(对象)封装标签的属性。
⑵设置元素格式btn.onclick
与对象.属性用法相同,区别是这是注册事件。当触发事件时系统自动检测调用。
⑶img.id,img.className
赋值、打印。 -
自定义属性:在html标签自定义属性。
⑴获取自定义属性:box.getAttribute("stuId");
也可获取标签本身具有的属性,但一般用box.id。
⑵设置(添加)自定义属性:box.setAttribute("try","value");
也可设置标签本身具有的属性。
⑶移除属性:box.removeAttribute("try");
⑷box.abc
不可以设置标签的自定义属性,但是box对象具有了abc属性。 -
样式操作:
⑴设置类样式:box.className="bg";
类样式赋值会覆盖其他类样式,使用box.className=box.className.replace("hide","show");
可以指定替换样式。
⑵设置style:box.style.width="200px";
获取标签的style属性中的字符串:box.style.cssText;
而标签可以直接设置table.border;box.style
不能获取id或类选择器设置的属性。 -
事件:btn.
onclick
。
⑴事件源:this-触发事件的元素
⑵事件名称:类似click
⑶事件处理程序:类似onclick
可以在事件中注册事件。 -
this是什么:
⑴作为函数调用–>是window顶级对象但严格模式下是undefined。
⑵作为对象的方法调用–>是调用该方法的对象
⑶作为构造函数调用–>通过构造函数创建的对象
⑷事件处理函数中this–>触发事件的对象,事件源。当注册事件在循环中进行时必须用this代替触发元素。apply call
(?)
⑸定时器、forEach中的函数中的this是window。
⑹谁调用this就是谁。 -
innerText,innerHtml都是获取标签之间的内容。
获取区别:innerHtml
会把标签也获取到,而innerText
会把标签过滤掉。
设置区别:innerText如果设置的内容有标签会自动转义,innerHtml如果设置的内容有标签会解析标签,并挂载到DOM树。
注意:innerHtml不是标准的DOM属性,innerText是最早IE增加的属性,老版本firefox不支持此属性,它使用textContent
-
当标签属性只有一个值的情况,一般DOM元素对应的属性类型是布尔类型。只有是非两种选择,就用布尔值true,false当标记。
-
表单提交时如果不满足提交条件则
return false
。onfocus
获取焦点,onblur
失去焦点。 -
当DOM树发生更改,游览器会立即渲染、重新绘制。
-
节点类型:
⑴元素节点document.getElementById();
nodeName
标签名称,nodeType
节点类型1,nodeValue
始终为null。
⑵属性节点:box.getAttributeNode("id");
nodeName
属性名称,nodeType
节点类型2,nodeValue
属性值。
⑶文本节点是换行留下的空白,标签之间的文本属于元素节点。nodeType
节点类型3,nodeValue
是换行符加一些空格。
⑷模拟文档树类型:先创建一个Node构造函数,然后创建每个元素节点,利用html.children.push("BODY");
⑸节点层级:
⒈父元素parentNode;
⒉子节点childNodes
,子元素children
。
第一个子节点firstChild
,第一个子元素firstElementChild
;
⒊最后一个子节点lastChild
,最后一个子元素lastElementChild
,用父节点调用。
⒋下一个兄弟节点nextSibling
,下一个兄弟元素nextElementSibling
;
⒌上一个兄弟节点previousSibling
,上一个兄弟元素previousElementSibling
。
⑹动态创建列表:★
createElement("ul");
创建一个DOM对象。
box.appendChild(ul);
往末尾追加对象。
box.insertBefore(div,fistEle);
指定插入fistEle之前。
ul.replaceChild(div,ul.children[0]);
替换子元素。
box.removeChild(li);
移除一个子元素。
innerHtml="";
移除所有子元素,不会删除元素身上的事件对应的函数,内存泄露。
使用for循环结合数组动态添加内容。
documentElement就是html标签。
DOM详细:
-
void关键字可以任意编写JS代码,但返回的都是undefined。
-
如果有循环里给元素注册事件的情况,需要在循环外定义函数,并把这个函数的函数名赋值给事件处理程序,提高性能。
-
动态创建元素:这两个都不用,一般用createElement。
⑴事件中使用document.write();
会把整个网页覆盖。
⑵arr.push("<ul>");arr.push("</ul>");
box.innerHtml=arr.join("");
效率更高,只渲染一次。
data.forEach遍历数组,参数是一个函数,这个函数有两个参数,第一个参数是数组中的元素,第二个参数是索引。 -
数组、集合删除一项后索引会重新排列。
所以当要删除所有子元素时将循环中div.children[0];始终设为0。 -
给同一个元素注册多个事件处理函数:
btn.addEventListener("click",btnClick,false);
可以冒泡或捕获。
第一个参数为事件名称,不带on;第二个参数是事件处理函数★,第三个参数是事件冒泡/事件捕获。true捕获,false冒泡。 -
给元素移除事件:
⑴btn.onclick=function(){this.onclick=null;};
⑵btn.addEventListener("click",btnClick,false);
function btnClick(){this.removeEventListener("click",btnClick,false);};
⑶低版本detachEvent("onclick",btnClick);
-
事件三个阶段(事件流):捕获,目标,冒泡。
事件捕获:一级一级向下传递。
事件目标:执行当前点击的元素的事件处理函数。
事件冒泡:一级一级向上传递。onclick。 -
事件委托:循环处理太麻烦所以转交给父元素处理,然后找到子元素(系统会把事件发生时的一些数据传递给事件处理函数)
ul.onclick=function(e){e.target.style.backgroundColor="red";}
e是事件对象,e.target是真正触发事件的对象li,目标对象,始终不变。 -
事件对象:默认是事件冒泡。
⑴e.type
获取事件名称,e.clientX
是鼠标在可视区域的位置,e.pageX
是鼠标在页面中的位置;
⑵e.eventPhase
:1是捕获阶段,2是目标阶段,3是冒泡阶段。
⑶e.currentTarget
调用事件处理函数的元素,就是冒泡的当前对象与this一样。
e.stopPropagation();
方法阻止事件冒泡。
e.preventDefault();
方法阻止默认行为。
⑷键盘事件:onkeydown
按下时触发,onkeyup
抬起时触发。e.keyCode
键盘码。
box.focus();
让元素获取焦点。
⑸e有兼容性问题,IE9之前版本不支持,使用window.event
。
BOM: 游览器的顶级对象是window。
- 使用window下的成员window可以省略
alert();
prompt();
confirm();
- 内置对象Array,function等等不是window里的,但function名是。但name,top是window属性,top只读不可更改。★
- onload是页面(DOM元素、外部文件)加载完毕之后执行。
onunlaod当关闭网页执行。
onload=function(){
var box =document.getElementById("div");
}
-
定时器:不考虑调用,写出来就能运行;
⑴setTimeout(function(){location.href="http..."; },5000);
–> 五秒后跳转,clearTimeout是取消跳转。
⑵setInterval(function(){},1000);
间隔一段时间做一段事。
⑶setTimeout
和setInterval
里面的参数function()可以换成在外面定义的函数名
;
⑷clearInterval
和clearTimeout
可以在setTimeout和setInterval里面使用,但要给set设置变量接收返回值,如var a=setInterval(function(){clearInterval(a);},1000;);
-
location对象:
⑴URL统一资源定位符:scheme(协议)://host(端口):port/path(路径)?query(查询)#fragment
⑵属性:href / search / hash
⑶方法:assign();
reload();
replace();
reload(true);
会强制从服务器强制获取刷新界面如ctrl+f5,false可能会读取缓存;
assign("http..."); / replace("https...")
都是跳转,前者会记录历史,后者不会。 -
history对象:
history.forward(); / history.go(1);
前进;
history.back(); / history.go(-1);
后退; -
navigator对象:
navigator.userAgen
t可以获取当前设备信息,在控制台的Network的Headers查看。 -
进程和线程:进程里有很多线程。
但却是单线程执行JavaScript代码,先执行主线程,才会考虑事件或定时器的任务
当遇到事件或定时器会放进任务队列。任务队列:先进先出。 -
拖拽效果:给document注册
onmousedown
和onmouseup
事件。
特效:
-
偏移量:offsetLeft盒子左边框和左边offsetParent的距离,offsetTop盒子上边框和上面offsetParent的距离;
offsetWidth
盒子的宽度(加上内边距,边框)offsetHeight
盒子的高度(加上内边距,边框)offsetParent
一般是body,父盒子设置position后为父盒子。 -
onmouseover和onmouseout会触发事件冒泡,在IE中问题大,用
onmouseenter
和onmouseleave
代替。 -
scrollHeight
和scrollWidth
用来计算滚动条滚动出去的大小,内容+padding,不包括边框。 -
offset需要具体问题具体分析,放大镜需要设置一元一次方程、比例和变量即是
大图片移动的距离=mask移动的距离*大图片最大能移动的距离/mask最大能移动的距离
,然后设置它的style.left与top。 -
clientWidth
、clientWidth
不包括边框也不包括滚动出去的距离。
clientTop
、clientLeft
就是盒子边框。 -
this.offsetLeft(box.offsetLeft);
左偏移
this.offsetTop(box.offsetTop);
上偏移量;
动画: 😉
-
计时器设置动画,动态改变定位的left或者top的值。
current=box.offsetLeft;
设置当前坐标,
step=10;步进,target=500;停止位置。 -
让每一个执行动画的元素记录自己的计时器。
element.timerId=setInterval(fn,2);
判断之前是否有定时器,如果有则清除定时器,保证点几次都走同样的速度。 -
当前位置current>目标位置target则setp取负step=-Math.abs(step);当前位置与目标位置的差小于步进则将left设为目标位置,然后清除计时器。
-
cloneNode(true);会复制子元素,而false自会复制自身不会复制子元素。
-
轮播图:
⑴根据img数量动态创建列表
⑵移上显示左右图标,离开隐藏
⑶点击圆点切换对应图片
⑷点击左右剪头切换图片
⑸自动滚动 -
回到顶部:
⑴获取滚动出去的距离getScrollTop().scrollTop;
⑵设置一个范围判断类样式的改变。
⑶点击置顶按钮获取当前滚动出去的距离。
⑷以动画形式回到目标位置0。
面向对象:(具体)
-
对象是单个事物的抽象。一本书、一辆汽车、一个人、一个数据库、一张网页。
-
对象是一个容器,封装了属性和方法。数据集或功能集。
无序属性的集合,其属性可以包含基本值、对象或者函数。 -
每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。具有灵活、代码可复用、高度模块化等特点。
-
构造函数是构造对象的函数。p1.constructor构造器,构造函数,可以获取创建p1的类型。
-
构造函数中的方法会因为每次创建对象而开辟空间造成资源浪费,所以需要将方法写在外面,用
Person.prototype.sayHI=function(){};
原型对象定义方法、通用属性。静态成员才是独属调用Person的。 -
当该对象拥有很多方法时则使用
Person.prototype={a:function(){}};
当重新设置构造函数的prototype,一定要重新设置constructor属性。这是因为普通对象没有constructor,只有构造函数的原型对象才有constructor属性。 -
系统内置对象的构造函数都是只读的,只能增加方法或属性:
Person.prototype.getSum=function(){};
-
每一个对象都有__proto__,都指向构造函数的prototype。
-
构造函数、实例、原型三者之间的关系:
构造函数中的属性Person.prototype属于原型对象,原型对象中Person.prototype.
constructor属于构造函数;构造函数new
Person()是实例对象,实例p1.__proto__属于原型对象。 -
原型对象中的原型对象,就是原型链。下级是Object,最早都是Person的原型。
Object.prototype===p1.proto.proto。最终是null,这是访问过程。 -
设置属性不关心原型链,即使原型链有test属性也直接给对象增加一个test属性p1.test=“abc”;
贪吃蛇案例:
-
随机生成方块:构造函数box,属性拥有backgroundColor、width、height、x、y方法有render渲染(创建设置style),random随机生成盒子位置,(地图高度除以盒子高度-1再乘以盒子高度。)
-
创建一个js工具对象,整个项目共享。
-
创建食物对象,利用自调用函数避免全局变量命名冲突,在里面让外部可以访问构造函数
window.Food=Food;
-
创建蛇对象,render方法中新开forEach函数、定时器中的this会改变成window,设置一个值记录this。
-
再抽象一个对象控制游戏的逻辑。
-
函数是对象,拥有属性prototype,bind方法等。bind中的第一个参数可以改变函数中的this指向。
-
开发时分散写js,发布网站时合并成一个js文件。
-
存在多个自调用函数而前一个没写分号作为结尾则会报错,所以一定要在自调用函数前面加分号。
-
自调用函数的形参和实参都会传入window和undefined。可以压缩形参变量名,老版本游览器undefined可以被重新赋值,所以传入undefined防止被改变。
继承:
-
原型继承问题:不会使用★
⑴修改原型属性一定要修改constructor
。
Student.prototype=Person.prototype;
Student.prototype.constructor=Student;
⑵属性是通过原型继承的,原型上的成员都是共享的、无法设置构造函数的参数。 -
借用构造函数继承:
在Student中调用Person.call(this,name,age);
改变Person的this指向。 -
组合继承:原型继承+借用构造函数。
-
在新版本的游览器中可以根据条件声明函数,新版本游览器在条件语句中定义函数不会进行函数提升。老版本ie中,条件语句中定义函数会进行函数。提升。
-
fn.apply(o,[1,2]);
第二个参数是数组,是传入fn的实参,第一个参数是需要改变成的this。
Array.prototype.splice.call(obj,1,2);
Array.prototype.push.call(obj,15);
-
删除对象的的name:delete o.name;
delete obj[“0”];括号里是属性名。 -
函数的成员:
fn.name
函数名称,fn.length
形参个数;
fn.arguments
获取实参;arguments私有成员、可变参数,fn.arguments.callee
当前函数;fn.caller
调用fn的函数。
高阶函数:函数作为参数或返回值。
- 作为参数:
animate(callback);
forEach(fn);setInterval(fn,50);
addEventListener("click",fn,false);
arr.sort(fn);
- 作为返回值:
所有自定义类型toString()返回的都是[object Object]。
function getFun(type){
return function(obj){
return Object.prototype.toString.call(obj) === type;
}}
var isArray=getFun("[object Array]");
var arr=[];isArray(arr);
- 闭包:可以访问另一个函数作用域的变量的函数。(是一个特殊的函数作用域)
⑴f1函数作为fn函数的返回值调用获取了fn的变量。
⑵循环中的事件处理函数,使用自调用函数接收索引,将i作为自调用函数的实参。
⑶可以访问独立数据的函数。全局作用域访问局部作用域。
⑷闭包调用的作用域难以释放,不到万不得已通常不使用。