您的位置:首页 > 其它

第五章 引用类型

2015-08-11 14:30 363 查看
引用类型是一种数据结构,用于将数据和功能组织在一起。

Object类型
访问对象可以使用点和中括号方法,从功能来看这两种方法没有区别,但方括号可以通过变量来访问属性,如:
var propertyName="name"; alert(person[propertyName]);或者属性名中包含会导致错误的字符如:person["first name"]
在使用对象字面量定义对象时,实际上不会调用Object的构造函数。使用数组字面量时也不会调用Array构造函数。

Array类型
ECMAScript数组中的每一项可以保存任何类型的数据。
数组的长度保存在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
var colors = ["red","blue","green"]; colors[99]="black"; alert(colors.length); //100 其他的值都是undefined

Array.isArray(value)判断是不是数组。
toString()、valueOf()方法调用每一项的toString()方法,toLocaleString()调用的是每一项的toLocaleString()方法。
join()方法默认使用,作为分隔符。
如果数组中的某一项的值是null或undefined,那么该值在join()、toLocaleString()、toString()、valueOf()方法返回的结果中以空字符串表示。

栈方法push()添加到数组末尾,返回修改后数组的长度。pop()从数组末尾移除最后一项,返回移除的项。
队列方法push()添加到数组末尾,返回修改后数组的长度。shift()从数组移除第一项,返回移除的项。
unshift()在数组前端添加任意项并返回新数组的长度。

重排序的方法
reverse()反转数组项的顺序
sort()默认会按升序排列数组项,调用的是每一项的toString()方法,比较字符串,即使每一项是数值,也比较的是字符串;

function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}

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


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()基于当前数组中的一或多个项创建一个新数组(参数可以为负)

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()

var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1); //remove the first item
alert(colors); //green,blue
alert(removed); //red - one item array

removed = colors.splice(1, 0, "yellow", "orange"); //insert two items at position 1
alert(colors); //green,yellow,orange,blue
alert(removed); //empty array

removed = colors.splice(1, 1, "red", "purple"); //insert two values, remove one
alert(colors); //green,red,purple,orange,blue
alert(removed); //yellow - one item array


位置方法indexOf()和lastIndexOf(),这两个方法返回要查找的项在数组中的位置,没找到返回-1.比较时采用的===操作符。

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

var person = { name: "Nicholas" };
var people = [{ name: "Nicholas" }];
var morePeople = [person];

alert(people.indexOf(person)); //-1
alert(morePeople.indexOf(person)); //0


迭代方法

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

every():对数组中每一项运行给定函数,每一项返回true则返回true。

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

forEach():对数组中每一项运行给定函数,没有返回值。

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

some():对数组中每一项运行给定函数,如果该函数对任一项返回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); //true

var numbers = [1,2,3,4,5,4,3,2,1];

var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});

alert(filterResult); //[3,4,5,4,3]

var numbers = [1,2,3,4,5,4,3,2,1];

var mapResult = numbers.map(function(item, index, array){
return item * 2;
});

alert(mapResult); //[2,4,6,8,10,8,6,4,2]


归并方法

reduce()从数组第一项开始,逐个遍历到最后。reduceRight()从数组的最后一项开始,向前遍历到第一项。接收4个参数:前一个值,当前值、项的索引和数组的对象。

var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum);//15


Date类型

var now = new Date() //当前日期和时间 Thu Feb 05 2015 14:32:03 GMT+0800 (中国标准时间)
var someDate = new Date(Date.parse("May 25,2004")); //Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
//January 1, 2000 at midnight

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

//May 5, 2005 at 5:55:55 PM GMT
var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
alert(allFives.toUTCString());

Date.now() 表示调用这个方法时的日期和时间 使用+,var start = +new Date();把Date对象转换成字符串,可以达到同样的目的。

Date类型的valueOf()方法,不返回字符串,而是返回日期的毫秒表示,可以用> <比较日期。
更多方法P.102

RegExp类型
正则表达式的匹配模式支持下列3个标志:

g:表示全局模式,模式江北应用于所有字符串。

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

m:表示多行模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

ECMAScript5规定,使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次都创建新的RegExp实例。

方法有两个pattern.exec(text)返回数组,但包括2个额外属性:index——匹配项在字符串的位置,input——应用正则表达式的字符串。 pattern.test(text)返回true或false

RegExp构造函数的属性P.107

Function类型
函数实际上是对象。每个函数都是Function类型的实例,而且与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

函数声明和函数表达式基本一样,唯一的区别是,在函数声明之前调用函数可以,但是在函数表达式之前调用会出错。解析器会率先读取函数声明,并使其在执行任何代码之前可用,至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

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

可以从一个函数中返回另一个函数

function createComparisonFunction(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: "Zachary", age: 28}, {name: "Nicholas", age: 29},{name: "Donghao",age: 23}];

data.sort(createComparisonFunction("name"));
alert(data[0].name); //Nicholas

data.sort(createComparisonFunction("age"));
alert(data[0].name); //Zachary


函数内部属性

函数内部,有两个特殊的对象:arguments和this。
arguments主要是保存参数,但这个对象还有一个名叫callee的属性,这个属性是一个指针,指向拥有这个arguments对象的函数。
递归函数时使用arguments.callee(num-1)。
this引用的是患上据以执行的环境对象
牢记函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的saycolor()与o.saycolor()指向的仍然是同一个函数。
还有一个函数对象的属性:caller 保存着调用当前函数的函数的引用。
直接用函数名调用inner.caller,为了实现更松散的耦合,通过arguments.callee.caller访问。

严格模式下访问argumens.callee和arguments.caller会导致错误,非严格模式下arguments.caller始终是undefined;严格模式下不能够为caller赋值,否则会导致错误。

函数包含2个属性:length和prototype,length表示函数希望接收的命名参数的个数。
对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在,toString()和valueOf()等方法实际上都保存在prototype下,prototype是不可枚举的,因此使用for-in无法发现。

每个函数都包括两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定作用域中调用函数,实际上等于设置函数体内的this对象的值。区别仅仅在接收参数的方式不同。

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

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

function callSum(num1, num2){
return sum.call(this, num1, num2);
}

alert(callSum(10,10)); //20


它们真正强大的地方是能够扩充函数赖以运行的作用域。

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


bind()方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值

window.color = "red";
var o = { color: "blue" };

function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue


每个函数继承的toLocalString()和toString()方法始终都返回函数的代码。valueOf()方法同样也只返回函数代码。

基本包装类型
ECMAScript提供了3个特殊的引用类型:Boolean、Numbe、String。这些类型与其他引用类型相似,但同时也具有与各自的基本类型相应的特殊行为。实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而能够调用一些方法来操作这些数据。

var s1 = "some text";
var s2 = s1.substring(2);
基本类型值不是对象,不应该有方法。其实,在第二行代码访问s1时,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值。在读取模式中访问字符串时,后台都会自动完成下列处理:

创建String类型的一个实例;

在实例上调用指定的方法;

销毁这个实例。

可以看做是执行了下列代码。

var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
同样适用于Boolean和Number类型对应的布尔值和数字值。
引用类型和基本包装类型的主要区别就是对象的生存期。适用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不恩能够在运行时为基本类型值添加属性和方法。

var s1 = "some text";
s1.color = "red";
alert(s1.color);//undefined
原因是在第二行创建的String对象在执行第三行代码时已经被销毁了。第三行又创建自己的String对象,而该对象没有color属性。
对基本包装类型的实例调用typeof会返回"object",而且所有基本包装类型的对象都会被转换为布尔值true。

var obj = new Object("some text");
alert(obj instanceof String)//true
把字符串传给Object构造函数,会创建String的实例;同理传入数值和布尔值也会得到相应的实例

使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不一样的

var value = "25";
var number = Number(value); //转型函数
alert(typeof number);//"number"

var obj = new Number(value);//构造函数
alert(typeof obj);//"object"


Boolean类型

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

var falseValue = false;
result = falseValue && true;
alert(result); //false

alert(typeof falseObject); //object
alert(typeof falseValue); //boolean
alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean); //false


布尔表达式中的所有对象都会转为true,可能会导致错误。

建议永远不使用Boolean对象。

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

//toString() using a radix传递一个表示基数的参数
alert(numberObject.toString()); //"10"
alert(numberObject.toString(2)); //"1010"
alert(numberObject.toString(8)); //"12"
alert(numberObject.toString(10)); //"10"
alert(numberObject.toString(16)); //"a"

//toFixed()会按照指定的小数位返回数值的字符串表示,可以自动舍入,参数为小数点后面的位数
alert(numberObject.toFixed(2)); //outputs "10.00"

//toExponential()返回以指数表示法表示的数值的字符串形式
var num = 10;
alert(num.toExponential(1));//"1.0e+1" 小数点后面一位

//参数表示所有数字的位数
numberObject = new Number(99);
alert(numberObject.toPrecision(1)); //"1e+2"
alert(numberObject.toPrecision(2)); //"99"
alert(numberObject.toPrecision(3)); //"99.0"

alert(typeof numberObject); //object
alert(typeof numberValue); //number
alert(numberObject instanceof Number); //true
alert(numberValue instanceof Number); //false


String类型
字符方法
charAt()和charCodeAt()

var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
alert(stringValue.charCodeAt(1));//"101"
stringValue[1]; //"e"


字符串操作方法
concat() 拼接字符串,可以有多个参数。但是主要使用“+”操作符。

var stringValue = "hello world";
alert(stringValue.slice(3)); //"lo world"
alert(stringValue.substring(3)); //"lo world"
alert(stringValue.substr(3)); //"lo world"
alert(stringValue.slice(3, 7)); //"lo w"
alert(stringValue.substring(3,7)); //"lo w"
alert(stringValue.substr(3, 7)); //"lo worl" 第二个参数是长度

alert(stringValue.slice(-3)); //"rld"
alert(stringValue.substring(-3)); //"hello world"
alert(stringValue.substr(-3)); //"rld"
alert(stringValue.slice(3, -4)); //"lo w"
alert(stringValue.substring(3, -4)); //"hel"
alert(stringValue.substr(3, -4)); //"" (empty string)


参数为负,slice()会将传入的负值与字符串的长度相加,substr()将负的第一个参数加上字符串的长度,负的第二个参数转换为0,substring()方法会把所有的负值参数转换为0。

字符串位置方法
indexOf()和lastIndexOf()搜索给定的子字符串,返回子字符串的位置(没有找到该子字符串,则返回-1),还有第二个参数,给定起始的查找位置。

var stringValue = "hello world";
alert(stringValue.indexOf("o")); //4
alert(stringValue.lastIndexOf("o")); //7
alert(stringValue.indexOf("o", 6)); //7
alert(stringValue.lastIndexOf("o", 6)); //4


trim()方法 去掉前面和后面的空格

字符串大小写转换方法 toLowerCase()、toUpperCase()、toLocaleLowerCase()、toLocaleUpperCase()后两个是对少数语言使用。
字符串模式匹配方法
match()、search(),匹配正则表达式

var text = "cat, bat, sat, fat";
var pattern = /.at/;

var matches = text.match(pattern);
alert(matches.index); //0
alert(matches[0]); //"cat"
alert(pattern.lastIndex); //0

var pos = text.search(/at/);
alert(pos); //1

var result = text.replace("at", "ond");
alert(result); //"cond, bat, sat, fat"

result = text.replace(/at/g, "ond");
alert(result); //"cond, bond, sond, fond"

result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)

function htmlEscape(text){
return text.replace(/[<>"&]/g, function(match, pos, originalText){
switch(match){
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """;
}
});
}

alert(htmlEscape("<p class=\"greeting\">Hello world!</p>")); //<p class="greeting">Hello world!</p>

var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"]
var colors2 = colorText.split(",", 2); //["red", "blue"]
var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""]


localCompare()方法

var stringValue = "yellow";
alert(stringValue.localeCompare("brick")); //1
alert(stringValue.localeCompare("yellow")); //0
alert(stringValue.localeCompare("zoo")); //-1
fromCharCode()方法,把多个字符编码,转换成字符串
alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"


单体内置对象

内置对象——由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。也就是多,开发人员不必显式的实例化内置对象,因为它们已经实例化了。Object、Array、String是内置对象,Global和Math是单体内置对象。

Global对象,不属于任何其他对象的属性和方法,最终都是它的方法。
encodeURI()替换空格,encodeURIComponent()替换所有非字母数字

var uri = "http://www.wrox.com/illegal value.htm#start";

//"http://www.wrox.com/illegal%20value.htm#start"
alert(encodeURI(uri));

//"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
alert(encodeURIComponent(uri));

var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start";

//http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start
alert(decodeURI(uri));

//http://www.wrox.com/illegal value.htm#start
alert(decodeURIComponent(uri));


eval()方法,相当于一个ECMAScript解析器,把字符串解析为代码。

禁止给undefined、NaN、Infinity赋值,在非严格模式下也会发生错误。
window对象,ECMAScript没有指出如何直接访问Global对象,但web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此在全局作用域中声明的所有变量和函数都成了window对象的属性。

Math对象
min、max

alert(Math.ceil(25.9));     //26
alert(Math.ceil(25.5));     //26
alert(Math.ceil(25.1));     //26

alert(Math.round(25.9));    //26
alert(Math.round(25.5));    //26
alert(Math.round(25.1));    //25

alert(Math.floor(25.9));    //25
alert(Math.floor(25.5));    //25
alert(Math.floor(25.1));    //25


Math.random()返回大于等于0小于1的一个随机数

var num = Math.floor(Math.random() * 10 + 1);//1到10间的数

var num = Math.floor(Math.random() * 9 + 2);//2到11间的数


小结

对象在JavaScript中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象:

引用类型与传统面向对象程序设计中的类相识,但实现不同;

Object是一个基础类型,其他所有类型都从Object继承了基本的行为;

Array类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;

Date类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;

RegExp类型是ECMAScript支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。

函数实际上是Function类型的实例,因此函数也是对象;由于函数是对象,所以函数也拥有方法,可以用来增强其行为。

因为有了基本包装类型,所以JavaScript中的基本类型值可以被当做对象来访问。三种基本包装类型:Boolean、Number、String,他们的共同特征:

每个包装类型都映射到同名的基本类型;

在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;

操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象;

所有代码执行之前,作用域中就已经存在两个内置对象:Global和Math。大多数ECMAScript实现中都不能直接访问Global对象;不过,Web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: