国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > web前端 > htmlcss > JavaScript:引用类型

JavaScript:引用类型

来源:程序员人生   发布时间:2016-06-03 19:00:31 阅读次数:2588次

  援用类型的值(对象)是援用类型的1个实例。在ECMAscript中,援用类型是1种数据结构,用于将数据和功能组织在1起。它也常被称为类,但是这类称呼其实不妥当。虽然ECMAscript从技术讲是1门面向对象的语言,但是它不具有传统的面向对象语言所支持的类和接口等基本结构。援用类型有时候也称为对象定义,由于它们描写的是1类对象所具有的属性和方法。

1、Object类型

  Object类型是JavaScript中使用最多的1种类型。虽然Object的实例不具有多少功能,但对在利用程序中存储和传输数据而言,它确切是非常理想的选择。

  创建Object实例的方式有两种,第1种是使用new操作符后跟Object构造函数

var person = new Object(); person.name = "tt"; person.age = 12;

  另外一种方式是使用对象字面量表示法

var person = { name : 'tt', age : 12 }

  另外,使用对象字面量语法时,如果留空其花括号,则可以定义值包括默许属性和方法的对象。

var person = {}; //与new Object()相同 person.name = "tt"; person.age = 12;

  虽然可使用前面介绍的任何1种方法来定义对象,但开发人员更青睐第2种方法(对象字面量语法),由于这类语法要求的代码量少,而且能给人封装数据的感觉。实际上,对象字面量也是向函数传递大量可选参数的首选方式,例如:

function showInfo(args) { if(args.name != undefined) { alert(args.name); } if(args.age != undefined) { alert(args.age); } } showInfo({ name:'name', age:12 }); showInfo({name:'name'});

  1般来讲,访问对象属性时使用的都是点表示法,这也是很多面向对象语言中通用的语法。不过,在JavaScript也能够使用方括号表示法来访问对象的属性。例如:

alert(person.name); alert(person['name']);

  从功能上看,这两种访问对象属性的方法没有任何区分。但方括号语法的主要优点是可以通过变量来访问属性。

var propertyName = 'name'; alert(person[propertyName]);

  通常,除非必须使用变量来访问属性,否则我们建议使用点表示法。

2、Array类型

  除object以外,Array类型恐怕是ECMAscript中最经常使用的类型了,ECMAscript中的数组与其他多数语言中的数组有着相当大的区分。虽然JavaScript数组与其他语言中的数组都是数据的有序列表,但与其他语言不同的是,JavaScript数组的每项可以保持任何类型的数据。也就是说,可以用数组的第1个位置来保存字符串,用第2个位置来保存数值,用第3个位置来保存对象。而且,JavaScript数组的大小是可以动态调剂的,便可以随着数据的添加自动增长以容纳新增数据。

  创建数组的基本方式有两种。第1种是使用Array构造函数

var colors1 = new Array(); var colors2 = new Array(20); var colors3 = new Array('red','blue','yellow');

   在使用Array构造函数时可以省略new操作符,例如:

var colors = Array(10); var colorName = Array('red');

  创建数组的第2种基本方式是使用数组字面量表示法

var colors1 = []; var colors2 = ['red','blue','yellow'];

  在读取和设置数组的值时,要使用方括号并提供相应值的基于0的数字索引。

var colors = ['red','blue','yellow']; //定义1个字符串数组 alert(colors[0]); //显示第1项 colors[2] = 'green'; //修改第3项 colors[3] = 'black'; //新增第4项

  数组的长度保存在其length属性中,这个属性始终会返回0或更大的值。

var colors = ['red','blue','yellow']; var names = []; alert(colors.length); //3 alert(names.length); //0

  数组的length属性很有特点——它不是只读的。因此,通过设置这个属性,可以从数组的末尾移除项或想数组中添加新项。

var colors = ['red','blue','yellow']; colors.length = 2; alert(colors[2]); //undefined

  这个例子中的数组colors1开始有3个值。将其length属性设置为2会移除最后1项,结果再访问colors[2]就会显示undefined了。

  利用length属性也能够方便地在数组末尾添加新项。

var colors = ['red','blue','yellow']; colors[colors.length] = 'green'; //在位置3添加1种色彩 colors[colors.length] = 'black'; //再在位置4添加1种色彩

  由于数组最后1项的索引始终是length⑴,因此下1个新项的位置就是length。

(1)、检测数组

     ECMAscript5新增了Array.isArray()方法,这个方法的目的是终究肯定某个值究竟是不是数组,而不管它是在哪一个全局履行环境中创建。这个方法的用法以下:

     if(Array.isArray(value)){

        //对数组履行某些操作;

     }

(2)、转换方法

  所有对象都具有toLocaleString()、toString()和valueOf()方法。其中,调用数组的toString()和valueOf()方法会返回相同的值,即由数组中每一个值的字符串构成拼接而成的1个以逗号分隔的字符串。实际上,为了创建这个字符串会调用数组每项的toString()方法。  

var colors = ['red','blue','yellow']; alert(colors.toString()); //red,blue,yellow alert(colors.valueOf()); //red,blue,yellow alert(colors); //red,blue,yellow

  我们首先显式地调用了toString()和valueOf()方法,以便返回数组的字符串表示,每一个值的字符串表示拼接成了1个字符串,中间以逗号分隔。最后1行代码直接将数组传递给了alert()。由于alert()要接收字符串参数,所有它会在后台调用toString()方法,由此会得到与直接调用toString()方法相同的结果。

  另外,toLocaleString()方法常常也会返回与toString()和valueOf()方法相同的值,但也不总是如此。当调用数组的toLocaleString()方法时,它也会创建1个数组值的以逗号分隔的字符串。而与前两个方法唯1的不同的地方在于,这1次为了获得每项的值,调用的是每项的toLocaleString()方法,而不是toString()方法。例如:

   

var person1 = { toLocaleString : function(){ return "person1 : toLocaleString"; }, toString : function(){ return "person1 : toString"; } }; var person2 = { toLocaleString : function(){ return "person2 : toLocaleString"; }, toString : function(){ return "person2 : toString"; } }; var people = [person1,person2]; alert(people); //person1 : toString,person2 : toString alert(people.toString()); //person1 : toString,person2 : toString alert(people.toLocaleString()); //person1 : toLocaleString,person2 : toLocaleString

  数组继承的toLocaleString()、toString()和valueOf()方法,在默许情况下都会以逗号分隔的字符串的情势返回数组项。而如果使用join()方法,则可使用不同的分隔符来构建这个字符串。   

var colors = ['red','blue','yellow']; alert(colors.join(',')); //red,blue,yellow alert(colors.join('||')); //red||blue||yellow

  注意:如果数组中的某1项的值是null或undefined,那末该值在join()、toString()、toLocaleString()和valueOf()方法返回的结果中以空字符串表示。

(3)、栈方法

  JavScript数组也提供了1种让数组的行动类似于其他数据结构的方法。具体来讲,数组可以表现得就像栈1样,后者是1种可以限制插入和删除项的数据结构。栈是1种落后先出的数据结构。而栈中项的插入(叫做推入)和移除(叫做弹出),只产生在1个位置——栈的顶部。JavaScript提供了push()和pop()方法,以便实现类似的栈行动。

  push()方法可以接收任意数量的参数,把它们逐一添加到数组末尾,并返回修改后数组的长度。而pop()方法则从数组末尾移除最后1项,减少数组的length值,然后返回移除的项。  

var colors = new Array(); //创建1个数组 var count = colors.push('red','blue'); //推入两项 alert(count); //2 count = colors.push('yellow'); //再推入1项 alert(count); //3 var item = colors.pop(); //获得最后1项 alert(item); //yellow alert(colors.length); //2

(4)、队列方法

  队列数据结构的访问规则是先进先出。队列在列表的末端添加项,从列表的前端移除项。由于push()是向数组末端添加项的方法,因此要摹拟队列只需1个从数组前端获得项的方法。实现这1操作的数组方法就是shift(),它能够移除数组中的第1个项并返回该项,同时将数组长度减1。结合使用shift()和push()方法,可以像使用队列1样使用数组:   

var colors = new Array(); //创建1个数组 var count = colors.push('red','blue'); //推入两项 alert(count); //2 count = colors.push('yellow'); //再推入1项 alert(count); //3 var item = colors.shift(); //获得第1项 alert(item); //red alert(colors.length); //2

  JavaScript还为数组提供了1个unshift()方法。顾名思义,unshift()与shift()的用处相反:它能在数组前端添加任意个项并返回新数组的长度。因此,同时使用unshift()和pop()方法,可以从反方向来摹拟队列,即在数组的前端添加项,从数组的末端移除项,例如:   

var colors = new Array(); //创建1个数组 var count = colors.unshift('red','blue'); //推入两项 alert(count); //2 count = colors.unshift('yellow'); //再推入1项 alert(count); //3 var item = colors.pop(); //获得第1项 alert(item); //blue alert(colors.length); //2

  注意:IE对JavaScript的实现中存在1个偏差,其unshift()方法总是返回undefined而不是数组的新长度。

(5)、重排序方法

  数组中已存在两个可以直接用来重排序的方法:reverse()和sort(),reverse()方法会反转数组项的顺序。

var values = [1,2,3,4,5]; values.reverse(); alert(values); //5,4,3,2,1

  在默许情况下,sort()方法按升序排列数组项——即最小的值位于最前面,最大的值排在最后面。为了实现排序,sort()方法会调用每一个数组项的toString()转型方法,然后比较得到的字符串,以肯定如何排序。即便数组中的每项都是数值,sort()方法比较的也是字符串,以下所示:

var values = [0,1,5,10,15]; values.sort(); alert(values); //0,1,10,15,5

  可见,即便例子中值的顺序没有问题,但sort()方法也会根据测试字符串的结果改变原来的顺序。由于数值5虽然小于10,但在进行字符串比较时,“10”则位于“5”的前面。因此sort()方法可以接收1个比较函数作为参数,以便我们指定哪一个值位于哪一个值的前面。  

function compare(value1,value2){ if(value1 < value2){ return 1; } else if(value1 > value2){ return ⑴; } else{ return 0; } } var values = [0,1,5,10,15]; values.sort(compare); alert(values); //15,10,5,1,0

  对数值类型或其valueOf()方法会返回数值类型的对象类型,可使用1个更简单的比较函数。这个函数主要用第2个值减第1个值便可。

function compare(value1,value2){ return value2 - value1; }

(6)、操作方法

  JavaScript对操作数组提供了很多方法。其中,concat()方法可以基于当前数组中的所有项创建1个新数组,如果传递给concat()方法的是1或多个数组,则该方法会将这些数组中的每项都添加到结果数组中。如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。

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()方法能够基于当前数组中的1或多个项创建1个新数组。slice()方法可以接受1或两个参数,即要返回项的起始和结束位置。在只有1个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之前的项——但不包括结束位置的项。   

var colors = ['red','green','blue','yellow','black','brown']; var colors2 = colors.slice(1); var colors3 = colors.slice(1,4); alert(colors2); //green,blue,yellow,black,brown alert(colors3); //green,blue,yellow

  下面我们来介绍splice()方法,这个方法恐怕要算是最强大的数组方法了,splice()主要用处是向数组的中部插入项,但使用这类方法的方式则有以下3种。

  删除——可以删除任意数量的项,只需指定2个参数:要删除的第1项的位置和要删除的项数。例如,splice(0,2)会删除数组中的前两项。

  插入——可以向指定位置插入任意数量的项,只需提供3个参数:起始位置、0(要删除的项数)、要插入的项。如果要插入多个项,可以再传入第4、第5,以致任意多个项。例如,splice(2,0,'red','green')会从当前数组的位置2开始插入字符串'red'和'green'。

  替换——可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数没必要与删除的项数相等。例如,splice(2,1,'red','green')会删除当前数组位置2的项,然后再从位置2开始插入字符串'red'和'green'。   

var colors = ['red','green','blue']; var removed = colors.splice(0,1); //删除第1项 alert(colors); //green,blue alert(removed); //red removed = colors.splice(1,0,'yellow','black'); //从位置1开始插入两项 alert(colors); //green,yellow,black,blue alert(removed); //返回1个空数组 removed = colors.splice(1,1,'red','brown'); //插入两项,删除1项 alert(colors); //green,red,brown,black,blue alert(removed); //yellow

(7)、位置方法

  ECMAscript5为数组实例添加了两个位置方法:indexOf()和lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选的)表示查找出发点位置的索引。其中indexOf()方法从数组的开头开始向后查找,lastIndexOf()方法从数组的末尾开始向前查找。 

var numbers=[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

(8)、迭代方法

  ECMAscript5为数组定义了5个迭代方法。每一个方法都接收两个参数:要在每项上运行的函数和(可选的)运行该函数的作用域对象—影响this的值。传入这些方法中的函数会接收3个参数:数组项的值、该项在数组中的位置和数组对象本身。

     every():对数组中的每项运行给定函数,如果该函数对每项都返回true,

            则返回true。

    filter():对数组中的每项运行给定函数,返回该函数会返回true的项组

            成的数组。

   forEach():对数组中的每项运行给定函数,这个方法没有返回值。

      map():对数组中的每项运行给定函数,返回每次调用函数的结果组成

         的数组。

     some():对数组中的每项运行给定函数,如果该函数对任1项返回true,

         则返回true。  

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); //ture 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] var forEachResult=numbers. forEach(function(item,index,array){ //履行某些操作; })

(9)、归并方法

  ECMAscript5还新增了两个归并数组的方法:reduce()和reduceRight()。这两个方法都会迭代数组的所有项,然后构建1个终究返回的值。其中,reduce()方法从数组的第1项开始,逐一遍历到最后。而reduceRight()则从数组的最后1项开始,向前遍历到第1项。

 

3、Date类型

  JavaScript中的Date类型是在初期Java中的java.util.Date类基础上构建的。为此,Date类型使用自UTC 1970年1月1日零时开始经过的毫秒数来保存日期。在使用这类数据存储格式的条件下,Date类型保存的日期能够精确到1970年1月1日之前或以后的100000000年。

  要创建1个日期对象,使用new操作符和Date构造函数便可。

             var now = new Date();

  在调用Date构造函数而不传递参数的情况下,新创建的对象自动取得当前日期和时间。如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数。为了简化这1计算进程,JavaScript提供了两个方法:Date.parse()和Date.UTC()。

  其中,Date.parse()方法接收1个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数。JavaScript没有定义Date.parse()应当支持哪一种格式,因此这个方法的行动因实现而异,而且通常是因地区而异。将地区设置为美国的阅读器通常都接受以下日期格式:

  ● "月/日/年",如:6/13/2204

  ● "英文月名 日,年",如:January 12,2004

  ● "英文星期几 英文月名 日 年 时:分:秒 时区",如:Tue May 25 2004 00:00:00 GMT-0700

  例如,要为2004年5月25日创建1个日期对象,可使用下面的代码:

  var someDate = new Date(Date.parse("May 25 , 2004"));

  如果传入Date.parse()方法的字符串不能表示日期,那末它会返回NaN。实际上,如果直接将表示日期的字符串传递给Date构造函数,也会在后台调用Date.parse()。换句话说,下面的代码与前面的例子是等价的:

  var someDate = new Date('May 25 , 2004');

  Date.UTC()方法一样也返回表示日期的毫秒数,但它与Date.parse()在构建值时使用不同的信息。Date.UTC()的参数分别是年份、基于0的月份(1月是0,2月是1,以此类推)。月中的哪1天(1到31)、小时数(0到23)、分钟、秒和毫秒数。在这些参数中,只有前两个参数(年和月)是必须的。如果没有提供月中的天数,则假定天数为1;如果省略其他参数,则统统假定为0。

  //GMT时间2000年1月1日零时

  var y2k = new Date(Date.UTC(2000, 0));

  //GMT时间2005年5月5日下午5:55:55

  var allFives = new Date(Date.UTC(2005,4,5,17,55,55));

  犹如模仿Date.parse()1样,Date构造函数也会模仿Date.UTC(),但有1点明显不同:日期和时间都基于本地时区而非GMT来创建的。可以将前面的例子重写以下:

  //本地时间2000年1月1日零时

  var y2k = new Date(2000,0);

  //本地时间2005年5月5日下午5:55:55

  var allFives = new Date(2005,4,5,17,55,55);

  Date类型还有1些专门用于将日期格式化为字符串的方法,这些方法以下:

  ● toDateString()——以特定于实现的格式显示星期几、月、日和年

  ● toTimeString()——以特定于实现的格式显示时、分、秒和时区

  ● toLocaleDateString()——以特定于地区的格式显示星期几、月、日和年

  ● toLocaleTimeString()——以特定于实现的格式显示时、分、秒

  ● toUTCString()——以特定于实现的格式完全的UTC日期

  以上这些字符串格式方法的输出也是因阅读器而异的,因此没有哪个方法能够用来在用户界面中显示1致的日期信息。

以下是Date类型的所有方法:

Date() 返回当日的日期和时间。

getDate() 从 Date 对象返回1个月中的某1天 (1 ~ 31)。

getDay() 从 Date 对象返回1周中的某1天 (0 ~ 6)。

getMonth() 从 Date 对象返回月份 (0 ~ 11)。

getFullYear() 从 Date 对象以4位数字返回年份。

getYear() 请使用 getFullYear() 方法代替。

getHours() 返回 Date 对象的小时 (0 ~ 23)。

getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。

getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。

getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。

getTime() 返回 1970 年 1 月 1 日至今的毫秒数。

getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差。

getUTCDate() 根据世界时从 Date 对象返回月中的1天 (1 ~ 31)。

getUTCDay() 根据世界时从 Date 对象返回周中的1天 (0 ~ 6)。

getUTCMonth() 根据世界时从 Date 对象返回月份 (0 ~ 11)。

getUTCFullYear() 根据世界时从 Date 对象返回4位数的年份。

getUTCHours() 根据世界时返回 Date 对象的小时 (0 ~ 23)。

getUTCMinutes() 根据世界时返回 Date 对象的分钟 (0 ~ 59)。

getUTCSeconds() 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。

getUTCMilliseconds() 根据世界时返回 Date 对象的毫秒(0 ~ 999)。

parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。

setDate() 设置 Date 对象中月的某1天 (1 ~ 31)。

setMonth() 设置 Date 对象中月份 (0 ~ 11)。

setFullYear() 设置 Date 对象中的年份(4位数字)。

setYear() 请使用 setFullYear() 方法代替。

setHours() 设置 Date 对象中的小时 (0 ~ 23)。

setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。

setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。

setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。

setTime() 以毫秒设置 Date 对象。

setUTCDate() 根据世界时设置 Date 对象中月份的1天 (1 ~ 31)。

setUTCMonth() 根据世界时设置 Date 对象中的月份 (0 ~ 11)。

setUTCFullYear() 根据世界时设置 Date 对象中的年份(4位数字)。

setUTCHours() 根据世界时设置 Date 对象中的小时 (0 ~ 23)。

setUTCMinutes() 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。

setUTCSeconds() 根据世界时设置 Date 对象中的秒钟 (0 ~ 59)。

setUTCMilliseconds() 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。

toSource() 返回该对象的源代码。

toString() 把 Date 对象转换为字符串。

toTimeString() 把 Date 对象的时间部份转换为字符串。

toDateString() 把 Date 对象的日期部份转换为字符串。

toGMTString() 请使用 toUTCString() 方法代替。

toUTCString() 根据世界时,把 Date 对象转换为字符串。

toLocaleString() 根据本地时间格式,把 Date 对象转换为字符串。

toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部份转换为字符串。

toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部份转换为字符串。

UTC() 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。

valueOf() 返回 Date 对象的原始值。

 

4、Function类型

  JavaScript中甚么最成心思,我想那莫过于函数了——而成心思的本源,则在于函数实际上时对象。每一个函数都是Function类型的实例,而且都与其他援用类型1样具有属性和方法。由于函数是对象,因此函数名实际上也是1个指向函数对象的指针,不会与某个函数绑定。

  函数通常是使用函数声明语法定义的,以下面例子所示:

    

function sum(num1,num2) { return num1 + num2; }

  这与下面使用函数表达式定义函数的方式几近相差无几:

   

var sun = function(num1,num2){ return num1 + num2; };

  以上代码定义了变量sum并将其初始化为1个函数。function关键字后面没有函数名,这是由于在使用函数表达式定义函数时,没有必要使用函数名——通过变量sum便可援用函数。另外,还要注意函数末尾有1个分号,就像声明其他变量时1样。

  最后1种定义函数的方式是使用Function构造函数。Function构造函数可以接收任意数量的参数,但最后1个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。

 var sum = Function('num1','num2','return num1 + num2'); //不推荐使用此种方式

  由于函数名仅仅是指向函数的指针,因此函数名与包括对象指针的其他变量没有甚么不同。换句话说,1个函数可能会有多个名字,例如:  

function sum(num1,num2) { return num1 + num2; } alert(sum(10,10)); //20 var anotherSum = sum; alert(anotherSum(10,10)); //20 sum = null; alert(anotherSum(10,10)); //20

  注意:使用不带括号的函数名是访问函数指针,而非调用函数。

(1)、函数声明与函数表达式

  目前为止,我们1直没有对函数声明和函数表达式加以区分。而实际上, 解析器在向履行环境中加载数据时,对函数声明和函数表达式并不是1视同仁。解析器会率先读取函数声明,并使其在履行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器履行到它所在的代码行,才会真正被解释履行。  

alert(sum(10,10)); function sum(num1,num2) { return num1 + num2; }

  以上代码完全可以正常运行。由于在代码开始履行之前,解析器就已读取函数声明并将其添加到履行环境中了。如果像下面例子所示,把上面的函数声明改成变量初始化方式,就会在履行期间致使毛病。    

alert(sum(10,10)); var sum = function(num1,num2) { return num1 + num2; }

 (2)、作为值的函数

  由于JavaScript中的函数名本身就是变量,所以函数也能够作为值来使用。也就是说,不但可以像传递参数1样把1个函数传递给另外一个函数,而且可以将1个函数作为另外一个函数的结果返回。   

function callSomeFunction(someFunction , someArgument) { return someFunction(someArgument); }

  这个函数接受两个参数,第1个参数应当是1个函数,第2个参数应当是要传递给该函数的1个值。然后,就能够像下面的例子1样传递函数了:    

function add(num) { return num + 10; } var result = callSomeFunction(add,10); alert(result); //20

  固然,可以从1个函数中返回另外一个函数,而且这也是极其有用的1种技术。  

function createSumFunction() { return function(num1,num2){ return num1 + num2; }; } var sumFunction = createSumFunction(); alert(sumFunction(10,10)); //20

(3)、函数内部属性

  在函数内部,有两个特殊的对象:arguments和this。其中,arguments是1个类数组对象,包括着传入函数中的所有参数,而且可使用length属性来肯定传递进来多少个参数。   

function sayHi(){ alert(arguments.length); //2 alert(arguments[0] + ',' + arguments[1]); //hello,world } sayHi('hello','world');

  虽然arguments的主要用处是保存函数参数,但这个对象还有1个名叫callee的属性,该属性是1个指针,指向具有这个arguments对象的函数。看下面这个非常经典的阶乘函数:    

function factorial(num) { if(num <= 1){ return 1; } else { return num * factorial(num⑴); } }

  定义阶乘函数1般都要用到递归算法;如上面的代码,在函数着名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的履行与函数名factorial牢牢耦合在1起。为了消除这类紧密耦合的现象,可以像下面这样使用arguments.callee   

function factorial(num) { if(num <= 1){ return 1; } else { return num * arguments.callee(num⑴); } }

  在这个重写后的factorial()函数的函数体内,没有再援用函数名factorial。这样,不管援用函数时使用是甚么名字,都可以保证正常完成递归调用。例如:   

var trueFactorial = factorial; factorial = function(){ return 0; }; alert(trueFactorial(5)); //120 alert(factorial(5)); //0

  函数内部的另外一个特殊对象是this,this援用的是函数据以履行操作的对象——或也能够说,this是函数在履行时所处的作用域(当在网页的全局作用域中调用函数时,this对象援用的就是window)。看下面的例子:  

window.color = 'red'; var o = {color:'blue'}; function sayColor() { alert(this.color); } sayColor(); //red o.sayColor = sayColor; o.sayColor(); //blue

  上面这个函数sayColor()是在全局作用域中定义的,它援用了this对象。由于在调用函数之前,this的值其实不肯定,因此this可能会在代码履行进程中援用不同的对象。当在全局作用域中调用sayColor()时,this援用的是全局对象 window;换句话说,对this.color求值会转换成对window.color求值,因而结果就是'red'。而当把这个函数赋给对象o并调用o.sayColor()时,this援用的是对象o,因此对this.color求值会转换成对o.color求值,结果就是'blue'。

(4)、函数属性和方法

  由于JavScript中的函数是对象,因此函数也有属性和方法。每一个函数都包括两个属性:length和prototype。其中,length属性表示函数希望接收的命名参数的个数   

function sayName(name) { alert(name); } function sayHi() { alert('hi'); } alert(sayName.length); //1 alert(sayHi.length); //0

  在JavaScript中最耐人寻味的就要数prototype属性了。对援用类型而言,prototype是保存它们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都是保存在prototype名下,只不过是通过各自对象的实例访问罢了。在创建自定义援用类型和实现继承时,prototype属性的作用是极其重要的(这里就不对prototype属性做详细介绍了)。

  每一个函数都包括两个非继承而来的方法:apply()和call()。这两个方法的用处是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先,apply()方法接受两个参数:1个是在其中运行函数的作用域,另外一个是参数数组。其中,第2个参数可以是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

  在上面例子中,callSum1()在履行sum()函数时传入了this作为作用域(由于是在全局作用域中调用的,所以传入的就是window对象)和arguments对象。而callSum2一样也调用了sum()函数,但它传入的则是this和1个参数数组。

  call()方法与apply()方法的作用相同,它们的区分仅在于接收参数的方式不同。对call()方法而言,第1个参数是作用域没有变化,变化的只是其余的参数都是直接传递给函数的。   

function callSum2(num1,num2) { return sum.call(this,num1,num2); } alert(callSum2(10,10)); //20

  事实上,传递参数并不是apply()和call()真实的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域。看下面的例子:

window.color = 'red'; var o = {color:'blue'}; function sayColor() { alert(this.color); } sayColor(); //red sayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blue

  在上面的例子中,当运行sayColor.call(o)时,函数的履行环境就不1样了,由于此时函数体内的this对象指向了o,因而结果显示"blue"。

  注意:每一个函数都有1个非标准的caller属性,该属性指向调用当前函数的函数。1般是在1个函数的内部,通过arguments.callee.caller来实现对调用栈的追溯。目前,IE、FireFox、Chrome都支持该属性,但建议将该属性用于调试目的。

4、内置对象

 JavaScript中有两个内置对象:Global和Math。

(1)、Global对象

  Global(全局)对象可以说是ECMAscript中最特别的1个对象了,由于不管你从甚么角度上看,这个对象都是不存在的。JavaScript中的Global对象在某种意义上是作为1个终极的“兜底儿对象”来定义的。换句话说,不属于任何其他对象的属性和方法,终究都是它的属性和方法。事实上,没有全局变量或全局函数;所有在全局作用域定义的属性和函数,都是Global对象的属性。诸如isNaN()、parseInt()和parseFloat(),实际上全都是Global对象的方法,Global对象还包括其他1些方法。

    1)、URI编码方法

  Global对象的encodeURI()和encodeURIComponent()方法可以对URI进行编码,以便发送给阅读器。有效的URI中不能包括某些字符,例如空格。而这两个URI编码方法就能够对URI进行编码,它们用特殊的UTF⑻编码替换所有没有效的字符,从而让阅读器能够接受和理解。

  其中,encodeURI()主要用于全部URI(例如:http://www.test.com/test value.html),而encodeURIComponent()主要用于对URI中的某1段(例如前面URI中的test value.html)进行编码。它们主要区分在于,encodeURI()不会对本身属于URI的特殊字符进行编码,例如冒号、正斜杠、问好和井号;而encodeURIComponent()则会对它发现的任何非标准字符进行编码。

var uri = "http://www.test.com/test value.html#start"; //"http://www.test.com/test%20value.html#start" alert(encodeURI(uri)); //"http%3A%2F%2Fwww.test.com%2Ftest%20value.html%23start" alert(encodeURIComponent(uri));

  1般来讲,使用encodeURIComponent()方法的时候要比使用encodeURI()更多,由于在实践中更常见的是对查询字符串参数而不是对基础URI进行编码。

  与encodeURI()和encodeURIComponent()方法对应的两个方法分别是decodeURI()和decodeURIComponent()。其中,decodeURI()只能对encodeURI()替换的字符进行解码,一样,decodeURIComponent()只能对encodeURIComponent()替换的字符进行解码。

    2)、eval()方法

  eval()方法大概是JavaScript中最强大的1个方法了,eval()方法就像是1个完全的JavaScript解析器,它只接受1个参数,即要履行的字符串。看下面的例子:

  eval("alert('hi')");

  这行代码的作用等价于下面这行代码:

  alert('hi');

  当解析器发现代码中调用eval()方法时,它会将传入的参数当作实际的JavaScript语句来解析,然后把履行结果插入到原位置。通过eval()履行的代码被认为是包括该次调用的履行环境的1部份,因此被履行的代码具有与该履行环境相同的作用域链。这意味着通过eval()履行的代码可以援用在包括环境中定义的变量,例如:

var msg = 'hello world'; eval('alert(msg)'); //hello world

  可见,变量msg是在eval()调用的环境以外定义的,但其中调用的alert()依然能够显示“hello world”。这是由于上面第2行代码终究被替换成了1行真实的代码。一样地,我们也能够在eval()调用中定义1个函数,然后再在该调用的外部代码中援用这个函数:

eval("function sayHi(){alert('hi')}"); sayHi();

  注意:能够解释代码字符串的能力非常强大,但也非常危险。因此在使用eval()时必须极其谨慎,特别是在用它履行用户输入数据的情况下。否则,可能会有歹意用户输入要挟你的站点或利用程序安全的代码(即所谓的代码注入)。

(2)、Math对象

  与我们在JavaScript直接编写的计算功能相比,Math对象提供的计算功能履行起来要快很多。Math对象还提供了辅助完成这些计算的属性。

E 返回算术常量 e,即自然对数的底数(约等于2.718)。

LN2 返回 2 的自然对数(约等于0.693)。

LN10 返回 10 的自然对数(约等于2.302)。

LOG2E 返回以 2 为底的 e 的对数(约等于 1.414)。

LOG10E 返回以 10 为底的 e 的对数(约等于0.434)。

PI 返回圆周率(约等于3.14159)。

SQRT1_2 返回返回 2 的平方根的倒数(约等于 0.707)。

SQRT2 返回 2 的平方根(约等于 1.414)。

Math对象包括的方法以下:

abs(x) 返回数的绝对值。

acos(x) 返回数的反余弦值。

asin(x) 返回数的反正弦值。

atan(x) 以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。

atan2(y,x) 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。

ceil(x) 对数进行上舍入。

cos(x) 返回数的余弦。

exp(x) 返回 e 的指数。

floor(x) 对数进行下舍入。

log(x) 返回数的自然对数(底为e)。

max(x,y) 返回 x 和 y 中的最高值。

min(x,y) 返回 x 和 y 中的最低值。

pow(x,y) 返回 x 的 y 次幂。

random() 返回 0 ~ 1 之间的随机数。

round(x) 把数4舍5入为最接近的整数。

sin(x) 返回数的正弦。

sqrt(x) 返回数的平方根。

tan(x) 返回角的正切。

toSource() 返回该对象的源代码。

valueOf() 返回 Math 对象的原始值。

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------

上一篇 VRP系统——5

下一篇 Hadoop get JobId

分享到:
------分隔线----------------------------
关闭
程序员人生