[JavaScript] 引用类型

1. 原生引用类型


1.1 引用类型和类

引用类型是一种数据结构,用于将数据和功能组织在一起,也常称做类。ECMAScript从技术上说是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构。


1.2 Object类型

大多数引用类型的值都是Object类型的实例,创建object实例的方式有两种,第一种是使用new操作符,例如:

var myobj = new Object();

另一种方式是使用对象字面量表示法,例如:

var myobj  = {
  name : "obj",
  weight : 20
};

如果留空其花括号,则可以定义只包含默认属性和方法的对象,例如:

var myobj = {};

一般来说,访问对象属性时使用的都是点表示法,也可以使用方括号一肤浅法来访问对象的属性,例如:

var myobj = {
  name = "obj"
}
alert(myobj["name"]);


1.3 Array类型

ECMAScript数组的每一项可以保存任何类型的数据,而且,数组的大小是可以动态调整的,即随着数据的添加自动增长以容纳新增数据。创建数组有两种形式,第一种是使用Array构造函数,例如:

var myarray = new Array();

也可以给Array构造函数传递数组要保存的项目数量,例如:

var myarray = new Array(20);

也可以向Array构造函数传递数组中应该包含的项,例如:

var myarray = new Array("a", "b", "c");

使用Array构造函数时也可以省略new操作符,第二种创建数组的方式是使用数组字面量表示法,例如:

var myarray = ["a", "b", "c"];

在读取数组的值时,要使用方括号并提供相应值的基于0的数字索引,例如:

alert(myarray[0]);

数组的项数保存在其length属性中,例如:

alert(myarray.length);

这个属性不是只读的,可以通过设置这个属性,从数组的末尾移除项或向数组中添加新项。


1.4 Array方法

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

ECMAScript数组也提供了一种让数组行为类似于其他数据结构的方法:push()和pop()。push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度,而pop()方法则从数组末尾移除最后一项,然后返回移除的项,例如:

myarray.push("d");
myarray.pop();

此外,ECMAScript数组还提供了类似队列行为的方法:shift()和unshift()。shift()能够移除数组中的第一个项并返回该项,而unshift()相反,它能在数组前端添加任意个项并返回数组的长度,例如:

myarray.shift();
myarray.unshift("A", "B");

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

myarray.reverse();
myarray.sort();

最后,ECMAScript为操作已经包含在数组中的项提供了很多方法。其中,concat()方法也可基于当前数组中的所有项创建一个新数组,在没有传递参数的情况下,它只是复制当前数组并返回副本,如果传递给concat()方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中,如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。

slice()方法能够基于当前数组中的一或多个项创建一个新数组,它可以接受一或两个参数,即要返回项的起始和结束位置,只有一个参数的情况下,slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。

splice()方法的主要用途是向数组的中部插入项,它有很多种用法,如果提供两个参数(要删除的第一项的位置和要删除的项数),则会删除数组中的项,如果提供三个参数(起始位置,要删除项数,要插入的项),则可以实现在数组中插入元素。


1.5 Date类型

Date类型使用自UTC1970年1月1日午夜开始经过的毫秒数来保存日期,在使用这种存储格式的条件下,Date类型保存的日期能够精确到1970年1月1日之前或之后的285616年。

创建一个日期对象,使用new操作符和Date构造函数即可,例如:

var now = new Date();

在不传递参数的情况下,新创建的对象自动获得当前日期和时间,如果想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数。为了简化这一过程,ECMAScript提供了两个方法:Date.parse()和Date.UTC()。

Date.parse()方法接收一个表示日期的字符串参数,尝试根据这个字符串返回相应日期的毫秒数,如果传入Date.parse()方法的字符串不能表示日期,那么它会返回NaN,例如:

var mydate = new Date(Date.parse("May 01, 2000"));

Date.UTC()方法同样也返回表示日期的毫秒数,但它与Date.parse()在构建值时使用不同的信息。Date.UTC()的参数分别是年份、基于0的月份(一月是0)、月中的哪一天(1到31)、小时数(0到23)、分钟、秒以及毫秒数,只有前两个参数是必须的,如果省略其他参数,则一律设为0,例如:

var mydate = new Date(Date.UTC(2000, 1, 1, 8, 10, 10));


1.6 Date方法

Date类型也重写了toLocaleString()、toString()和valueOf()方法,但这些方法返回的值与其他类型中的方法不同。toLocaleString()方法会按照与浏览器设置的地区相适应的格式返回日期和时间。而toString()方法则通常返回带有时区信息的日期和时间。valueOf()方法根本不返回字符串,而是返回日期的毫秒表示。

Date类型还有一些用于将日期格式化为字符串的方法。

1) toDateString: 以特定于实现的格式显示星期几、月、日和年。

2) toTimeString: 以特定于实现的格式显示时、分、秒和时区。

3) toLocaleDateString: 以特定于地区的格式显示星期几、月、日和年。

4) toLocaleTimeString: 以特定于地区的格式显示时、分、秒。

5) toUTCString(): 以特定于实现的格式完整的UTC日期。

此外,还有一些Date类型的方法,都是直接取得和设置日期中特定部分的方法,UTC日期指的是在没有时区偏差的情况下的日期值。

日期时间组件方法
方法
说明
getTime()返回表示日期的毫秒数。
setTime()以毫秒数设置日期。
getFullYear()取得4位数年份。
getUTCFullYear()取得UTC日期的4位数年份。
setFullYear()以4位数字设置年份。
setUTCFullYear()以4位数字设置UTC日期的年份。
getMonth()取得月份(0表示1月)。
getUTCMonth()取得UTC日期月份(0表示1月)。
setMonth()设置月份,超过11则增加年份。
setUTCMonth()设置UTC日期月份,超过11则增加年份。
getDate()取得天数(1到31)。
getUTCDate()取得UTC日期天数(1到31)。
setDate()设置天数,超过该月中应有的天数,则增加月份。
setUTCDate()设置UTC日期天数,超过该月中应有的天数,则增加月份。
getDay()取得星期中的星期几。
getUTCDay()取得UTC日期星期中的星期几。
getHours()取得小时数(0到23)。
getUTCHours()取得UTC日期小时数(0到23)。
setHours()设置小时数,超过23则增加天数。
setUTCHours()设置UTC日期小时数,超过23则增加天数。
getMinutes()取得分钟数(0到59)。
getUTCMinutes()取得UTC日期分钟数(0到59)。
setMinutes()设置分钟数,超过59则增加小时数。
setUTCMinutes()设置UTC日期分钟数,超过59则增加小时数。
getSeconds()取得秒数(0到59)。
getUTCSeconds()取得UTC日期秒数(0到59)。
setSeconds()设置秒数,超过59则增加分钟数。
setUTCSeconds()设置UTC日期秒数,超过59则增加分钟数。
getMilliseconds()取得毫秒数。
getUTCMilliseconds()取得UTC日期毫秒数。
setMilliseconds()设置毫秒数。
setUTCMilliseconds()设置UTC日期毫秒数。
getTimezoneOffset()返回本地时间与UTC时间相差的分钟数。


1.7 RegExp类型

ECMAScript通过RegExp类型来支持正则表达式,语法如下:

var expression = /pattern/ flags;

其中模式(pattern)部分是正则表达式,每个正则表达式都可带有一或多个标志(flag)。正则表达式的匹配模式支持以下3个标志:

1) g: 表示全局模式,即模式将被用于所有字符串,而非在发现第一个匹配项时停止。

2) i: 表示不区分大小写模式。

3) m: 表示多行模式,即在到达一行文本末尾时还会继续查找下一行。

RegExp的每个实例具有以下属性:

1) global: 布尔值,表示是否设置了g标志。

2) ignoreCase: 布尔值,表示是否设置了i标志。

3) lastIndex: 整数,表示开始搜索下一个匹配项的字符位置,从0开始。

4) multiline: 布尔值,表示是否设置了m标志。

5) source: 正则表达式的字符中表示。

ECMAScript中的正则表达式仍然缺少某些语言支持的高级正则表达式特性,如下:

1) 匹配字符串开始和结尾的\A和\Z锚。

2) 向后查找。

3) 并集和交集类。

4) 原子组。

5) Unicode支持(单个字符除外)。

6) 命名的捕获组。

7) s和x匹配模式。

8) 条件匹配。

9) 正则表达式注释。


1.8 RegExp方法

RegExp对象的主要方法是exec(),它接受一个参数,即要应用模式的应符串,然后返回包含第一个匹配项信息的数组,没有匹配项的情况下返回null。返回的数组是Array()的实例,但包含两个额外属性index和input,index表示匹配项在字符串中的位置,input表示应用正则表达式的字符串,例如:

var input = "this is a test";
var pattern = /test/gi;
var matches = pattern.exec(text);
alert(matches.index);
alert(matches.input);
alert(matches[0]);

对于exec()方法,即使设置了模式g,每次也只返回一个匹配项,但每次调用都会在字符串中继续查找新匹配项。

另一个方法是test(),它接受一个字符串参数,在模式与参数匹配的情况下返回true,否则返回false,例如:

var input = "this is a test";
var pattern = /test/gi;
alert(pattern.test());

RegExp继承的toLocaleString()和toString()方法都会返回正则表达式的字面量。


1.9 RegExp属性

RegExp构造函数包含一些属性,这些属性可以通过两种方式访问它们,一个长属性名,一个短属性名(Opera不支持短属性名)。

RegExp构造函数属性
长属性名
短属性名说明
Input$_最近一次要匹配的字符串(Opera不支持)。
lastMath$&最近一次的匹配项(Opera不支持)。
lastParen$+最近一次匹配的捕获组(Opera不支持)。
lastContext$`input字符串中lastMatch之前的文本。
multiline$*是否所有表达式都使用多行模式(IE和Opera不支持)。
rightContext$'input字符串中lastMatch之后的文本。


1.10 Function类型

函数实际上是对象,每个函数都是Function对象的实例,而且都与其他引用类型一样具有属性和方法。函数名实际上也是一个指向函数的指针,不会与某个函数绑定。函数通常使用函数声明语法定义,例如:

function myfunc(myvar) {
  return myvar;
}

也可以使用如下方式 :

var myfunc = function(myvar) {return myvar;};

第二种方式是使用Function构造函数,它可以接收任意数量的参数,但最后一个参数始终都被看成是函数体,例如:

var myfunc = new Function("myvar", "return myvar;");

但是不推荐使用这种方式,因为这种语法会导致解析两次代码,从而影响性能,但这种语法有助于理解函数是对象的概念。

如果声明两个同名函数,结果就是后面的函数覆盖了前面的函数,因为函数名相当于指针。

解析器在执行环境中加载数据时,会率先读取函数声明,并使其在执行任何代码前可用,但函数表达式则必须等到解析器执行到它所在的代码行,才会被真正解析执行,例如:

alert(myfunc1(1)); //正确
function myfunc1(myvar) {
  return myvar;
}
alert(myfunc2(1)); //错误
var myfunc2 = function(myvar) {
  return myvar;
}

因为ECMAScript中函数名本身就是变量,所以函数也可以作为值来使用,比如可以将一个函数作为另一个函数的结果返回,例如:

function myfunc() {
  return function() {
    return 1;
  }
}


1.11 Function方法

每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数。

apply()方法接受两个参数,一个是在其中运行函数的作用域,另一个是参数数组,第二个参数可以是Array的实例,也可以是arguments对象,例如:

function myfunc1() {
}
function myfunc2() {
  return myfunc1.apply(this, arguments);
}

call()方法与apply()方法的作用相同,只是在于接收参数的方式不同,对于call()方法而言,第一个参数是作用域,其余参数都是直接传递给函数的,例如:

function myfunc1() {
}
function myfunc2(myvar) {
  return myfunc1.call(this, myvar);
}


1.12 Function属性

ECMAScript中的函数是对象,所有也有属性和方法,每个函数都包含两个属性:length和prototype。其中length属性表示函数希望接收的命名参数的个数。

对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在,例如toString()和valueOf()等方法实际都保存在prototype名下,只不是通过各自对象的实例访问,在创建自定义引用类型及实现继承时,prototype属性极为重要。

在函数内部,有两个特殊的对象:arguments和this.arguments包含传入函数中的所有参数,这个对象还有一个callee属性,该属性是一个指针,指向拥有这个agruments对象的函数。this与Java和C#中的this大致类似,引用的是函数据以执行操作的对象,或者说this是函数在执行时所处的作用域。


2. 基本包装类型


2.1 Boolean类型

Boolean类型是与布尔值对应的引用类型,要创建Boolean对象,可以调用Boolean构造函数,并传入true或false值,例如:

var booleanObject = new Boolean(false);

Boolean类型重写了valueOf()方法,返回基本类型值true或false。重写了toString()方法,返回字符串"true"或"false"。但是Boolean类型容易引用误解,例如:

var falseObject = new Boolean(false);
alert(falseObject && true); //true

示例中的代码是对falseObject而不是对它的值求值,布尔表达式中的所有对象都会被转换成true,因此示例的结果是true。


2.2 Number类型

Number是与数字值对应的引用类型,要创建Number对象,可以调用Number构造函数并传入相应的数值,例如:

var numberObject = new Number(1);

Number类型重写了valueOf()方法,返回对象表示的基本类型数值。重写了toLocaleString()和toString(),返回字符串形式的数值。

除了继承的方法外,Number类型还提供了一些用于将数值格式化的方法。toFixed()方法按照指定的小数返回数值的字符串表示,例如:

var num = 1;
alert(num.toFixed(2));

如果数值本身包含的小数位比指定的还多,那么接近指定的最大小数位的值就会舍入,例如:

var num = 1.005;
alert(num.toFixed(2));

toExponential()方法返回以指数表示法表示的数值的字符串形式,它接收一个参数,指定输出结果中的小数位数,例如:

var num = 1;
alert(num.toExponential(1));


2.3 String类型

String类型是字符串的对象包装类型,可以使用String构造函数来创建,例如:

var stringObject = new String("Hello World!");

String对象继承的valueOf()、toLocaleString和toString()方法都返回对象所表示的基本字符串值。

String对象都有length属性,表示字符串中包含多个字符,例如:

var mystr = "Hello World!";
alert(mystr.length);


2.4 String方法

两个用于访问字符串中特定字符的方法是:charAt()和charCodeAt()。这两个方法都接收一个参数,即基于0的字符位置。charAt()方法以单字符字符串的形式返回给定位置的那个字符,而charCodeAt()方法返回的不是字符而是字符编码,例如:

var mystr = "Hello World!";
alert(mystr.charAt(1));
alert(mystr.charCodeAt(1));

String构造函数本身有一个静态方法:fromCharCode(),这个方法是接收一个或多个字符编码,然后将它们转换成一个字符串,与charCodeAt()执行的是相反的操作,例如:

alert(String.fromCharCode(104, 101, 108, 108, 111));

还有几个与操作字符串有关的方法,第一个是concat(),用于将一或多个字符串拼接起来,返回拼接得到的新字符串,例如:

var mystr = "Hello";
alert(mystr.concat(" World!"));

虽然concat()是专门用来拼接字符串的方法,但是使用更多的是加号操作符,在大多数情况下,加号操作符比concat()方法简便。

另外三个是基于子字符串创建新字符串的方法:slice()、substr()和substring()。这三个方法都返回被操作字符串的一个子字符串,都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数表示子字符串到哪里结束。slice()和substring()的第二个参数指定的是子字符串最后一个字符后面的位置,而substr()的第二个参数指定的则是返回的字符个数。如果没有指定第二个参数,则将字符串的长度作为结束位置,例如:

var mystr = "Hello World!";
alert(mystr.slice(3, 6));
alert(mystr.substr(3, 6));
alert(mystr.substring(3, 6));

有两个可以从字符串中查找子符串的方法:indexOf()和lastIndexOf()。这两个方法都是从一个字符串搜索给定的子字符串,返回子字符串的位置,如果没有找到,则返回-1。但indexOf()方法从字符串开头向后搜索,而lastIndexOf()方法是从字符串的末尾向前搜索,例如:

var mystr = "Hello World!";
alert(mystr.indexOf("o"));
alert(mystr.lastIndexOf("o"));

ECMAScript中涉及字符串大小写转换的方法有4个:toLowerCase()、toLocaleLowerCase()、toUpperCase()和toLocaleUpperCase()。toLowerCase()和toUpperCase()方法分别指字符串转换为小写和大写,而toLocaleLowerCase()和toLocaleUpperCase()方法则是针对特定地区的实现,例如:

var mystr = "Hello World";
alert(mystr.toLowerCase());
alert(mystr.toUpperCase());
alert(mystr.toLocaleLowerCase());
alert(mystr.toLocaleUpperCase());

与操作字符串有关的最后一个方法是localeCompare(),这个方法比较两个字符串,并返回下列值中的一个:

1) 如果字符串在字母表中的顺序在参数之前,则返回一个负数。

2) 如果字符串等于参数,则返回0.

3) 如果字符串在字母表中的顺序在参数之后,则返回一个正数。


2.5 String的模式匹配

String类型定义了几个用于在字符串中匹配模式的方法。第一个方法是match(),在字符串上调用这个方法,本质上与调用RegExp的exec()方法相同,例如:

var input = "this is a test";
var pattern = /is/;
var matches = input.match(pattern);

另一个用于查找模式的方法是search(),这个方法的唯一参数也是一个正则表达式。search()方法返回字符串中第一个匹配项的索引,如果没有找到匹配项,则返回-1,例如:

var input = "this is a test";
var pos = input.search(/is/);
alert(pos);

ECMAScript还提供了用于替换子字符串的replace()方法,这个方法接收两个参数:正则表达式和一个字符串或函数。如果第一个参数是字符串,那么只会替换第一个子字符串,要替换所有子字符串,要提供正则表达式并指定全局标志,例如:

var input = "this is a test";
alert(input.replace(/s/g, "a"));

如果第二个参数是字符串,那么还可以使用特殊字符序列,将正则表达式操作得到的值插入到结果字符串中,例如:

var input = "this is a test";
alert(input.replace(/(s)/g), "result: ($1)");
特殊字符序列
字符序列
替换文本
$$$
$&匹配整个模式的子字符串。
$'匹配的子字符串之前的子字符串。
$`匹配的子字符串之后的子字符串。
$n匹配第n个捕获组的子字符串。
$nn匹配第nn个捕获组的子字符串。

最后一个与模式匹配有关的方法是split(),这个方法可以基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符可以是字符串,也可以是正则表达式,split()方法接受可选的第二个参数,用于指定数组的大小,例如:

var mystr = "a, b, c, d";
var myarray = mystr.split(",");


3. 内置对象


3.1 Global对象

所有在全局作用域中定义的属性和函数,都是Global对象的属性,例如isNan()、isFinite()、parseInt()和parseFloat(),换句话说,不属于任何其他对象的属性和方法,最终都是Global对象的属性和方法。

Global对象的encodeURI()和encodeURIComponent()方法可以对URI进行编码,encodeURI()主要用于整个URI,而encodeURIComponent()主要用于对URI中的某一段进行编码。主要区别在于,encodeURI()不会地本身属于URI的特殊字符进行编码,而encodeURIComponent()会地它发现的任何非标准字符进行编码,例如:

var uri = "http://www.test.com/";
alert(encodeURI(uri));
alert(encodeURIComponent(uri));

与encodeURI()和encodeURIComponent()方法对应的两个方法分别是decodeURI()和decodeURIComponent()。

另一个方法,也是ECMAScript中最强大的方法:eval()。eval()方法像是一个ECMAScript解析器,它接受一个参数,即要执行的ECMAScript字符串,例如:

eval("alert('Hello World!')");

通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,被执行的代码具有与该执行环境相同的作用域链。

Global对象还包含一些属性,例如undefined、NaN和Infinity。此外,所有原生引用类型的构造函数,也是Global对象的属性。

Global对象属性
属性
说明
undefined特殊值undefined
NaN特殊值NaN
Infinity特殊值Infinity
Object构造函数Object
Array构造函数Array
Function构造函数Function
Boolean构造函数Boolean
String构造函数String
Number构造函数Number
Date构造函数Date
RegExp构造函数RegExp
Error构造函数Error
EvalError构造函数EvalError
RangeError构造函数RangeError
ReferenceError构造函数ReferenceError
SyntaxError构造函数SyntaxError
TypeError构造函数TypeError
URIError构造函数URIError


3.2 window对象

ECMAScript没有指出如何直接访问Global对象,但WEB浏览器都是将它作为window对象的一部分加以实现的,例如:

var mystr = "Hello World!";
alert(window.mystr);


3.3 Math对象

ECMAScript为保存数学公式提供了一个Math对象。

Math对象的属性大都是数学计算中可能会用到的一些特殊值。

Math对象属性
属性
说明
Math.E自然对数底数E的值
Math.LN1010的自然对数
Math.LN22的自然对数
Math.LOG2E以2为底e的对数
Math.LOG10E以10为底e的对数
Math.PIπ的值
Math.SQRT1_21/2的平方根
Math.SQRT22的平方根

Math对象还包含许多方法,用于完成简单的数学计算。其中,min()和max()方法用于确定一组数值中的最小值和最大值,例如:

var max = Math.max(1, 2, 3, 4);
var min = Math.min(1, 2, 3, 4);

还有几个用于舍入的方法:Math.ceil()、Math.floor()和Math.round()。Math.ceil()执行向上舍入,Math.floor()执行向下舍入,Math.round()执行标准舍入,例如:

alert(Math.ceil(25.5));
alert(Math.floor(25.5));
alert(Math.round(25.5));

Math.random()方法返回介于0和1之间一个随机数,不包括0和1,例如:

var num = Math.random();

Math对象还包含其他一些计算方法 ,不一一列举。

Math对象方法
方法
说明
Math.abs(num)返回num的绝对值。
Math.exp(num)返回Math.E的num次幕。
Math.log(num)返回num的自然对数。
Math.pow(num, power)返回num的power次幂。
Math.sqrt(num)返回num的平方根。
Math.acos(x)返回x的反余弦值。
Math.asin(x)返回x的反正弦值。
Math.atan(x)返回x的反正切值。
Math.atan2(y, x)返回y/x的反正切值。
Math.cos(x)返回x的余弦值。
Math.sin(x)返回x的正弦值。
Math.tan(x)返回x的正切值



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章