第五章——引用类型

2016-05-31  本文已影响48人  26001a36aa12

Object类型


方法1:

var person = new Object();
person.name = "frank";
person.age = 18;

方法2:

var person = {
    name : "frank",
    age : 18
}

属性名可以使用字符串。

再通过对象字面量定义对象时,实际上不会调用Object构造函数。

实际上,对象字面量也是向函数传递大量可选参数的首选方式。也就是说,传递了一个对象参数。
注意:这种传递参数的模式最适合需要向函数传入大量可选参数的情形。一般来讲,命名参数虽然容易处理,但在有多个可选参数的情况下就会显示不够灵活。最好的做法是对那些必需值使用命名参数,而使用对象字面量来封装多个可选参数。

若使用方括号表示法,应该将属性以字符串的形式放在方括号中。方括号的优点是可以通过变量访问属性。

如果属性名中包含会导致语法错误的字符(如空格,非字母非数字等),或者属性名使用的是关键字或保留字,可以使用方括号表示法。

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

Array类型


(1)数组可保存任何类型数据;(2)数组大小可以动态调整。

方法1:使用Array构造函数。

var colors = new Array();
var colors = new Array(20);
var colors = new Array("red","blue","green");

当然,可以省略new操作符。

方法2:使用数组字面量。

var colors = ["red","blue","green"];

在使用数组字面量表示法时,不会调用Array构造函数。

如果设置的某个值的索引超过了数组现有项数,则数组会自动增加到该索引值加1的长度。

数组的length属性不是只读的。通过设置这个属性可以从数组的末尾移除项或向数组中添加新项。当然,利用length属性也可以方便的在数组末尾添加新项。

1.检测数组

Array.isArray(xxx)

使用instanceof检测数组的问题在于,它假定单一的全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上的不同全局执行环境,从而存在两个以上的不同版本Array构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建数组分别具有各自不同的构造函数。

2.转换方法

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

实际上,为了创建这个字符串会调用数组每一项的toString方法。
最后一行直接将数组传递给了alert,由于alert要接收字符串参数,所以它会在后台调用toString方法。

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

如果不给join方法传入任何值,或者给它传入undefined,则使用逗号分隔符。

如果数组中某一项是null或者undefined,那么该值在join、toLocaleString、toString、valueOf方法返回的结果中以空字符串表示。

3.栈方法

ECMAScript为数组专门提供了push()和pop()方法,以便实现类似栈的行为。

push()方法将元素添加到数组末尾,并返回修改后数组长度。
pop()方法从数组末尾移除最后一项,减小length值,返回移除的项。

4.队列方法

push()是向数组末端添加项的方法;shift()是移除数组中第一个项,减小length值,并返回移除的项。

ECMAScript还为数组提供了unshift()方法,在数组前端添加任意个项,并返回新数组长度。因此,同时使用unshift()和pop()方法,可以从相反方向模拟队列。

5.重排序方法

reverse():翻转数组
sort():升序排列数组,sort方法会调用每一项的toString方法,然后排序比较字符串。

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

arr.sort(compare);

6.操作方法

concat():首先,创建当前数组的一个副本,然后把接收到的参数添加到数组末尾,最后返回新创建的数组。

var colors = ["red","green","blue"];
var colors2 = colors.concat("yellow",["black","brown"]);  //red,green,blue,yellow,black,brown

slice():切分数组,不会影响原数组。

如果slice方法中有一个负数,则用数组长度加上该数来确定相应的位置。

splice():主要用途是向数组的中部插入项。

7.位置方法

index():两个参数,要查找的项、查找起点位置的索引(可选)。
lastIndexOf()

比较使用的是全等操作符===

8.迭代方法

5个迭代方法,每个方法接收两个参数:要在每一项上运行的函数、运行该函数的作用域对象——影响this的值(可选)。

传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置、数组对象本身。

var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = number.every(function(item,index,array){
    return item>2;
});  //false
var everyResult = number.some(function(item,index,array){
    return item>2;
});  //true
var filterResult = number.filter(function(item,index,array){
    return item>2;
});  //[3,4,5,4,3]
var mapResult = number.map(function(item,index,array){
    return item*2;
});  //[2,4,6,8,10,8,6,4,2]
number.forEach(function(item,index,array){
    //某些操作
});

9.缩小方法

reduce()、reduceRight():前者从前遍历到后,后者从后遍历到前。

两个参数:在每一项上调用的函数、作为缩小基础的初始值(可选)。
传给该函数的函数包含四个参数:前一个值、当前值、项的索引、数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。

Date类型


var now1 = new Date();  //自动获得当前CST格式时间
var now2 = +new Date();  //自动获得当前毫秒时间
var now3 = Date.now();  //自动获得当前毫秒时间

var date1 = new Date(1464364800000);  //自动获得CST格式时间
var date2 = new Date("5/28/2016");  //自动获得CST格式时间,自动调用了Date.parse方法
var date3 = new Date(2016,5,28,17,59,50);  //自动获得CST格式时间,自动调用Date.UTC方法(不过日期时间都是基于本地时区)

Date.parse("May 28, 2016");  //特定日期转换成毫秒
Date.parse("5/28/2016");  //特定日期转换成毫秒
Date.parse("May 28, 2016");  //特定日期转换成毫秒
Date.parse("Tue Jun 28 2016 17:59:50 GMT+0800");  //特定日期转换成毫秒

Date.UTC(2016,5,28,17,59,50);  //特定日期转换成毫秒,基于GMT时间

1.继承的方法

toLocaleString、toString

var now = new Date();
now.toLocaleString();  //2016/5/28 下午6:21:15
now.toString();  //Sat May 28 2016 18:21:55 GMT+0800 (CST)

valueOf,不返回字符串,而是返回日期的毫秒表示。因此,可以方便使用比较操作符来比较日期值。

2.日期格式化方法

**因浏览器而异

now.toDateString();  //Sat May 28 2016
now.toTimeString();  //18:26:09 GMT+0800 (CST)
now.toLocaleDateString();  //2016/5/28
now.toLocaleTimeString();  //下午6:26:52
now.toUTCString();  //Sat, 28 May 2016 10:27:07 GMT

3.日期/时间组件方法

剩下未介绍的直接取得和设置日期中特定部分的方法参见官网

RegExp类型


字面量形式创建一个正则表达式:

var expression = /pattern/flags;

每个正则表达式都可带有一个或多个flags,用以标明正则表达式的行为。

flags:
   - g:全局模式,模式将被应用在所有字符串,而非在发现第一个匹配项时立即停止;
   - i:不区分大小写模式,即在确定匹配项时忽略模式与字符串的大小写;
   - m:多行模式,即在到达文末时还会继续查找下一行是否存在与模式匹配的项;

元字符:( [ { \ ^ $ | ) ? * + . ] }

RegExp构造函数创建正则表达式:

var pattern = new RegExp("pattern","flags");

正则表达式中的\要在字符串中被转义为\

ECMAScript 5明确规定使用字面量方式和构造函数一样,每次都创建新的RegExp实例。

1.RegExp实例属性

通过以下属性可以取得有关模式的各种信息。

2.RegExp实例方法

exec():专门为捕获组而设计的。

返回的信息虽然是Array实例,但包含两个额外属性:index和input。index表示匹配项在字符串中的位置;input表示应用正则表达式的字符串。

虽然说,尽管设置了g标志,每次也只会返回一个匹配项,但是设置了之后,每次调用exec都会在字符串中继续查找新的匹配项。

test():接收一个字符串参数。在模式与该参数匹配的情况下返回true,否则返回false。经常被用于if语句中。

toString和toLocaleString都会返回正则表达式的字面量。

3.RegExp构造函数属性

RegExp构造函数包含一些属性(这些属性在其他语言中被看成是静态属性),这些属性适用于作用域中的所有正则表达式,并且基于最近一次的正则表达式操作而变化。

长属性名 短属性名 说明
input $_ 最近一次要匹配的字符串
lastMatch $& 最近一次的匹配项
lastParen $+ 最近一次匹配的捕获组
leftContext $` input字符串中lastMatch之前的文本
rightContext $' input字符串中lastMatch之后的文本
multiline $* 布尔值,是否所有表达式都是用多行模式

长属性名用.来访问,短属性名用[]来访问(除了$_)。

此外,还有九个用于存储捕获组的属性:RegExp.$1、RegExp.$2等。

4.模式的局限性

Function类型


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

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

等同于

var sum = function(num1,num2){
    return num1+num2;
};  //注意分号哦!

在使用函数表达式定义函数时,没有必要使用函数名——通过变量sum即可引用函数。

还可使用Function构造函数定义函数,但不推荐。

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

1.没有重载

重载就相当于修改了函数指针,使其指向了另一个函数。

2.函数声明与函数表达式

解析器在向执行环境中加载数据时,率先读取函数声明,并使其在执行任何代码之前可用;至于函数表达式,则必须等到解析器执行到他所在的代码行,才会真正被解释执行。

alert(sum(1,2));
function sum(num1,num2){
    return num1+num2;
}  //正确

alert(sum(1,2));
var sum = function(num1,num2){
    return num1+num2;
}  //错误

同时使用函数声明和表达式时在Safari中会出错

3.作为值的函数

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

(1)像传递参数一样把一个函数传递给另一个函数,例如:

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

注意:要访问函数的指针而不执行函数的话,必须去掉函数名后面那对圆括号。因此传递给callSomeFunction的是add和getGreeting,而不是执行后的结果。

(2)将一个函数作为另一个函数的结果返回,例如:
假设有一个对象数组,我们想要根据某个对象的属性对数组进行排序。但传递给sort的方法的比较函数要接收两个参数,即要比较的值。可是我们需要一种方式来指明按照哪个属性排序。因此,我们可以定义一个函数,它接收一个属性名,然后根据这个属性名来创建一个比较函数。

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:"zz",age:26},{name:"nn",age:29}];
data.sort(createComparisonFunction("name"));

4.函数内部属性

函数内部有两个属性,arguments和this。

arguments包含传入函数的所有参数,且这个参数还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

例如一个阶乘递归函数,函数名紧紧耦合在了一起,为了消除紧耦合,将内部的函数名替换为arguments.callee,这样不论调用函数时使用的是什么名字,都可以保证正常完成递归调用。

this引用的是函数据以执行的环境对象。在调用函数之前,this的值并不确定,因此this可能会在代码执行过程中引用不同的对象。

ECMAScript5也规范化了另一个属性caller。这个属性保存着调用当前函数的函数的引用。注意,arguments.caller始终是undefined,定义此属性是为了分清arguments.caller和函数的caller属性。以上变化都是为了加强这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其他代码了。

5.函数属性和方法

前面提到过,函数也是对象,因此函数也有属性和方法。每个函数包含两个属性:length和prototype

length属性表示函数希望接收的命名参数的个数。

prototype是保存它们所有实例方法的真正所在,只不过都是通过各自对象的实例访问。在创建自定义引用类型以及实现继承时,prototype极为重要,且prototype不可枚举,不可使用for-in发现它。

每个函数都包含两个非继承而来的方法:apply()和call()

这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。(this指向一个对象)

apply()方法两个参数:函数作用域、参数数组(可以是Array,可以是arguments对象)。函数作用域即目前所在函数所处的作用域。
call()方法两个参数:函数作用域、其余参数。
适用:(1)直接传递arguments对象和(2)函数第一个参数是数组,两种情况使用apply方便,其余使用call方便。

他们真正强大的地方在于能够扩充函数赖以生存的作用域。并且好处是对象不需要与方法有任何耦合关系。即不用将函数放到对象中去了。

ECMAScript5还定义了一个方法:bind()

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

apply和call都是立马调用函数,而bind是生成一个新函数。

其余方法:**toLocaleString()、toString()、valueOf()根据浏览器而异返回函数代码或函数代码内部表示。

基本包装类型


我们知道基本类型值不是对象,因而从逻辑上讲它们不应该有方法。其实,为了让我们实现这种直观的操作,后台已经自动完成了一系列处理。

var s1 = "some text";
var s2 = s1.substring(2);

当执行第二行代码时,后台进行下列三个过程:

var s3 = new String("some text");
var s2 = s3.substring(2);
s3 = null;

这三个步骤也分别适用于Boolean和Number。

引用类型和基本包装类型主要区别都是对象的生存期。new出来的实例在执行流离开作用域之前一直保存在内存中。而自动创建的基本包装类型对象,则只存在于代码执行的瞬间,然后立即被销毁。这意味着不能在运行时添加属性和方法。

当然也可以调用Boolean、Number、String创建基本包装类型的对象,不过最好不要这么做,因为很容易让人分不清自己是在处理基本类型还是引用类型的值。

Object构造函数也会像工厂方法一样,根据传入值的类型返回相应基本包装类型的实例。

var obj1 = new Object("some text");//String类型的实例
alert(typeof obj);//Object
alert(obj instanceof String);//true,如果对基本类型判断的话会返回false
var obj2 = new Object(20);//Number类型的实例
var obj3 = new Object(true);//Boolean类型的实例

1.Boolean类型

var booleanObject = new Boolean(false);
var result = booleanObject && true;
alert(result);  //true
//因为布尔表达式中所有对象都会被转换为true

typeof操作符对基本类型返回boolean,对引用类型返回object。

建议永远不要使用Boolean对象

2.Number类型

toFixed(n)会按照指定的n个小数位返回数值的字符串表示(四舍五入)。

toExponential(n)返回指数表示法表示的数值的字符串形式。n是小数的位数。

toPrecision(n)返回最合适的格式。n表示位数。

同样建议不要使用Number对象,并且用typeof和instanceof时和Boolean返回值一样。

3.String类型

注意:即使字符串中包含双字节字符(不占一个字节的ASCII字符),每个字符也仍然算一个字符。

字符方法

字符串操作方法
concat("xxx","xxx"):拼接字符串,但原字符串保持不变。但大部分时候还是使用+来连接。

字符串位置方法

trim()方法
trim():创建一个字符串的副本,删除前置和后缀的空格,然后返回结果。(有些浏览器还支持trimLeft()和trimRight())

字符串大小写转换方法
toLowerCase()toUpperCase()
toLocaleLowerCase()toLocaleUpperCase()针对特定地区实现,更稳妥的方法。

字符串模式匹配方法
match():一个参数,正则表达式或者RegExp对象,返回一个数组。与RegExp的exec()方法相同。
search():参数与match一样,返回字符串中第一个匹配项的索引。
replace():两个参数:

function htmlEscape(text){
    return text.replace(/[<>"&]/g,function(match,pos,originalText){
        switch(match){
            case "<":
                return "<";
            case ">":
                return ">";
            case "&":
                return "&";
            case "\"":
                return """;
        }
    });
}
字符序列 替换文本
$$ $
$& RegExp.lastMatch
$' RegExp.leftContext
$` RegExp.rightContext
$n/$nn 第n个捕获组的字符串,没有则用空串代替

split():基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。可以接受第二个参数指定返回的数组的大小。

var colorText = "red,blue,green,yellow";
var color3 = colorText.split(/[\^,]+/);  //返回["" , "," , "," , "," , ""]
///[\^,]+/表示任何(1个或多个)非逗号的标识符
//因为,正则表达式指定的分隔符出现在了字符串的开头和末尾

localeCompare()方法
在字母表中的排序,排在参数前返回负数,后正数,相等则0。
大小写的前后根据情况而异。

fromCharCode()方法
静态方法,接收一个或多个字符编码,然后将他们转换成一个字符串。

HTML方法

单体内置对象


由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。也就是说,不必显式地实例化内置对象,因为它们已经实例化了。例如前面我们介绍过的Object、Array、String等,还有两个比较重要的Global和Math。

1.Global对象

全局对象可以说是最特别的对象了,因为不管从什么角度看,这个对象都是不存在的。“兜底儿对象”,不属于任何其他对象的属性和方法,最终都是他的属性和方法,例如isNaN、isFinite、parseInt、parseFloat等,除此之外,还有一些其他的。

URI编码方法
encodeURI()encodeURIComponent()可以对URI编码,例如有效地URI不能包含某些字符(空格等),因此可以编码成浏览器能理解的形式。

encodeURI()不会对本身属于URI的字符进行编码(如冒号、正斜杠、问号、井字号);而encodeURIComponent()对它发现的任何非标准字符进行编码。因此,我们常对整个URI使用encodeURI()编码,对附加在现有URI后面的字符串使用encodeURIComponent()。

一般来说,我们使用encodeURIComponent()的时候比较多,因为在实践中更常见的是对查询字符串参数而不是对基础URI编码。

与上面两个方法相对应的是:decodeURI()decodeURIComponent()

eval()方法
在eval()中创建的任何变量和函数都不会被提升,因为在解析代码的时候,它们被包含在一个字符串中;它们只在eval()执行的时候创建。

Global对象属性

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

window对象
ECMAScript虽然没有指出如何直接访问Global对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。

在没有给函数明确指定this值的情况下(无论是通过将函数添加为对象的方法,还是通过调用call()或apply()),this值等于Global对象。

2.Math对象

Math对象的属性

属性 说明
Math.E e值
Math.LN10 ln10
Math.LN2 ln2
Math.LOG2E log2(e)
Math.LOG10E log10(e)
Math.PI pi
Math.SQRT1_2 1/2平方根
Math.SQRT2 2平方根

max()和min()方法

Math.max(1,2,3,4)
Math.min(1,2,3,4)

要找到数组中的最大值可以用如下方法!

var values = [1,2,3,4];
var max = Math.max.apply(Math,values);

舍入方法

random()方法

从某个整数范围随机选择一个值公式
    值 = Math.floor(Math.random()*可能值的总数+第一个可能的值)

Math其他方法
参见官网

上一篇 下一篇

猜你喜欢

热点阅读