引用类型包括Object类型、Array类型、Date类型、RegExp类型、Function类型、基本包装类型(Boolean、Number、String)
一、Object类型
1.创建对象:
创建对象的方式有两种,第一种是使用new加构造函数,这是最为常见的,第二种是使用对象字面量表示法,语法如下:
var person={};
person.name="润滑";
person.age=18;//这种方法只能定义默认的属性
var person={
“age”:18,
"name":"润滑"
};
*在对象字面量创建对象的时候,要注意内部属性是字符串,并且属性与属性之间应当使用逗号分开。
通常,我们更建议使用对象字面量的方法创建对象,因为这样有符合我们封装数据的格式要求。而且,对象字面量也能向函数传递大量的参数。
在引用对象属性的时候,我们常用点表示法,在js中,还可以使用方括号来访问:
alert(person["name"]);//润滑
alert(person.name);//润滑
方括号表示法的使用,可以使得我们用一个变量来表示属性:
var propertyName="name";
alert(person[preopertyName]);
这样我们就可以在属性名当中添加空格了,而这在点表示法中时不允许的:
alert(person["first name"]);
二、Array类型
js数组的每一项可以用来保存任何一种数据类型的数据,其数组大小可以动态改变,随着数据的添加自动增长。
1.构建方法:
和前面Object类型一样,数组类型的构建同样分为new加构造函数和使用字面量方法两种:
(1)new方法
数组类型可以动态改变大小,所以我们可以不声明长度,但是也可以传递长度参数:var a=new Array(20);如果括号的不是一个数值,而是一个或多个字符串,就会把这多个字符串当做数组的项
var colors=new Array();
var colors=new Array(20);
var colors=new Array("red","green","blue");
var colors=Array();
(2)数组字面量
数组字面量是由一组包含数组项方括号表示,多个数组项之间以逗号隔开
var colors=["red","green"];
var name=[];
var values=[1,2,,]//错误的写法,会产生2或3个数组项
第三种写法,在IE8以及之前的浏览器当中,values数组会成为一个包含1,2还有undefined值的数组。但在其他浏览器中则是只有1,2两个数组项,所以极其不建议使用这种写法。
*length的用法:
length即是数组的长度,length不单是只读的,它还可以进行添加和删除的工作:
var colors=["red","green","blue"]; alert(colors.length);//3 colors.length=2;//删除最后一项 alert(colors[2]);//undefined colors.length=4;//添加两项 alert(colors[3]);//undefined
colors[colors.length]="black";//自动在最后一项添加一个black数组项
2.检测数组
我们在检测一个变量是何种类型的时候会使用typeof操作符,在检测对象是具体何种类型时会使用instanceof操作符,但是instanceof在检测的时候会假定环境中只有一个全局变量,所以在页面使用了多种框架的情况下,也即有多个全局变量的时候,instanceof就会出错。所以数组对象创建了isArray()方法来判断引用类型是否是数组
if(Array.isArray()){
//对数组执行某些操作
}
3.转换字符串
所有对象都具备toString()、toLocaleString()、valueOf()这三种转换方法,数组调用toString()方法转换为字符串的时候,就通过逗号把每一个数组项连接起来形成字符串。而valueOf()方法则还是返回一个数组;toLocaleString()方法和toString()方法非常类似,在大多数情况下会和toString()方法一样返回相同结果,但是因为toLocaleString()方法连接字符串会根据本地环境的改变而改变,所以有时候它的字符串连接符号与传统的逗号不一致。(参考:http://www.cnblogs.com/nifengs/p/5085824.html)
下面有一个关于toLocaleString和toString方法的例子,说明了在在调用相对应的方法转换数组时,会调用该数组每一项对应的方法:
var person1={
toLocaleString:function(){
return "Nikolaos";
},
toString:function(){
return "Nicholas";
}
};
var person2={
toLocaleString:function(){
return "Grigorios";
},
toString:function(){
return "Greg";
}
};
var people=[person1,person2];
alert(people);//Nicholas,Greg 默认调用toString()
alert(people.toString());//Nicholas,Greg
alert(people.toLocaleString());//Nikolaos,Grigorios
要想替换转换后字符串的连接符号,可以使用join方法:
var colors=["red","green","blue"];
alert(colors.join(","));//red,green,blue
alert(colors.join("||"));//red||green||blue
5.栈方法和队列方法
(1)栈
栈是一种可以限制插入和删除项的数据结构,栈中项的推入和弹出都是在栈的顶部发生的,也就是说最先添加的项最先被删除(后入先出)。
js为数组提供了两个方法模拟该数据结构:push()和pop()
push():接受任意数量的参数,并逐个添加到数组末尾,然后返回修改后数组的长度
pop():从数组末尾删除最后一项,减少length的值,并返回被删除项
(2)队列
队列同样是可以限制插入与删除的数据结构,与栈不同的是,它是在列表的前端移出项,末端添加项(后进先出)。
因为push是从末端添加项,所以只需要一个从数组前端取得项的方法就可以模拟队列了,这个方法就是shift()
shift():移出第一个项并返回
*从相反方向模拟队列,js还提供了另一个方法:unshift(),该方法从数组第一个项开始添加数组项,可以结合pop()方法来移出末端数组项来反方向模拟队列。
6.重排序方法
数组中有两个可以用来重排序的方法:reverse()和sort()。其中reverse()用来反转数组项的顺序,而sort()方法在默认情况下按升序排列数组项。但是sort()方法在进行数组项比较的时候,会先调用toString()方法将数组项转换为字符串,即便数组项当中的都是数组也是如此。这种方法将会产生以下结果:
var values=[0,1,5,10,15];
values.sort();
alert(values);//0,1,10,15,5
*之所以产生上面的结果,是因为在进行字符串比较的时候,js会先比较字符串的第一个字符,进行排序:0,1,5,1,1。自然5就排到了最后,然后再对相同的字符进行第二个字符的比较:1,10,15,。所以最后的结果是0,1,10,15,5
为了避免这种不符合我们结果的产生,我们可以让sort()方法接受一个比较函数作为参数,以便我们指定哪个值位于哪个值的前面。如果第一个参数位于第二个参数的前面,则返回一个负值;如果第一个参数位于第二个参数的后面,则返回一个正值;如果第一个参数和第二个参数位置相同,则返回0;
//升序
function compare(values1,values2){ if(values1<values2){ return -1; }else if(values1>values2){ return 1; }else{ return 0; } }
var values=[0,1,5,10,15];
values.sort(compare);
alert(values);//0,1,5,10,15
//降序
function compare(values1,values2){ if(values1<values2){ return 1; }else if(values1>values2){ return -1; }else{ return 0; } }
var values=[0,1,5,10,15];
values.sort(compare);
alert(values);//15,10,5,1,0
还有一个更为简便的排序:
function compare(value1,value2){
return value2-value1;//升序
}
7.数组的操作方法
js对数组内部插入、删除、替换数组项提供了两个方法:slice()和splice()
(1)slice()方法:该方法接收一到多个的参数,并返回从该参数指定位置开始到当前数组末尾的所有项。slice()方法会创建一个新的数组,而原先的数组不会发生改变,这是和下面的splice()方法所不同的
var colors=["red","green","blue","yellow","purple"];
var colors2=colors.slice(1);
var colors3=colors.slice(1,4);
alert(colors2);//green,blue,yellow,purple
alert(colors3);//green,blue,yellow
(2)splice()方法:该方法可以实现在数组中插入,删除,替换的所有操作方法,是非常强大的操作数组的方法。splice()接受三个参数:起始位置索引,删除项数,插入项(可多项)。然后将会返回包含被删除的数组项的数组。如果没有删除数组项,则返回一个空数组
var colors=["red","green","blue"];
var removed=colors.splice(0,1);
alert(colors);//green,blue
alert(removed);//red
removed=colors.splice(1,0,"yellow","orange");
alert(colors);//green,yellow,orange,blue
alert(removed);//返回一个空数组
removed=colors.splice(1,1,"red","purple");
alert(colors);//green,red,purple,orange,blue
alert(removed);//yellow
8.位置方法
js提供了两个位置方法:indexOf()和lastIndexOf(),这两个方法都接收两个参数:要查找的项和表示查找起点位置的索引。其中,indexOf()方法从数组的开头开始向后查找,lastIndexOf()方法则从末尾开始向前查找。这两个方法将会返回要查找的项在数组中的位置,在没有找到要查找的项的时候将会返回-1。
var number=[1,2,3,4,5,4,3,2,1]; alert(numbers.indexOf(4));//3 alert(numbers.lastIndexOf(4));//5 alert(numbers.indexOf(4,4));//5 alert(numbers.lastIndexOf(4,4));//3
var person={name:"Nicholas"};//创建对象person
var people=[{name:"Nicholas"}];//创建数组,该数组内部数组项是一个未命名的对象
var morePeople=[person];
alert(people.indexOf(person));//-1
alert(morePeople.indexOf(person));//0
*这两个方法都是在第一次遇见要找到的项的时候,立马返回位置索引,并结束函数的调用
9.迭代方法
js提供了五个迭代方法,这五个迭代方法都会都接收两个参数:要在每一项上运行的函数和运行该函数的作用域对象(可选)。传入这些方法中的函数会接收三个参数:数组项的值,该项在数组中的位置和数组对象本身。
*every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true(全部都返回true,方法才会返回true)
*filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
*forEach():对数组中的每一项运行给定函数,这个方法没有任何返回值
*map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
*some():对数组中的每一项运行给定函数,如果该函数对某一项返回true,则返回true(一个返回true,则方法就会返回true)
接下来是使用上述方法的几个例子:
//every(),检测数组中的数组项是否满足某种条件 var number=[1,2,3,4,5,4,3,2,1]; var everyResult=numbers.every(function(item,index,array){ return (item>2); }); alert(everyResult);//false //some(),和every()非常类似,但是只需要有一个数组项满足条件即可返回true var someResult=numbers.some(function(item,index,array){ return (item>2); }); alert(someResult);//true //filter(),找到符合条件的数组项,并将这些数组项以一个新数组的形式返回 var numbers=[1,2,3,4,5,4,3,2,1]; var filterResult=numbers.filter(function(item,index,array){ return (item>2); }); alert(filterResult);//[3,4,5,4,3] //map(),对数组的每一项进行操作并将得到的数组项以一个新的数组的形式返回,而原有数组则不变 var numbers=[1,2,3,4,5,4,3,2,1]; var mapResult=numbers.map(function(item,index,array){ return item*2; }) ; alert(mapResult);//[2,4,6,8,10,8,6,4,2] //forEach(),直接在原有数组上对数组项进行改动 var numbers=[1,2,3,4,5,4,3,2,1]; numbers.forEach(function(item,index,array){ //执行某些操作 }) ;
10.归并方法
js提供了两个方法对数组进行迭代:reduce和reduceRight,其中前者从数组的第一项开始根据传入的函数进行遍历操作,而reduceRight则从最后一项开始进行遍历操作。
这两个函数都会接受两个参数:一个是包含执行操作的函数,另一个则是作为归并基础的初始值。而这个包含执行操作的函数又会接收到四个参数,前一个值,当前值,项的索引以及数组对象。第一次迭代中,前一个值是数组的第一项,而往后的迭代中,前一个值则为我们这个传入的函数的返回值,例如:
var values=[1,2,3,4,5]; var sum=values.reduce(function(prev,cur,index,array){ return prev+cur; }); alert(sum); //15 //第一次执行回调函数,prev是1,cur是2,。第二次,prev是3,(前面1加2的结果),cur是3(数组的第三项),该过程会一直持续到把数组中的每一项都访问一遍,最后返回结果。
三、Date类型
基本上是获取本地或当地时间的方法,函数比较多。此处略。
四、Function类型、
1.没有重载
对于js函数,我们需要明确的一点是函数名其实是一个指向函数对象的指针。因此,一个函数可以有多个函数名,而且因为这个原因,所以js函数没有重载。原因是函数名作为指针,我们在后面定义的函数是会覆盖前面的函数的。例如:
function addSomeNumber(num){ return num+100; } function addSomeNumber(num){ return num+200; } var result=addSomeNumber(100);//300
*函数声明与函数表达式之间的区别:对于函数声明,解析器一般会优先读取函数声明,即是该声明在函数表达式之后。而函数表达式,解析器只会在执行到它所在的代码行才会真正被被解释执行。例如:
alert(sum(10,10)); function(){ return num1+num2; } /*这个代码段将会正常执行,因为解析器已经通过一个名为函数声明提升引擎在第一遍会声明函数并将它们放在源代码树的顶部。但如果是将函数声明改为函数表达式就会报错,如:*/ alert(sum(10,10)); var sum=funcion sum(num1,num2){ return num1+num2; };
2.函数内部属性:
在函数内部有两个特殊的对象:arguments和this
(1)argument是用来保存函数中参数的数组,而且该数组对象还有一个属性:callee,这个属性是一个指针,指向拥有argument对象数组的这个函数。
这个callee属性一般用来实现递归函数中函数名与函数的执行之间的耦合松散:
function fatorial(num){ if(num<=1){ return 1; } else{ return num*fatorial(num-1); } }
在这个实现阶乘的递归函数中,函数内部调用了本身的函数名,也就是函数引用,如果在之后我们把函数名修改了之后,这个函数就会调用失败。为了解除这种耦合,我们利用argument的callee属性:
function fatorial(num){ if(num<=1){ return 1; } else{ return num*argument.callee(num-1); } }
在解除了耦合之后,我们就可以实现以下代码而不报错:
var trueFatorial=fatorial;
fatorial=function(){
return 0;
}
alert(trueFatorial(5)); //120
alert(fatorial(5)); //0
还有一个和callee比较相似的属性,calller。该函数属性用于保存调用当前函数的函数引用。看下面的例子:
function outer(){ inner(); } function inner(){ alert(arguments.callee.caller); } outer();//显示outer函数的源代码
(2)另一个特殊对象就是this,this引用的是函数执行的环境对象。当在全局作用域当中,this引用的就是window对象。
window.color="red"; var 0={color:"blue"}; function sayColor(){ alert(this.color); } sayColor();//red o.sayColor=sayColor; o.sayColor();//blue(局部作用域中调用)
3.函数外部属性和方法
(1)属性:length和prototype
(2)方法:apply()和call()
这两个方法的作用都是规定函数执行的作用域。也就是设置this对象的值,apply方法接受两个参数,第一个参数就是执行的作用域,第二个参数是参数数组,它既可以是Array的实例也可以是arguments对象。例如:
function sum(num1,num2){ return num1+num2; } function callSum1(num1,num2){ return sum.apply(this,arguments); } function callSum2(num1,num2){ return sum.apply(this,[num1,num2]); } alert(callSum1(10,10));//20 alert(callSum2(10,10));//20
而call方法和apply方法的不同在于参数的接受方式,call方法中参数都是直接传递给函数,所以在使用call()时,传递的参数必须逐个列举出来。
利用call方法和apply方法可以扩充函数赖以执行的作用域:
window.color="red"; var o={color:"blue"}; function sayColor(){ alert(this.color); } sayColor(); sayColor.call(this);//red sayColor.call(window);//red sayColor.call(o);//blue
最后一个方法:bind方法,将this值绑定到传给bind函数的值
window.color="red"; var 0={color:"blue"}; function sayColor(){ alert(this.color); } var objectSayColor=sayColor.bind(o);//绑定this值为o objectSayColor();//blue
五、基本包装类型
基本包装类型包括:Number、Boolean、string。每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而可以调用一些方法来操作这些数据。
var s1="some text";
var s2=s1.substring(2);
在上面这里的例子里,s1肯定是基本类型值,但是在执行第二句语句的时候,后台会创建一个同名的基本包装类型值s1,在执行完之后,会立马销毁这个基本包装类型。实际上执行第二条语句相当于执行下列代码
var s1=new String("some text");
var s2=s1.substring(2);
s1=null;
(1)Boolean
重点理解基本类型布尔值和Boolean对象之间的区别
1.Boolean对象在任何情况下被输出都会被转换为true
2.typeof操作符对基本类型返回Boolean,而对Boolean对象返回object
3.instanceof测试Boolean对象会返回true,而测试基本类型会返回false:
alert(falseObject instanceof Boolean);//true
alert(falseValue instanceof Boolean);//false
这是因为Boolean对象是Boolean类型的实例
(2)Number类型
将数值格式化为字符串的方法:
1.toFixe()方法,将会按照指定的小数位返回数值的字符串表示
var num=10;
alert(num.toFixed(2));//"10.00"
传入数值2,意为显示2位小数;如果数值本身的小数位大于指定的小数位,就会进行四舍五入
2.toExponential,返回以指数表示法表示的数值的字符串形式。
var num=10;
alert(num.toExponential(1));//"1.0e+1"
3.toPrecision()方法,根据具体情况,来决定将数值转换为字符串的格式。可能是固定大小格式(fixed),也可能是返回指数格式。该方法接收一个参数,就是数值的所有数字的位数(不包括指数的部分)
var num=99;
alert(num.toPrecision(1));//"1e+2"
alert(num.toPrecision(2));//"99"
alert(num.toPrecision(3));//"99.0"
注:1e+2表示100,因为要数值位只有一个,而1位数无法准确表达99,所以向上舍入为100.利用指数表示法来用一位来表示它。
(3)String类型
1.属性:length
length用于返回字符串中字符个数,应该注意的是,即使字符串中包含双字节的字符,如汉字,每个字符也仍然算是一个字符。
2.字符方法:
charAt(n):以单字符字符串的形式返回给定位置的那个字符
var stringValue="hello world";
alert(stringValue.charAt(1));//"e"
当然我们也可以利用stringValue[n],通过索引来获取个别字符的方法,同样也可以达到一样的效果
charCodeAt():以单字符字符编码字符串的形式返回给定位置的那个字符
var stringValue="hello world";
alert(stringValue.charCodeAt(1));//"101"
3.字符串操作方法
concat():实现字符串的拼接,可以传入多个字符串参数,并将这些字符串按照顺序接入原字符串的尾部。一般用加号“+”同样也可以做到同样的效果,所以我们更建议使用加号。
slice()、substr()、substring():根据参数的索引位置,创建新的字符串。当参数都是正数时,subtring和slice会返回以第一个索引参数为开始位置,第二个索引参数为结束位置的字符串。而substr则会返回以第一个索引参数为开始,长度为第二个参数的字符串。如果参数中出现了负数,则slice会将传入的负值与字符串的长度相加,以相加后的正数作为参数;substr会将第一个负的参数加上字符串的长度,而将负的第二个参数转换为0.substring则将全部负数都转换为0
4.字符串位置方法
indexOf和lastIndexOf,两个方法都接受一个字符串参数,并返回该字符串参数的位置,没有找到该字符串就会返回-1。而且这两个方法也接受第二参数,表示从字符串的那个位置开始搜索。两个方法的不同在于indexOf是返回第一次查找到目标字符串的位置,而lastIndexOF是返回最后一次查找到目标字符串的位置。
在使用第二个参数的情况下,我们可以用这两个方法来循环遍历字符串
var stringValue="Lorem ipsum dolor sit amet,consectetur adipisicing elit"; var positions=new Array(); var pos=stringValue.indexOf("e"); while(pos>-1){ positions.push(pos);//向数组末尾添加新的数组项 pos=stringValue.indexOf("e",pos+1);//开始位置为最近搜索索引值加一 } alert(positions);//3,24,32,35,52
5.trim():删除字符串前后的多余空格,并返回该新字符串
6.字符串大小写转换方法
toLocaleUppercase()、toUpperCase()、toLocaleLowerCase()、toLowerCase(),一般不清楚代码将在哪种语言环境下运行的话,使用针对地区的方法比较好。
7.字符串的模式匹配方法
match(),match实际上和正则表达式里的exec方法类型:
var text="cat,bat,sat,fat"; var pattern=/.at/; //与pattern.exec(text)相同 var matches=text.match(pattern); alert(matches.index);//0 alert(matches[0]);//cat alert(pattern.lastIndex);//0
search(),该方法返回字符串中第一个匹配项的索引,它的用法与matches一样,但是该方法永远都是从字符串的第一项开始向后查找模式的。
replace(),该方法用于替换子字符串的操作,它接受两个参数,第一个参数可以是一个RegExp对象或者一个字符串。第二个参数则是一个字符串或者一个函数。来看下面一个例子
var text="cat,bat,sat,fat"; var result=text.replace("at","ond"); alert(result);//"cond,bat,sat,fat";
上面这个例子中,如果两个参数都是字符串,那么被替换的就只会是第一个字符串,而后面的符合条件的子字符串都不会被替换。要解决这个问题,就要将第一个参数换为正则表达式,并且规定他的匹配模式为全局模式。
result=text.replace(/at/g,"ond"); alert(result);//"cond,bond,sond,fond"
如果第二个参数是函数,可以实现更为精确的操作:
function htmlEscape(text){ return text.replace(/[<>"&]/g,function(match,pos,originalText){ switch(match){ case "<": return "<"; case ">": return ">"; case "&": return "&"; case """: return """; } }); } alert(htmlEscape("<p calss="greeting">Hello world!</p>")); //<p calss="greeting">Hello world!!</p>
split(),基于指定的分割符将字符串分割成多个子字符串。
LocaleCompare(),用法与数组对象中的sort()相似,是一个比较字符串大小的函数,当第一个字符串应该拍第二个字符串之前,应该会返回负数(一般为-1),否则为整数(一般为1)。相等则为0。
formCharCode(),接收一个或多个字符编码,将他们转换为一个字符串,与charCodeAt方法操作相反。
8.Math对象
除了常用的min、max方法之外,Math对象还有一个非常实用的方法,random方法,这个方法可以用来随机显示一些名人名言和新闻事件。套用以下公式,可以利用该方法在某个整数范围内随机选择一个值:
值=Math.floor(Math.random()*可能值的总数+第一个可能的值)