JavaScript
基础篇(一)
简介:
JavaScript是一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型属于解释型的高级编程语言。
历史—ScriptEase:
1992年,Nombas的公司开发了一川叫做C减减(C-minus-minus,简称Cmm)的嵌入式脚本语言。这个脚本语言捆绑在一个叫做CEnvi的共享软件中,后来改名为ScriptEase。
历史—JavaScript:
1995年,顺应当时的市场需要,Netscape(网景)公司的BrendanEich设计一种在浏览器运行的脚本语言,取名LiveScript,并在发行的Netscape Nav-igator 2.0上运行。正值Java(sun公司)风风火火的时候,于是借势改名为“JavaScript”。
同年,sun公司也想在浏览器的份额,于是推出Java Applet(使用JAVA语言开发)与JavaScirpt抗衡。
历史-JScript:
1996年, 为了获取技术优势,微软的亲儿子 - IE决定也搞一个与Javascript类似的脚本语言在IE浏览器运行的脚本语言-JScript。
三分天下ECMAScript统一:
此后几年, ScriptEase、JavaScript和JScript份额不分相下,随着业界担心的增加,这个语言的标准化显然已经势在必行
1997 年,Netscape将JavaScript 1.1作为一个草案提交给欧洲计算机制造商协会(ECMA)。由来自Netscape、Sun、微软、Borland和其他一些对脚本编程感兴趣的公司的程序员组成的TC39锤炼出了ECMAScript一种新语言,标准编号ECMA-262。
特点:
脚本语言、基于对象、跨平台性、简单,容易上手、应用广泛
原理:
ECMAScript,描述了该语言的语法和基本对象,是一个标准。
文档对象模型(DOM),描述处理网页内容的方法和接口。
浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口。
引擎(ECMAScript的解释器):
Microsoft公司的JScript.
Mozilla的JavaScript-C(C语言实现),现名SpiderMonkey
Mozilla的Rhino(Java实现)
Digital Mars公司的DMDScript
Google公司的V8(速度最快)
WebKit
迄今为止, 运行环境不单单在浏览器端运行
展望:
从应用范围来看:
截止到JS应用的范围越来越广泛,从最开始的单纯的浏览器客户端的脚本语言,到现在手机app(html5),桌面应用(nw.js),服务器语言(node.js或io.js)
从各个时代来看,不管什么时代,都不开信息数据化:
互联网时代: 网页,数据简单的展示
物联网时代: 网页/app/桌面应用,更好的用户体验
大数据时代: 数据处理/数据可视化,完全融于数据中
将来涉及更多的方面, 比如: JS一统各种平台的APP,将与替换不适应当前时代的重量级编程语言。
document.write(“hello world”); //输入文本
alert(“hello world”); //弹窗
console.info(“hello world”); //控制台
语法篇(二)
变量:
var str = “abc”;
声明 命名 赋值 值
命名:
格式——驼峰命名
范围——限于数字、字母、$、下划线
要求:①首字母小写,接着每个单词首字母大写。
②变量名的第一个单词应当是一个。
③以字母开头,也可以以$、_开头(不建议)。
④具有可识别性。
注释:
单行注释://
多行注释:/* */
引用外部链接:
<script src=”script.js” type=”text/javascript”></script>
简写<script src=”script.js”></script>
变量类型:
①一个变量应该只存放一种类型的数据。
②查看变量的方法:typeof(var);
常见类型——number(数字)、string(字符串)、boolean(布尔值)、function(函数)、object(对象)、undefined(未定义)
释:undefined:真的没定义;‚虽然定义,但没有给东西。
强制类型转换:
parseInt()字符串转整数。
parseFloat()字符串转浮点数。
String(var)、toString(var)转为字符串。
Boolean(var)转换成布尔值。
isNaN(var)判断是还是是非数字,非数字返回true、数字返回false
运算符:
+加;-减;*乘;/除;%取模(余数);
+=;-=;*=;/=;%=;
例:i+=2 相当于i=i+2;
i++ ;i-- 相当于i=i+1; i=i-1;
大小关系检测运算符:
<小于;<=小于或等于;>大于;>=大于或等于;
等性检测运算符:
==等于;!=不等于;===恒等于;!==不恒等于;
等于——判断两个变量的值是否相等。
恒等于——判断两个变量的值 和类型是否相等。
逻辑运算符:
!——!表达式——(逻辑非)如果是true则返回false;如果是false则返回true;
&&——表达式1&&表达式2——(逻辑与)只有两边都为true时才返回true,否则返回false;
||——表达式1||表达式2——(逻辑或)左边或右边为true时返回true,否则返回false;
三目运算符:
判断条件?true语句:false语句;
判断:
if判断——
if(条件1){
语句1;
}else if(条件2){
语句2;
}else{
false语句;
}
释:满足条件1执行语句1,满足条件2执行语句2;else if可以有无数个,如果都不满足则执行else语句。
switch判断——
switch(var){
case 值1:语句1; break;
case 值2:语句2;
case 值3:语句3;
default: false语句;
}
释:当var变量的值等于值1时,执行语句1,然后执行break打断。如果var变量的值等于值2时,执行语句2,并往下一直执行,包括default语句也会被执行,除非被break打断或continue跳过。与if判断不同的是default分支语句可以在分支语句的第一行,而if的else只能写在最后一个分支语句。
循环:
for循环——
for(声明变量;判断条件;变量变化语句){
循环体语句;
}
执行顺序:声明变量(只在首次循环时执行)→判断条件→循环体语句→变量变化语句
注:变量变化语句其实也是语句,只不过是最后执行罢了。
while循环——
var i=0;
while(i<2){
alert(“a”);
i++;
}
do while循环——
var i=0;
do{
alert(“a”);
i++;
}while(i<2);
while与do while的不同点:while循环是先判断再执行循环体语句。do while循环是先执行循环语句再判断。
while与do while的共同点:当判断条件不成立时都会立刻终止整个循环。
注:while与do while的区别,首次循环while循环不满足条件时会直接结束,而do while首次循环不满足条件时会执行循环体语句一次。
json数组
var jso={a:1, b:2, c:3};
alert(jso[“a”]); //或者jso.a
注:json数组与array数组不同,array数组是通过索引 号来访问array数组的元素,json数组多是用字符串来访问json数组里的元素(也可以跟array一样用数字来访问,用数字保存就行),所以要在中括号里加双引号。————用到[“”]的地方都可以用.(点)代替。
json数组的for in循环——
for(var i in jso){
document.write(jso[i]);
}
循环体的常用命令:
continue——跳过本次循环;
break——终止整个循环;
函数篇(三)
函数的特点:
①简洁/方便/代码量少/发动少
②把相同功能的代码,放到一个地方去了。
③函数是一个相同功能的代码块,可重复使用。
函数的语法:
定义——
function 函数名(形参1,形参2){
代码块;
return 变量(也可以是语句); //返回并终止整个函数;
}
调用——
函数名(传参1, 传参2);
return——
执行后面的一个代码块,如果是变量则直接返回出去,如果是语句则直接执行。然后终止整个函数。return是可选的。
注:在定义函数的时候,形参可以定义、可以不定义,形参可以有n个。在调用的时候,传参是可选的,可以少传、不传或多传。
变量作用域:
(1)全局变量——如果在任何函数之外声明了一个变量,则该变量为全局变量,且该变量的值整个持续范围内都可以访问和修改。
(2)局部变量——如果在函数定义内声明了一个变量,则该变量为局部变量。每次执行该函数时都会创建和破坏该变量;且它不能被该函数外的任何事物访问。
注:局部变量一定要以var申明,否则在调用函数时执行该变量的时候,系统会在函数的最外面也就是全局默认生成一个var,该变量此时就会变成全局变量。
除了函数变量不加var声明在调用时会变成全局变量外,for循环也是一样。
对象篇(四)
对象的认识:
对象是带有属性和方法的特殊数据类型。
访问对象的属性——
objectName.attributeName;
访问对象的方法——
objectName.methodName();
属性和方法——
属性是与对象相关的值。
方法是能够在对象上执行的操作。
对象——JS内置对象:
Array、Boolean、Date、Math、Number、String
Array创建——
var arr = new Array(); //或者var arr=[];
var arr = new Array(size);
var arr = new Array(element1, element2…);
//或者var arr = [element1, element2];
注:size是期望的数组元素个数,返回的数组length字段将被设为size的值。
Array属性——
length:数组的长度
Array方法——
unshift(newElement1, newElement2…):向数组的开头添加一个或多个元素,并返回新的数组长度。
shift():删除并返回数组的第一个元素。
push(newElement1, newElement2…):向数组的末尾添加一个或多个元素,并返回新的数组长度。
pop():删除并返回数组的最后一个元素。
arrayObject1.concat(arrayObject2…):连接两个或多个数组对象,并返回结果。
join(separator):把数组的所有元素放入一个字符串,元素通过指定的分隔符进行分隔,并返回结果。
slice():从数组中选中一段元素集返回出去。
reverse():颠倒数组中元素的顺序。
splice(index, length, newElements1…):从index开始删除length个元素,并在index前面插入一个或多个元素,返回删除的元素。
sort():对数组的元素进行排序。
sort()的数字排序——
arrayObject.sort(function(n1, n2){
return n1-n2;
});
注:
在调用unshift()、shift()、push()、pop()方法时都是会修改arrayObject本身的数据。unshift()、push()返回的是新数组的length。shift()、pop()返回的是被删除的元素。
在调用concat()、join()、slice()方法的时候并不会修改arrayObject本身的数据,结果都是以返回值的形式返回出去。
在调用reverse()、splice()、sort()都会修改arrayObject本身的数据。其中splice()返回的是所被删除的数据,reverse()、sort()返回的就是结果本身。sort()的排序方式是从小到大,例:0,1,2,3,’a’,’b’…;
Boolean值——
true、false
Date创建——
var dateObject = new Date();
Date方法——
getFullYear():从Date对象以四位数字返回年份。
getMonth():从Date对象返回月份(0~11)。
getDate():从Date对象返回当月的第几天(1~31)。
getDay():从Date对象返回本周是星期几(0~6)。
getHours():返回Date对象的小时(0~23)。
getMinutes():返回Date对象分钟(0~59)。
getSeconds():返回Date对象的秒数(0~59)。
getMilliseconds():返回Date对象的毫秒数(0~999)。
getTime():返回1970年1月1日至今的毫秒总数。
setFullYear(year, month, day):设置Date对象中的年份、月份(0~11)、日期。
setMonth(month, day):设置Date对象中的月份(0~11)、日期。
setDate(day):设置Date对象中的日期。
setHours(hours, minutes, seconds, milliseconds):设置Date对象中的时、分、秒、毫秒。
setMinutes(minutes, seconds, milliseconds):设置Date对象中的分、秒、毫秒。
setSeconds(seconds, milliseconds):设置Date对象中的秒、毫秒。
setMilliseconds(milliseconds):设置Date对象中的毫秒。
注:设置只会对dateObject进行修改,并不会修改系统的时间。所有的传参都是可选的,可以多传、少传、不传都可以;JavaScript所有的方法都一样。
Math方法——
Math.ceil(n):对数进行上舍入。
Math.floor(n):对数进行下舍入。
Math.max(n1, n2…):返回数中最大的数。
Math.min(n1, n2…):返回数中最小的数。
Math.random(n):随机返回一个16位小数(0~1)之间。
Math.round(n):正数四舍五入,负数取就近的整数。
Math.abs(n):返回数字的绝对值。
Math.pow(n, 幂):运算n的指定次幂。
Math.sprt(n):运算n的平方根。
注:调用Math对象的方法不会修改number变量的数据,结果统一是由返回值的形式来保存。
Number
String方法——
toLowerCase():把字符串的字母转换为小写,返回值。
toUpperCase():把字符串的字母转换为大写,返回值。
charAt(index):返回指定索引号位置的字符。
charCodeAt(index):返回在指定索引号位置字符的Unicode编码。
indexOf(string, index):从前向后搜索字符串。若搜索到则返回首个字符所在的位置,若没有搜索到则返回-1。
lastIndexOf(string, index):从后向前搜索字符串。若搜索到则返回首个字符所在的位置,若没有搜索到则返回-1。
match(string):找到与正则表达式匹配的字符串,返回该字符串。
replace(string, replacement):替换与正则表达式匹配的首个字符串,返回新的字符串。
substr(start, length):从start位置开始返回length个长度的字符集。
substring(start, end):返回从start位置开始到end位置结束 的字符集。
slice(start, end):返回从start位置开始到end位置结束 的字符集。
search(regexp):检索与正则表达式相匹配的值,并返回首个字符的位置。
stringObject1.concat(stringObject2…):连接字符串,并返回新的字符串。
split(separator, length):用指定的字符把字符串分割为数组对象关返回。(指定的字符必须是stringObject当中的。)
注:在调用replace()方法时,两个传参都必须传,空值就传””。否则在返回新字符串中会出现null/undefine字符串拼接的错误。
DOM对象(文档对象模型):
Document对象、Element对象
Document方法——
getElementById():通过指定id值获取第一个元素,返回一个对象。
getElementsByName():通过指定name值获取第元素,返回数组。
getElementsByTagName():通过指定标签名获取元素,返回数组。
注:这三种是最常用获取元素的方法,其中第一个返回的是一个对象,后面二个返回的都是数组。但这些并不是普通的数组,不能直接调用数组对象的方法,可以新建一个数组遍历一下再调用数组对象的方法就可以了。
createElement(element):创建元素节点。
createTextNode(text):创建文本元素节点。
write():输入文本。
Element属性——
childNodes:获取元素的所有子节点,返回数组。
children:获取元素的所有子元素节点,返回数组。
firstChild:获取第一个子节点。
lastChild:获取最后一个子节点。
nextChild:获取下一个兄弟节点。
nodeName:获取dom对象对应的html标签名(大写字母)。
nodeType:获取dom对象对应的类型值。
标签类型是1;文本类型是3;注释类型是8;
nodeValue:获取dom对象的值(文本节点和注释节点)。
parentNode:获取父节点。
offsetParent:获取最近一级带有定位属性的父级。
attributes:获取对象的属性集合。
innerHTML:向对象添加HTML文本。
nodelist.length:获取属性集合的长度。
title:获取对象的标题。
tagName:获取对象的标签名(大写字母)。
textConcat:获取对象的文本内容(包括换行符)。
Id:获取对象对应的id值。
表格应用——获取:tBodies、tHead、tFoot、rows、cells加索引”[i]”;
注:lastChild、firstChild若不兼容,FF和Chrome可能用的是document.firstElementChild…用if判断一下。
Element方法——
appendChild():向子元素的末尾添加元素。
insetBefore(element, index):向指定的子元素之前添加元素。
removeChild(o):删除指定子元素。
getAttribute(s):获取指定属性名对应的属性值。
getAttributeNode(s):获取指定属性名对应的属性对象。
hasAttributes():判断标签是否有属性。
hasAttribute():判断标签是否有指定属性。
hasChildNodes():判断标签是否有子节点。
removeAttribute(s):删除元素指定属性,通过属性名。
removeAttributeNode(o):删除元素指定属性,通过属性对象。
setAttribute(s, v):设置指定属性,通过属性名。
setAttributeNode(o):设置指定属性,通过属性对象。
elementObject1.isSame(elementObject2):判断是否为同一个标签。
replaceChild(oNewElement, oElement):替换子元素。
BOM对象(浏览器对象模型):
window、navigator、screen、history、location
window方法——
alert():弹框。
close():关闭浏览器窗口。
confirm(message):显示带有一段消息以及确认按钮和取消按钮的对话框。
prompt():可输入文本的提示框。
open(URL):打开一个新的浏览器窗口或查找一个已命名的窗口。(传参”_self”覆盖当前窗口;”_blank”打开一个新窗口;”about:blank”打开一个空白新窗口;status状态栏、toolbar工具栏、menubar菜单栏、location是否显示地址输入框,值:yes|no)。
注:confirm()方法是有一个返回值的,点确定会返回一个true,点取消或关闭会返回一个false。
navigator属性——
appCodeName:获取浏览器的内核技术名字。
appName:获取技术开发的公司名字。
appVersion:返回浏览器的平台(操作系统)。
userAgent:返回浏览器的平台(操作系统)。
screen属性——
availHeight:获取显示屏的高度。
availWidth:获取显示屏的宽度。
location属性——
location:返回当前的url。
host:返回主机名和端口号。
hostname:返回主机名。
port:返回主机的端口号。
href:返回当前的url(同document.URL一样)。
pathname:返回当前的url部公地址。
protocol:返回主机的使用协议。
注:window.location=”document.html”可以实现页面跳转。
事件篇(五)
Event事件:
鼠标、键盘、页面、表单
鼠标——
onclick:单击鼠标左键。
ondblclick:双击鼠标左键。
oncontextmenu:右键菜单。
onmousedown:鼠标的左键被按下。
onmouseup:鼠标左键被松开。
onmouseover:鼠标移入目标的上方。
onmouseout:鼠标移出目标的上方。
onmousemove:鼠标移动时。
clientX:获取鼠标的X轴坐标。
clientY:获取鼠标的Y轴坐标。
注:获取真的event对象。下一页有写↓。
键盘——
onkeydown:键盘被按下时。
onkeyup:键盘被松开时。
onkeypress:键盘输入时。
oEvent.keyCode:返回按键对应的keyCode码。
其他属性:
ctrlkey:ctrl功能键等候。
shiftkey:shift功能键等候。
altkey:alt功能键等候。
例:if(oEvent.ctrlkey&&oEvent.keyCode==13){代码块}//ctrl+回车
页面事件——
onload:当元素加载完成。
onfocus:当元素获取焦点。
onblur:当元素失去焦点。
onchange:当元素的值发生改变。
表单事件(form)——
onreset:重置按钮被点击。
onsubmit:提交按钮被点击。
reset():自动提交函数。
submit():自动重置函数。
注:使用自动提交、自动重置函数是不会执行表单事件里的代码块。当提交表单事件时会刷新页面,会破坏你需要实现的功能。
获取真的event对象——
document.οnclick=function(ev){
var oEvent = ev||event; //FF||IE;
alert(oEvent.clientX+”,”+oEvent.clientY);
}
注:在IE、Chrome浏览器下获取event对象是直接调用就可以了,FF和Chrome是在默认从事件方法里传一个参数,即事件对象。用或取一个为真保存到新变量就可以了。
获取键盘的keyCode码:
document.οnkeydοwn=function(ev){
var oEvent=ev||event;
document.title=oEvent.keyCode;
}
取消事件冒泡:
oEvent.concelBubble=true;
注:在调用事件冒泡属性时必须获取真的事件对象。事件冒泡属性一般秀于事件函数内。
可视区的尺寸——
document.documentElement.clientWidth:可视区的宽度。
document.documentElement.clientHeight:可视区的高度。
常用的一些框架
获取鼠标的X、Y坐标——
function getPos(ev){
var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;
var scrollLeft=document.documentElement.scrollLeft||document.body.scrollLeft;
return {x: ev.clientX+scrollLeft, y: ev.clientY+scrollTop};
}
处理事件绑定兼容的方法——
function myAddEvent(obj, ev, fn){
if(obj.attachEvent){
obj.attachEvent(“on”+ev, fn);
}else{
obj.addEventListener(ev, fn, false);
}
}
获取非行间样式——
function getStyle(obj, name){ //获取非行间样式;
if(obj.currentStyle){ //判断currentStyle是否为真,是否是IE浏览器;
return obj.currentStyle[name]; //IE浏览器获取非行间样式的方法;
}else{
return getComputedStyle(obj)[name];//Chrome、FF...获取非行间样式的方法;
}
}
在指定的父级元素内通过className获取元素数组——
function getByClass(oParent, sclass){
var aEle=oParent.getElementsByTagName(“*”);
var aResult=[];
for(var i=0; i<aEle.length; i++){
if(aEle[i].className==sclass){
aResult.push(aEle[i]);
}
}
return aResult;
}
完美运动框架——
function startMove(obj, json, fnEnd){
clearInterval(obj.timer); //避免多个定时器同时运行,把obj之前开的定时器关掉;
obj.timer=setInterval(function(){
var bStop=true; //假设所有的值都已经到了;
for(var attr in json){ //循环json的数组,实现多样式同时运动;
var cur=0; //定义一个变量,为保存属性值用的;
if(attr=="opacity"){
//判断运动的属性是否是opacity(透明度),是透明度需要特殊处理;
cur=Math.round(parseFloat(getStyle(obj, attr))*100);
//把字符串转为小数再乘100,然后四舍五入一下,最后赋值给cur变量;
}else{
cur=parseInt(getStyle(obj, attr));
//把字符串转为整数,然后赋值给cur变量;
}
var speed=(json[attr]-cur)/6; //运动的速度=(终点值-当前值)/6;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
//避免到不了终点,做个上下取整,正数取上,负数取下;
if(cur!=json[attr]) //任何一个没有到达终点,bStop为false
bStop=false;
if(attr=="opacity"){
//判断运动的属性是否是opacity(透明度),是透明度需要特殊处理;
obj.style.filter="alpha(opacity:"+(cur+speed)+")";
obj.style.opacity=(cur+speed)/100;
}else{ //属性开始运动;
obj.style[attr]=cur+speed+"px";
}
}
if(bStop){ //只有所有的属性都到达终点到,即bStop为true时,关闭定时器;
clearInterval(obj.timer);
if(fnEnd)fnEnd();
//当关闭定时器时判断有没有传函数fnEnd,有的话继续执行fnEnd;
}
}, 30)
}
扩展篇
定时器:
开启定时器——
setInterval(vCode, iMilliSeconds):间隔型
setTimeout(vCode, iMilliSeconds):延时型
停止定时器——
clearInterval(vInterval):关闭间隔定时器
clearTimeout(vInterval):关闭延时型定时器
注:间隔型定时器会每隔一段指定的时间执行一次,一直循环,直到定时器被关闭。
延时型定时器只在指定的时间后执行一次,然后自动关闭,不再执行。
所有定时器都是先执行指定的等待时间,再执行代码块。
函数——实参的访问:
假设定义了函数f,它的形参只有一个x。如果调用这个函数时传入两个实参,第一个实参可以通过参数名x来获得,也可以通过arguments[0]来得到。第二个实参只能通过arguments[1]来得到。此外,和真正的数组一个,arguments也包含一个length属性,用以标识其所包含元素的个数。因此,如果调用函数f()时传入两个参数,arguments.length的值就是2。
进制之间的转换:
其它进制数转为十进制数——
parseInt(合法的数字或字符串,进制数);
parseInt(1010, 2) //==>10
parseInt(77, 8) //==>63
parseInt(“FF”, 16) //==>255
十进制数转为其它进制数——
iObject.toString(进制数);
var i=255;
i.toString(2); //==>”11111111”
i.toString(8); //==>”377”
i.toString(16); //==>”ff”
ECMAScript5中的数组方法:
forEach()、map()、filter()
every()、some()
reduce()、reduceRight()
forEach()——
forEach()方法从头至尾遍历数组,为每个元素调用指定的函数。传递函数作为forEach()的第一个参数。然后forEach()使用三个参数调用该函数:数组元素、元素的索引、数组本身。如果只关心数组元素的值,可以编写只有一个参数的函数——额外的参数将忽略:
var data = [1, 2, 3, 4, 5];
var sum = 0;
data.forEach(function(value){
sum+=value; //将每个值累加到sum上;
});
sum; //输出sum等于15;
data.forEach(function(v, i, a){
a[i]=v+1;
})
data; //=>[2, 3, 4, 5, 6];
注:forEach()无法在所有元素都传递给调用的函数之前终止遍历。也就是说,没有像for循环中使用的相应的break语句。如果要提前终止,必须把forEach()方法放在一个try块中,并能抛出一个异常。
map()——
map()方法将调用的数组的每个元素传递给指定的函数,并返回一个数组,它包含该函数的返回值。
var a=[1, 2, 3];
var b=a.map(function(x){
Return x*x;
}) //b=[1, 4, 9];
注:传递给map()的函数的调用方式和传递给forEach()的函数的调用方式一样。但传递给map()的函数应该有返回值。注意,map()返回的是新数组。如果是稀疏数组,返回的也是相同方式的稀疏数组:它具有相同的长度,相同的缺失元素。
filter()——
filter()方法返回的数组元素是调用的数组的一个子集。传递的函数是用来逻辑判定的:该函数返回true或false。调用判定函数就像调用forEach()和map()一样。如果返回值为true或能转化为true值,那么传递给判定函数的元素就是这个子集的成员,它将被添加到一个作为返回值的数组中。例如:
var a=[5, 4, 3, 2, 1];
a.filter(function(x){
return x<3
}) //[2, 1];
a.filter(function(x){
return X%2==0;
}) //[4, 2];
注:filter()会跳过稀疏数组中缺少的元素,它的返回数组总是稠密的。为了压缩稀疏数组的窑,代码如下:
var a=[1, 2, , , , 3, 4, 5];
a.filter(function()return true;}); //=>[1, 2, 3, 4, 5];
甚至,压缩空缺并删除undefined和null元素,可以这样使用filter()如下:
a.filter(function(x){return x!==undefined && x!==null;});
every()和some()——
every()和some()方法是数组的逻辑判定:它们对数组元素应用指定的函数进行判定,返回true或false。
every()方法就像数学中的“针对所有”的量词:当且仅当针对数组中的所有元素调用判定函数都返回true,它才返回true:
var a=[1, 2, 3, ,4, 5];
a.every(function(X){
return x<10; // =>true 所有的值都小于10。
})
a.every(function(x){
return x%2==0; //=>false 不是所有的值都是偶数。
})
some()——
方法就像数学中的“存在”的量词:当数组中至少有一个元素调用判定函数返回true,它就返回true;并且当且仅当数值中的所有元素调用判定函数都返回false,它才返回false:
var a=[1, 2, 3, 4, 5];
a.some(function(){
return x%2==0; //a含有偶数值
})
a.some(isNaN); //=>false a不含有非数值元素
注:一旦every()和some()确认该返回什么值它们就会停止遍历数组元素。some()在判定函数第一次返回true后就返回true,但如果判定函数一直返回false,它将遍历整个数组;
every()恰好相反:它在判定函数第一次返回false后就返回false,但如果判定函数一直返回true,它将会遍历整个数组。注意,根据数学上的惯例,在空数组上调用时,every()返回true,some()返回false。
reduce()和reduceRight()——
reduce()和reduceRight()方法使用指定的函数将数组进行组合,生成单个值。这在函数式编程中是常见的操作,也可以称为“注入”和“折叠”。举例说明它是如何工作的:
var a=[1, 2, 3, 4, 5];
var sum=a.reduce(function(x, y){
return x+y;
}, 0); //数组求和
var product=a.reduce(function(x, y){
return x*y;
}, 1); //数组求积
var max=a.reduce(function(x, y){
return (x>y)?x:y;
}); 求最大值
reduce()需要两个参数。第一个是执行化简操作的函数。化简函数的任务就是用某种方法把两个值组全或化简为一个值,并返回化简后的值。在上述例子中,函数通过加法、乘法或取最大值的方法组合两个值。第二个(可选)的参数是一个传递给函数的初始值。
reduce()使用的函数与forEach()和map()使用的函数不同。比较熟悉的是,数组元素、元素的索引和数组本身将作为第2~4个参数传递给函数。第一个参数是到目前为止的化简操作累积的结果。第一次调用函数时,第一个参数是初始值,它就是传递给reduce()的第二个参数。在接下来的调用中,这个值就是上一次化简函数的返回值。在上面的第一个例子中,第一次调用化简函数时的参数是0和1.将两者相加并返回1.再次调用时的参数是1和2,它返回3.然后它计算3+3=6、6+4=10,最后计算10+5=15.最后的值是15,reduce()返回这个值。
可能已经注意到了,上面第三次调用reduce()时只有一个参数:没有指定初始值。当不指定初始值调用reduce()时,它将使用数组的第一个元素作为初始值。这意味着第一次调用化简函数就使用了第一个和第二个数组元素作为其第一个和第二个参数。在上面求和与求积的例子中,可以省略初始值参数。
在空数组上,不带初始值参数调用reduce()将导致类型错误异常。如果调用它的时候只有一个值——数组只有一个元素并且没有指定初始值,或者有一个空数并且指定一个初始值——reduce()只是简单地返回那个值而不会调用化简函数。
reduceRight()的工作原理和reduce()一样,不同的是它按照数组索引从高到低(从右到左)处理数组,而不是从低到高。如果化简操作的优先顺序是从右到左,你可能想使用它,例如:
var a=[2, 3, 4];
//计算2^(3^4)。乘方操作的优先顺序是从右到左。
var big=a.reduceRight(function(accumulator, value){
return Math.pow(value, accumulator)
})
注意:reduce()和reduceRight()都能接收一个可选的参数,它指定了化简函数调用时的this关键字的值。可选的初始值参数仍然需要占一个位置。如果想让化简函数作为一个特殊对象的方法调用,请参看Function.bind()方法。
值得注意的是,上面描述的every()和some()方法是一种类型的数组化简操作。但是不同的是,它们会尽早终止遍历而不总是访问每一个数组元素。
为了简单起见,到目前位置所展示的例子都是数值的,但数字计算不是reduce()和reduceRight()的唯一意图。
Ferrari笔记