首页 > 代码库 > JS基础知识回顾:引用类型(一)
JS基础知识回顾:引用类型(一)
在ECMAScript中引用类型是一种数据结构,用于将数据和功能组织在一起,而对象时引用类型的一个实例。
尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构,所以虽然说引用类型与类看起来想死,但他们并不是相同的概念。
不过引用类型有的时候也可以被称为对象定义,因为他们描述的是一类对象所具有的属性和方法。
新对象是使用new操作符后跟一个构造函数来实现的,构造函数本身就是一个函数,只不过该函数时处于创建新对象的目的而定义的。
ECMAScript提供了很多原生引用类型,以便开发人员用来实现常见的计算任务。
Object是ECMAScript中使用最多的一个类型,虽然Object的实例不具备多少功能,但对于在应用程序中存储和传输数据而言,它们确实是非常理想的选择。
创建Object实例的方式有两种:
使用new操作符后跟Object构造函数,例如:var person=new Object();person.name="Name";person.age=29;
还可以使用对象字面量表示法,需要注意的是利用对象字面量表示法表示对象时最后一个属性后面不能添加逗号,否则在IE7及更早版本及Opera中会导致错误。
对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程,例如:var person={name:"Name",age:29};
在使用对象字面量语法时,属性名可以使用字符串或数字,不过数字属性名会被自动转换为字符串,例如:var person={"name":"Name","age":29,5=true}
在使用对象字面量语法时,如果留空花括号,则可以定义值包含默认属性和方法的对象,例如:var person={};//与new Object()相同 person.name="Name";person.age=29;
在通过对象字面量定义对象时,实际上并不会调用Object构造函数(Firefox2及之前的版本会调用,但Firefox3之后就不会了)。
在实际应用中,人们往往更倾向于使用对象字面量语法,因为这种语法要求的代码量少,而且能够给人封装数据的感觉。
对象字面量也是向函数传递大量可选参数的首选方式,例如:
function displayInfo(args){
var output="";
if(typeof args.name=="string"){output+="Name:"+args.name+"\n";}
if(typeof args.age=="number"){output+="Age:"+args.age+"\n";}
alert(output);
}
displayInfo({name:"Nicholas",age:29});
displayInfo({name:"Greg"});
一般来说,访问对象属性时使用的都是点表示法,不过在JavaScript中也可以使用方括号来表示访问对象的属性,例如:
alert(person.name);//"Nicholas"(除非必须使用变量来访问属性,否则建议使用点表示法)
alert(person["name"]);//"Nicholas"(方括号表示法可以在方括号中写属性名)
alert(person[propertyName]);//"Nicholas"(方括号表示法也可以在方括号中写变量名)
person["first name"]="Nicholas";(在属性名当中有空格等非字母数字的字符时用点表示法会报错,所以最好用方括号表示法)
Array类型在ECMAScript中用来表示数组,与其他语言不同的是,ECMAScript数组的每一项可以保存任何类型的数据,且数组的大小是可以动态调整的。
创建数组的基本方式有两种:
第一种方式是使用Array构造函数,例如:var colors=new Array();
如果预先知道了数组的长度,也可以给构造函数传递该数量,而该数量会自动变成数组的length属性的值,例如:var colors=new Array(20);
也可以像Array构造函数传递数组中应该包含的项,例如:var colors=new Array("red","blue","green");
当只给构造函数传递一个值时,如果该值是一个数字,则会按照该数值创建包含给定项数的数组,如果传入的是其他类型的参数,则会创建包含那个值的只有一项的数组。
另外在创建Array构造函数时也可以省略new操作符,例如:var colors=Array(3);var names=Array("Greg");
第二种方式是使用数组字面量表示法,数组字面量由一对包含数组项的方括号表示,多个数组项之间用逗号隔开,例如:
var colors=["red","blue","green"];//创建一个包含三个字符串的数组
var names=[];//创建一个空数组
var values=[1,2,]//不建议使用,在IE8及之前版本会创建包含三个项目每项的值分别为1,2,undefined的数组,其他浏览器中会创建包含1,2两项的数组
var options=[,,,,,]//不建议使用,在IE8及之前版本会创建包含六个undefined的数组,其他浏览器中会创建包含五个undefined的数组
由于IE的处理和其他浏览器不同,所以建议不要使用缺省值的方式来创建数组。
与对象一样,在使用数组字面量表示法时,也不会调用Array构造函数(Firefox3及之前版本除外)。
在读取和设置数组的值时,要使用方括号并提供相应的基于0的数字索引,例如:
var colors=["red","blue","green"];//创建一个有三个字符串的数组
var names=[];//创建一个空数组
alert(colors[0]);//显示第一项(索引小于数组中的项数,则返回对应项的值)
colors[2]="black";//修改第三项
colors[3]="brown";//新增第四项(索引超出现有项数,则数组会自动增加到该索引值加1的长度)
alert(colors.length);//3(初始情况下,该数组当中有三个值)
alert(names.length);//0
colors.length=2;//length属性并不是只读的,通过length属性,可以从数组的末尾移除项目
alert(colors[2]);//undifined
colors.length=4;//length属性并不是只读的,通过length属性,也可以向数组的末尾增添项目
alert(colors[3]);//undifined(新增的每一项都会去的undefined值)
colors[colors.length]="black";//在位置4添加一种颜色(数组最后一项的索引始终都是length-1,因此下一个新项的位置就是length)
colors[colors.length]="brown";//在位置5再添加一种颜色(每当在数组末尾添加一项后,其length属性就会自动更新以反映这一变化)
colors[99]="pink";//当把一个值放在超出当前数组大小的位置上时,数组就会重新计算其长度值
alert(colors.length);//100(长度等于最后一项的索引加1)
数组最多可以包含4294967295项数据,如果想添加的项数超过这个上限值就会发生异常,而创建一个初始大小与这个上限值接近的数组,则可能会导致运行时间超长的脚本错误。
确定某个对象是不是数组可以利用instanceof操作符来实现,例如:if(value instanceof Array){//某些操作}
但是由于instanceof操作符会假设只有一个全局执行环境,如果网页中包含多个框架,那么实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。如果从一个框架向另外一个框架传入一个参数,那么传入的数组就与在第二个框架中原生创建的数组分别具有各自不同的构造函数。
为了解决这个问题ECMAScript5中新增了Array.isArray()方法,这个方法的目的就是最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的,例如:if(Array.isArray(value)){//某些操作}
支持该方法的浏览器有IE9+、Firefox4+、Safari5+、Opera10.5+、Chrome。
每个对象都具有toLocaleString()、toString()、valueOf()方法,这三种方法默认都会以逗号分隔的字符串的形式返回数组项。
var colors=["red","blue","green"];//创建一个包含三个字符串的数组
alert(colors.toString());//red,blue,green(调用toString()方法会返回由数组中每个值的字符串形式拼接而成的以逗号隔开的字符串)
alert(colors.valueOf());//red,blue,green(调用valueOf()方法会返回数组)
alert(colors);//red,blue,green(将数组直接传递给alert(),由于alert()要接收字符串参数,所以会在后台调用toString()方法而得到与toString()相同的结果)
当调用toLocaleString()方法时,也会创建一个数组值的以逗号分隔的字符串,而与前两种方法不同的是,这一次为了取得每一项的值,调用的是每一项的toLocaleString()方法。
var person1={toLocaleString:function(){return "Nikolaos";},toString:function(){return "Nikolaos";}};
var person2={toLocaleString:function(){return "Grigorios";},toString:function(){return "Greg";}};
var people=[person1,person2];
alert(people);//Nikolaos,Greg
alert(people.toString());//Nikolaos,Greg
alert(people.toLocaleString());//Nikolaos,Gigorios
如果使用join()方法,可以用不同的分隔符来构建数组字符串,join()方法值接受一个用作分隔符的字符串作为参数,然后返回包含所有数组项的字符串。
var color=["red","green","blue"];
alert(colors.join(","));//red,green,blue
alert(colors.join("||"));//red||green||blue
如果不给join()方法传入任何值或者传入undefined,则使用逗号作为分隔符,IE7及更早版本会错误的使用字符串"undefined"作为分隔符。
如果数组中的某一项的值为null或者undefined,那么该值在以上四种方法的返回结果中以空字符串表示。
ECMAScript数组也提供了一种让数组的行为类似于其他数据结构的方法。
栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构,而栈中项的插入(叫做推入)和移除(叫做弹出)值发生在栈的顶部。
ECMAScript中为数组提供了push()和pop()方法,用来实现类似于栈的行为。
push()方法可以接受任意数量的参数,并把他们逐个添加到数组末尾,最后返回修改后的数组的长度。
pop()方法则从数组末尾移除最后一项,减少数组的length值,最后返回移除的项。
var colors=new Array();//创建一个数组
var count=colors.push("red","green");//推入两项
alert(count);//2
count=colors.push("black");//推入另一项
alert(count);//3
var item=colors.pop();//取得最后一项
alert(item);//"black"
alert(colors.length);//2
队列是一种FIFO(First-In-First-Out,先进先出)的数据结构,队列在列表的末端添加项,从列表的前端移除项。
ECMAScript中提供了shift()方法,它能够移除数组中的第一项并返回该项,同时将数组的项目减1。
结合使用shift()和push()方法,可以像使用队列一样使用数组。
var colors=new Array();//创建一个数组
var count=colors.push("red","green","black");//推入三项
alert(count);//3
var item=colors.shift();//取得第一项
alert(item);//"red"
alert(colors.length);//2
ECMAScript中还提供了unshift()方法,它能够在数组前端添加任意个项并返回新数组的长度。
结合使用unshift()和pop()方法,可以从相反的方向来模拟队列。
var colors=new Array();//创建一个数组
var count=colors.unshift("red","green");//推入两项
alert(count);//2
count=colors.unshift("black");//推入另一项
alert(count);//3
var item=colors.pop();//取得最后一项
alert(item);//"green"
alert(colors.length);//2
IE7及更早版本对JavaScript的实现中存在一个偏差,其中的unshift()方法总是返回undefined而不是数组的新长度,IE8在兼容模式下回返回正确的长度值。
ECMAScript中的数组有两个重新排序的方法:reverse()和sort(),他们返回的都是经过排序之后的数组。
reverse()方法会反转数组项的顺序,例如:var values=[1,2,3,4,5];values.reverse();alert(values);//5,4,3,2,1
sort()方法在默认情况下回按照升序排列数组项(最小的排在最前面,最大的排在最后面)。
为了实现排序,sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串,以确定如何排序,例如:
var values=[0,1,5,10,15];values.sort();alert(values);//0,1,10,15,5(得到的是字符串比较的结果)
由于这种排序方式在很多情况下都不是最佳的,因此sort()方法还可以接收一个比较函数作为参数,以便我们制定哪个值位于哪个值前面,例如:
function compare(value1,value2){if(value1<value2){return -1;}else if(value1>value2){return 1;}else{retrun 0;}}
var values=[0,1,5,10,15];values.sort(compare);alert(values);//0,1,5,10,15
也可以通过反转比较函数中的返回值来实现降序排列。
对于数值类型或者其valueOf()方法会返回数值类型的对象类型,可以使用更简单的比较函数:function compare(value1,value2){return value2-value1;}
ECMAScript为操作应包含在数组中的项提供了很多方法。
concat()方法可以给予当前数组中的所有项创建一个新数组。
这个方法会先创建当前数组的一个副本,然后将接受到的参数添加到这个副本的末尾,最后返回新构建的数组。
在没有给concat()方法传递参数的情况下,它只是赋值当前数组并返回副本。
如果传递给concat()方法的是一个或多个数组,则该方法会将这些数组的每一项都添加到结果数组中。
如果传递给concat()方法的是值而不是数组,这些值就会被简单的添加到数组末尾。
var colors=["red","green","blue"];
var colors2=colors.concat("yellow",["black","brown"]);
alert(colors);//red,green,blue
alert(colors2);//red,green,blue,yellow,black,brown
slice()方法能够基于当前数组中的一个或多个项创建一个新数组。
slice()方法可以接收一个或两个参数,即要返回项的起始位置和结束位置。
在只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。
如果有两个参数,slice()方法返回起始位置和结束位置之间但不包含结束位置所在项的所有项。
如果slice()方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置。
如果传入的参数中结束位置小于起始位置,则返回空数组。
var colors=["red","green","blue","yellow","purple"];
var colors2=colors.slice(1);
var colors3=colors.slice(1,4);
var colors4=colors.slice(-2,-1);
var colors5=colors.slick(4,1);
alert(colors2);//green,blue,yellow,purple
alert(colors3);//green,blue,yellow
alert(colors4);//blue
alert(colors5);//null
splice()方法的主要用途是向数组的中部插入项,这种方法有如下三种规则:
(删除)如果给该方法传入两个参数,即要删除的第一项的位置和要删除的项数,则可以删除自指定位置起的任意数量的项;
(插入)如果给该方法传递三个或三个以上的参数,即起始位置、0(要删除的项数)和要插入的项,则可以向指定位置插入任意数量的项;
(替换)如果给该方法传递三个参数,即起始位置、要删除的项数和要插入的任意数量的项(删除数量和插入数量可以不相等),则可以向指定位置插入任意数量的项且删除任意数量的项。
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");//从位置1开始插入两项
alert(colors);//green,yellow,orange,blue
alert(removed);//返回一个空数组
removed=colors.splice(1,1,"red","purple");//从位置1开始删除一项后插入两项
alert(colors);//green,red,purple,orange,blue
alert(removed);//yellow
ECMAScript5为数组实例添加了两个位置方法:indexOf()和lastIndexOf()。
这两个方法都接受两个参数:要查找的项和表示查找起点位置的索引(可选)。
其中,indexOf()方法从数组的开头开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。
这两个方法都要返回要查找的项在数组中的位置,或者在没有找到的情况下回返回-1.
在比较第一个参数与数组中的每一项时,会使用全等操作符,且如果数组中有多个匹配项则只返回查找到的第一个位置。
支持这两种方法的浏览器有IE9+、Firefox2+、Safari3+、Opera9.5、Chrome。
ECMAScript5为数组定义了5个迭代方法,每个方法都接收两个参数:要在每一项上运行的函数和运行该函数的作用域对象(可选,影响this的值)。
传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。
every()方法对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
some()方法对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
filter()方法对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
map()方法对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
forEach()方法对数组中的每一项运行给定函数,该方法没有返回值。
var numbers=[1,2,3,4,5,4,3,2,1];
var everyResult=numbers.every(function(item,index,array){return (item>2);});
alert(everyResult);//false
var someResult=numbers.some(function(item,index,array){return (item>2);});
alert(someResult);//true
var filterResult=numbers.filter(function(item,index,array){return (item>2);});
alert(filterResult);//[3,4,5,4,3]
var mapResult=numbers.map(function(item,index,array){return item*2;});
alert(mapResult);//[2,4,6,8,10,8,6,4,2]
numbers.forEach(function(item,index,array){//执行某些操作});
//forEach()方法只是对数组中的每一项运行传入的函数,没有返回值,本质上与使用for循环迭代数组一样
支持这些方法的浏览器有IE9+、Firefox2+、Safari3+、Opera9.5、Chrome。
ECMAScript5还新增了两个归并数组的方法:reduce()和reduceRight()。
这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
其中,reduce()方法从数组的第一项开始逐个遍历到最后,reduceRight()则从数组的最后一项开始向前遍历到第一项。
这两个方法都接受两个参数:一个在每一项上调用的函数和作为归并基础的初始值(可选)。
传给这两个方法的函数接收四个参数:前一个值、当前值、项的索引和数组对象。
这个函数返回的值会作为第一个参数自动传给下一项,第一次迭代发生在数组的第二项上。
使用这两个方法当中的哪一个完全取决于从哪头开始遍历数组,初次之外他们完全相同。
var values=[1,2,3,4,5];
var sum=values.reduce(function(prev,cur,index,array){return prev+cur;});
alert(sum);//15
var sum2=values.reduceRight(function(prev,cur,index,array){return prev+cur;});
alert(sum2);//15
支持这两种方法的浏览器有IE9+、Firefox2+、Safari3+、Opera9.5、Chrome。