第五章 引用类型
一、Object类型
创建object实例的方式有两种。
第一种是使用new操作符后跟object构造函数,如下所示:
ver person = new Object( ) ; person.name = “Nicholas” ; person.age = 29 ;
另一种方式是使用对象字面量表示法:
var person = { name : “Nicholas”, age : 29 } ;
对象字面量是向函数传递大量可选参数的首选形式。
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" })
访问对象属性时使用的都是点表示法,如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或者保留字,也可以使用方括号表示法。例如
var propertypeName = “name”;
alert(person[propertypeName]) ;
二、Array类型
创建数组的基本方式有两种,第一种是使用Array构造函数,如下面的代码所示:
var colors = new Array( );
可以省略new操作符。
第二种方式是使用数组的对象字面量。
var names = [ ];
var values = [ 1 , 2 ];
1.检测数组
Array.isArray( )方法。这个方法的目的是最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的。
2.转换方法
如前所述,所有对象都具有toLocaleString( )、toString( )和valueOf( )方法。其中,调用数组的toString( )方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。而调用valueOf( )返回的还是数组。
ver 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 alert(people.toString()); // Nikolaos , Grigorios alert(people.toLocaleString()); // Nicholas , Greg
当直接传值给alert( )时,默认调用的是toString( )方法。
3.栈方法
数组的push( )和pop( )方法,可以让数组的行为类似于其他数据结构,表现的像栈一样。push( )方法可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。而pop( )方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
例如:
var colors = [“red” , “blue”] ; colors.push(“black”); alert(colors.length) //3 alert(colors.po( ) ) //”black”
4.队列方法
队列在列表的末端添加项,从列表的前端移除项。实现这一操作的数组方法就是shift( ),它能够移除数组中的第一个项并返回该项,同时将数组长度减1。
var colors = ["red","green"]; colors.push("black"); colors.shift(“white”,”brown”) alert(colors.length); alert(colors.pop()); //black alert(colors.shift()); //red alert(colors.shift()); //green alert(colors.length); //0
unshift( )方法与shift( )方法相反,它能在数组前端添加任意个项并返回新数组的长度,因此,同时使用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
总结:unshift( )用来向数组前端添加项,push( )用来向数组后端添加项;shift( )用来移除最前端的项,pop( )用来移除最后端的项。
5.重排序方法
数组中,已经存在两个可以直接用来重排序的方法:reverse( )和sort( )。
reverse( )会反转数组的项排序,sort( )会按从小到大排序。
var values = [1 , 2 , 3 , 4 , 5];
values.reverse( ); // 5 , 4 , 3 , 2 , 1
values.sort( ); //1 , 2 , 3 , 4 , 5
6.操作方法
(1)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
(2)slice( )方法 :能够基于当前数组中的一个或多个项创建一个新数组。slice( )方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice( )方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回其实和结束位置之间的项——但不包括结束位置的项。注意,slice( )方法不会影响原始数组。
例如:
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
(3)splice( )方法 :使用的方式有以下三种
删除 :指定要删除的第一项的位置和要删除的项数就可以删除任意数量的项。
例如 :splice( 0 , 2 )会删除数组中的前两项。
插入 :提供三个参数——起始位置、0(要删除的项数)和要插入的项。
例如:splice( 2 , 0 , “red” , “green” )会删除当前数组位置2的项,然后再从位置2开始插入字符串“red”和“green”。
替换 :可以向指定位置插入任意数量的项,同时删除任意数量的项,只需指定3个参数——其实位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。
例如:splice( 2 , 1 , “red” , “green” )会删除当前数组位置2的项,然后再从位置2开始插入字符串“red”和“green”。
splice( )方法始终都会返回一个数组,该数组中包含从原始数组中删除的项。
7.位置方法
indexOf( )和lastIndexOf( )。这两个方法都接受两个参数:要查找的项和表示查找起点位置的索引。其中,indexOf( )从数组的开头开始向后查找,lastIndexOf( )从数组的末尾开始查找。
8.迭代方法
数组的5个迭代方法,都接收两个参数:要在每一项上运行的函数和运行该函数的作用域对象——影响this的值。
(1)every( ) :如果该函数对每一项都返回true,则返回true。
(2)filter( ) :返回该函数会返回true的项组成的数组。
(3)forEach( ) :没有返回值。
(4)map( ) :返回每次函数调用的结果组成的数组。
(5)some( ) :如果该函数对任一项返回true,则返回true。
every( )必须每一项都返回true它才返回true;而some( )只要有一项返回true,它就返回true。
9.归并方法
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
三、date类型
如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数,有两个方法:Date.parse( )、Date.UTC( )
四、function类型
1.函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。2.函数没有函数重载,声明两个同名函数,第二个函数会覆盖第一个函数。
3.函数声明和函数表达式:
alert(sum(10 , 10)) ; function sum(num1 , num2){ return num1 + num2 ; }
以上代码可以正常运行,因为在代码执行之前解析器会读取并将函数声明添加到执行环境中,对代码求值时,javascript引擎在第一遍会声明函数并将它们放到源代码树的顶部。
而下面的代码是错误的:
alert( sum(10 , 10) ) ; var sum = function ( num1 , num2 ) { return num1 + num2 ; }
原因在于函数位于一个初始化语句中,而不是一个函数声明。在执行到函数所在的语句之前,变量sum中不会保存有对函数的引用。
4.作为值的函数
函数名本身就是变量,因此函数可以像传递参数一样作为另一个函数的返回值。例如:
function callSomeFunction( someFunction , someArgument ){ return someFunction( someArgument ) ; }
5.函数内部属性
在函数内部,有两个特殊的对象:arguments和this。其中,arguments是类数组对象,包含着传入函数中的所有参数。它的callee属性时一个指针,指向拥有这个arguments对象的函数。
例如:
function factorial (num) { if(num <=1){ return 1 ; } else { return num*factorial (num -1) ; } }
以上函数耦合度比较高,修改一个函数名必须要修改两次,改善后的代码为:
function factorial (num) { if(num <=1){ return 1 ; } else { return num*arguments.callee(num -1) } }