第5章 引用类型
在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起。它也被称为类,但这种称呼并不妥当。尽管从技术讲是一门面向对象的语言,但是她不具备传统的面向对象语言所支持的类和接口等基本结构。
对象时某个特定引用类型的实例。
新对象使用new操作符后更一个构造函数来创建。
构造函数本身就是一个函数,只不过该函数是出于创建新对象的目的而定义的。
5.1 Object类型
Object类型时ECMAScript中使用最多的一个类型,虽然不具备多少功能,但在应用程序中存储数和传输数据而言,它们确实是非常理想的选择。
创建Object实例的方法有两种:
1.使用new操作符后跟object函数
var person = new Object();
person.name ="Fred";
person.age = 20;
2.使用对象字面量表示法。
对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性对象的过程。
var person = {
name:"Fred",
age :20
};
一般来说访问对象属性时使用的都是点表示法。不过在JS中也可以使用方括号表示法来访问对象属性。在使用方括号语法时,应该将要访问的属性一字符串的形式放在方括号中。
方括号语法的主要优点是可以通过变量来访问属性。
通常,除非必须使用变量来访问属性,否则我们建议使用点表示法。
var propertyName = "name";
alert(person["propertyName"]); //Fred
5.2 Array类型
ECMAScript的数组类型与其他多数语言中的数组有着相当大的差别,
ECMAScript数组的每一项可以保存任何类型的数据,
也就是说数组的第一个位置来保存字符串,第二个位置可以来保存数值,第三个位置可以来保存对象。
ECMAScript数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容纳新数据
创建数组的方式有两种:
1.使用Array构造函数
var colors = new Array();
var names = new Array(3);
var colors = new Array("red","blue","green");
var names = new Array("Grey"); //创建一个包含1项,即字符串“Grey”的数组
2.使用数组字面量表示法
var colors = ["red","blue","green"]; //创建一个包含三个字符串的数组
var names =[ ]; //创建一个空数组
var values = [1,2,]; //不要这样,创建一个包含2或三项的数组
var options = [,,,,,]; //不要这样,创建一个包含5或6项的数组
在读取和设置数组的值时,要使用方括号并提供相应值的基于0的数字索引
var colors = ["red","blue","green"]; //定义一个字符串数组
alert(colors[0]); //显示第一项
colors[2] = "black"; //修改第三项
colors[3] = "brown"; //添加第四项
数组的项数保存在其length属性中,这个属性始终会返回0或更大的值。
length不是只读的,因此通过设置这个属性,可以从数组的末尾移除项或者向数组中添加新项。
var colors = ["red","blue","green"];
colors.length = 2;
alert(colors[2]); //undefined
var colors = ["red","blue","green"];
colors.length = 4;
alert(colors[3]); //undefined
利用length在末尾添加新项目
var colors = ["red","blue","green"];
colors[colors.length] = "black"; //在位置3添加
colors[colors.length] = "brown"; //在位置4添加
colors[99] = "white";
alter(colors.length); //100,位置5到99都是undefined
5.2.1 检测数组
对于一个网页或者一个全局作用域而言:
if(value instanceof Array){
//对数组执行某些操作
}
多个全局执行环境中,最终确定某个值到底是不是数字
if(Array.isArray(value)){
//对数组执行某些操作
}
5.2.2 转换方法
- toString
- valueOf
- toLocaleString
使用join()方法可以使用不同的分隔符来构建字符串
var colors = ["red","blue","green"];
alert(colors.join("||)); //red||green||blue
5.2.3 栈方法
栈是一种LIFO结构,后进先出,栈中项的插入和移除只发生在栈的顶部。
ECMAScript专门为数组提供了push()和pop()方法。
push()方法可以接受任意数量的参数,把他们逐个添加到数组末尾,并返回修改后的数组长度。
pop()方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。
var colors = new Array();
count = colors.push("red","blue");
alert(count); //2
count = colors.push("green")l
alert(count); //3
item = colors.pop();
alter(item); //"green"
alter(colors.length) //2
5.2.4 队列方法
队列数据结构的访问规则是FIFO
队列在列表的末端添加项,在列表的前端移除项
shift()能够移除数组中的第一个项,并返回该项,同时将数组长度减1
var colors = new Array();
var count = colors.push("red","green");
alter(count); //2
count = colors.push("black");
alter(count); //3
var item = colors.shift();
alter(item); //"red"
alter(colors.length); //2
unshift() 能在数组前端添加人一个项并返回新数组的长度。因此同时使用unshift()和pop()能够从相反方向来模拟队列
5.2.5 重排序方法
reverse()会翻转数组项的顺序
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
*5.2.6 操作方法
concat()基于当前数组中的所有项创建一个新数组
var colors = ["red","green","blue"];
var colors2 = color.concat("yellow",["black","brown"]);
alter(colors); //red,green,blue
alter(colors2); //red,green,blue,yellow,black,brown
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
splice() 最强大的数组方法,向数组的中部插入项
- 删除:可以删除任意数量的项,指定2个参数:要删除的第一项的位置和删除的项数 splice(0,2)会删除数组中的前两项
- 插入:可以向指定位置插入任意数量的项,只需3个参数:起始位置、0(要删除的项)和要插入的项。 splice(2,0,“red”,”green”)会从位置2插入字符串“red”和”green”
- 替换:可以向指定位置插入任意数量的项,同时删除任意数量的项,只需3个参数:起始位置、要删除的项数和要插入的项
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插入2项
alter(colors); //green,yellow,orange,blue
alter(removed); //空数组
removed = colors.splice(1,1,"red","purple");//从位置1插入2项
alter(colors); //green,red,purple,orange,blue
alter(removed); //yellow
5.2.7 位置方法
indexOf()
lastIndexOf()
这两个方法都接收两个参数:要查找的项和表示查找起点位置的索引。
indexOf的方法是从数组头开始向后查找
lastIndexOf的方法是从数组尾开始向前查找
这两个方法都要返回要查找的项在数组中的位置,或者在没找到的情况下返回-1
在比较时使用全等操作符
var numbers=[1,2,3,4,5,6];
alert(numbers.indexOf(4));//3
5.2.8 迭代方法
- every()对数组中的每一项运行给定函数,如果该函数对每一项都返回true则返回true
- filter()对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
- forEach()没返回值
- map()对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
- some()对数组中的每一项运行给定函数,如果该函数对某一项返回true,就会返回true。
5.2.9 归并方法
reduce()
var values = [1,2,3,4,5];
var sum = values.reduce(fuction(prev,cur,index,array){
return prev + cur;
});
alter(sum); //15
reduceRight()
var values = [1,2,3,4,5];
var sum = values.reduceRight(fuction(prev,cur,index,array){
return prev + cur;
});
alter(sum); //15
5.3 Date类型
创建日期对象:
var now = new Date();
Date.parse();//接收一个表示日期的字符串参数
var someDate = new Date(Date.parse("May 25,2004"));
var allFives = new Date(Date.UTC(2015,4,5,17,55,55));//GTM时间2015.5.5下午5.55.55
var start = Date.now();
doSomething();
var stop = Date.now();
result = stop - start;
5.3.1 继承的方法
5.3.2 日期格式化的方法
- toDateString()
- toTimeString()
- toLocaleDateString()
- toLocaleTimeString()
- toUTCString
5.3.3 日期时间组件方法
- get/setTime
- get/setFullYear(年)
- get/setMonth(月)
- get/setDate(日)
- get/setHours(时)
- get/setMinutes(分)
- get/setSeconds(秒)
- getDay(星期)
var d = new Date();
var week = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];
document.write(d.getFullYear()+"年");
document.write(d.getMonth()+"月");
document.write(d.getDate()+"日");
document.write(" "+week[d.getDay()]);
5.4 RegExp类型
ECMAScript通过RegExp类型来支持正则表达式。
var expression = /pattern / flags;
pattern部分可以是任何简单或复杂的正则表达式
每个正则都可以带一个或多个标志flag
正则表达式的匹配模式支持下列3个标志
- g:表示全局模式
- i:表示不区分大小写模式
- m:表示多行模式
与其他语言中的正则表达式类似,模式中使用的所有元字符都必须转义。元字符包括:([{\^$|)?*+.]}
5.4.1 RegExp实例属性
- global:布尔值,表示是否设置了g标志
- ignoreCase:布尔值,表示是否设置了i
- lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起
- multiline:布尔值,表示是否设置了m标志
- source:正则表示的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
5.4.2 RegExp实例方法
RegExp对象的主要方法是exec(),该方法是专门为捕获组而设计的。
exec()接收一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。
index表示匹配项在字符串中的位置
input表示应用正则表达式的字符串。
var text = "mom and dad and baby";
var pattern = /mom(and dad(and baby)?)?)/gi;
var matches = pattern.exec(text);
alert(matches.index); //0
alert(matches.input); //mom and dad and baby
alert(matches[0]); //mom and dad and baby
alert(matches[1]); //and dad and baby
alert(matches[2]); //and baby
在模式中设置了全局标志,每次返回一个匹配项,在同一个字符串上多次调用,都会在字符串中继续查找新的匹配项;若不在全局模式中则会始终返回第一个匹配项
var text = "cat, bat, sat, fat";
var pattern1 = /.at/;
var matches = pattern1.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern1.lastIndex); //0
matches = pattern1.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern1.lastIndex); //0
var pattern2 = /at./g;
var matches = pattern2.exec(text);
alert(matches.index); //0
alert(matches[0]); //cat
alert(pattern2.lastIndex); //3
matches = pattern2.exec(text);
alert(matches.index); //5
alert(matches[0]); //bat
alert(pattern1.lastIndex); //8
第二个方法是test();它接收一个字符串参数。在模式与该参数匹配的情况下返回true。
/*验证用户输入*/
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if(pattern.test(text)){
alert("The pattern was matched.");
}
5.4.3 RegExp构造函数属性
长属性名 | 短属性名 | 说明 |
---|---|---|
input | $_ | 最近一次要匹配的字符串 |
lastMatch | $& | 最近一次的匹配项 |
lastParen | $+ | 最近一次的捕获组 |
leftContext | $` | input字符串中lastMatch之前的文本 |
multiline | $* | 布尔值,表示是否所有表达式都使用多行模式 |
rightContext | $’ | Input字符串中lastMatch之后的文本 |
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if(pattern.test(text)){
alert(RegExp.input); //this has been a short summer
alert(RegExp.leftContext);//this has been a
alert(RegExp.rightContext);//summer
alert(RegExp.lastMatch);//short
alert(RegExp.lastParen);//s
alert(RegExp.multiline);//undefined
}
短属性名要用方括号来访问
5.4.4 模式的局限性
不支持的特性
- 匹配字符串开始和结尾的锚
- 向后查找
- 并集和交集类
- 原子组
- Unicode支持
- 命名的捕获组
- s和x匹配模式
- 条件匹配
- 正则表达式注释
5.5 Function类型
function sum (num1,num2){
return num1+num2;
}
var sum = function(num1,num2){
return num1+num2;
};
var sum = new Function("num1","num2","return num1 + num2");//不推荐
5.5.1 没有重载
声明两个同名函数,而结果则是后面的函数覆盖了前面的函数。
5.5.2 函数声明与函数表达式
解析器在向执行环境中加载数据时,对函数声明和 函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用;之余函数表达式,必须等到解析器执行到他所在的代码行,才会真正被解析。
//运行正常
alert(sum(10,10));
function sum(a,b){
return a+b;
}
//产生错误
alert(sum(10,10))
var sum = function(a,b){ //不是函数声明,函数只是位于一个初始化语句中
return a+b;
}
5.5.3 作为值的函数
函数作为参数值
function callSomeFunction(someFunction,someArgument){
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10,10)
alert(result1);
function getGreeting(name){
return "Hello " + name;
}
var result2 = callSomeFunction(getGreeting,"Fred");
alert(result2);
函数作为返回值
function creatComparisonFunction(propertyName){
return function (object1,object2) {
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1<value2){
return -1;
}
else if (value1>value2){
return 1;
}
else {
return 0;
}
}
}
var data = [{name:"Fred",age:28},{name:"Rose",age:20}];
data.sort(creatComparisonFunction("name"));
alert(data[0].name);
data.sort(creatComparisonFunction("age"));
alert(data[0].name);
5.5.4 函数内部属性
在函数内部,有两个特殊对象:arguments和this。
arguments用于保存函数参数,这个对象还有个名为callee的属性,是一个指针,指向拥有这个arguments对象的函数
function factorial(num){
if(num <= 1)
{
return 1;
}
else{
return num * arguments.callee(num-1);
//return num * factorial(num-1);
}
}
var truFactorial = factorial;
factorial = function()
{
return 0;
}
alert(trueFactorial(5)); //120
alert(factorial(5)); //0
如果使用注释的递归返回,alert(trueFactorial(5))则会显示为0。
函数内部的另一个特殊对象时this,其行为与java和c#中的this大致类似,
this引用的是函数据以执行的环境对象——或者也可以说是this值。
当在网页的全局作用域中调用函数时,this对象引用的就是window。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();
o.sayColor = sayColor;
o.sayColor();
caller属性保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为null。
function outer(){
inner();
}
function inner(){
//alert(inner.caller);
alert(arguments.callee.caller);
}
outer();
5.5.5 函数属性和方法
每个函数包含两个属性length和prototype。
length表示函数希望接受的命名参数个数
在创建自定义引用类型以及实现继承时,prototype属性的作用是极为重要的
每个函数都包含两个非继承而来的方法:apply和call
apply方法接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组
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));
alert(callSum2(10,10));
call方法与apply方法的作用相同,他们的区别仅在于接收参数的方式不同。call除第一个参数this以外的其他参数都是直接传递给函数。
事实上,传递函数并非apply和callde 真正用武之地。他们真正强大的地方是扩充函数赖以运行的作用域。
window.color ="red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();
sayColor.call(this);
sayColor.call(window);
sayColor.call(o); //blue
bind这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objetSayColor(); //blue
5.6 基本包装类型
使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型对象,则值存在于一行代码的执行瞬间,然后立即被销毁。
这意味着我们不能再运行时为基本类型添加属性和方法。
5.6.1 Boolean
建议永远不要使用boolean
5.6.2 Number类型
- toString()方法传递一个表示基数的参数
- toFixed()指定的小数位返回数值的字符串
- toExponential()用于格式化数值
5.6.3 String类型
1.字符方法
- charAt()以单字符字符串的形式返回给指定位置的那个字符
var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
- charCodeAt()以字符编码形式返回指定位置的那个字符
var stringValue = "hello world";
alert(stringValue.charCodeAt(1)); //"101"
2.字符串操作方法
- concat()
- slice()
- substring()
- substr()
3.字符串位置方法
- indexOf()从字符串的开头向后搜索子字符串
- lastIndexOf()从字符串的末尾向前搜索子字符串
var stringValue=" ... ";
var position = new Array();
var pos = stringValue.indexOf("");
while(pos > -1){
position.push(pos);
pos = stringValue.indexOf("",pos+1);
}
alert();
4.trim()
这个方法会创建一个字符串副本,删除前置及后缀的所有空格,返回结果。
5.字符串大小写
- toLowerCase
- toLocaleLowerCase
- toUpperCase
- toLocaleUppercase
6.字符串的模式匹配方法
match()方法只接受一个参数,要么是一个正则表达式,要么是一个RegExp对象
search()返回字符串中第一个匹配项的索引,无匹配项返回-1
replace()接收两个参数,一个可以是RegExp对象或者一个字符串,第二个参数是一个字符串或者一个函数,
var text = "cat,bat,sat,fat";
var result = text.replace("at","ond");
alert(result); //"cond,bat,sat,fat"
var result = text.replace(/at/g,"ond");
alert(result);//"cond,bond,sond,fond"
split(,)
7.localeCompare()比较两个字符串
如果字符串在字母表中排在字符串参数前返回-1
等于字符串 参数返回0
在字符串参数之后返回1
8.fromCharCode()
接收字符串编码,把他们转换成一个字符串
5.7 单体内置对象
Global
Math
.max
.min
.ceil
.floor
.round
.random