JavaScript--04 常用引用类型(Object、Array、Function、Date、RegExp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27127385/article/details/86721497

一、object类型

Object 是ECMAScript 中使用最多的一个类型,用于存储和传输数据。

1.1 创建 Object 实例的方式

1.1.1 使用 new 操作符

var person = new Object();
person.name = '邪人君子';
person.age = 24;

1.1.2 使用对象字面量表示法

  对象字面量用逗号分隔属性,最后一个属性后不能添加逗号。如果最后一个属性后添加了逗号,会在 IE7 及更早版本和 Opera 中导致错误。
  在使用对象字面量语法时,属性名也可以使用字符串。

var person = {
	name:'邪人君子',
	"age":24
}

1.1.3 对象字面量空括号

var person = {};  // 与 new Object(); 相同
person.name = '邪人君子';
person.age = 24;

1.1.4 对象字面量传可选参

function aaa(args){
	console.log(args.name);
	if (typeof args.age == "number") { 
		console.log(args.age);
	} 
}
aaa({
	name:'邪人君子',
	age:24
});
aaa({
	name:'邪人君子'
});

  在这个例子中,函数 aaa() 接受一个名为 args 的参数。这个参数可能带有一个名为 name 或 age 的属性,也可能这两个属性都有或者都没有。
  在这个函数内部,我们通过 typeof 操作符来检测 age 属性是否存在,然后再基于相应的属性来构建一条要显示的消息。然后,我们调用了两次这个函数,每次都使用一个对象字面量来指定不同的数据。这两次调用传递的参数虽然不同,但函数都能正常执行。

1.2 访问对象属性的方法

1.2.1 点表示法

person.name;

1.2.2 方括号表示法

  注意: 使用方括号语法时,应该将要访问的属性以字符串的形式放在方括号中。

person["name"];

1.2.3 方括号语法的优点

1、可以通过变量访问

var nameValue = 'name';
console.log(person[nameValue]);
// 等同于  person['name'];
// 等同于  person.name;

2、属性名不太合理时,只能用方括号语法

person['first name'];
// person.first name 错误

  虽然方括号语法功能更强一点,但我们平时常用的还是用点表示法。

二、Array 类型

  Array 类型链接

三、Date 类型

  要创建一个日期对象,使用 new 操作符和 Date 构造函数即可,如下所示。

var now = new Date(); 
// Wed Feb 20 2019 11:06:44 GMT+0800 (中国标准时间)

  在调用 Date 构造函数而不传递参数的情况下,新创建的对象自动获得当前日期和时间。

3.1 创建日期对象

3.1.1 Date.parse() 方法

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

var d = Date.parse("March 21, 2012");
// 返回1970/01/01至2012/3/21之间的毫秒数: 1332259200000

var d = Date.parse("哈哈哈");
// NaN

  Date.parse() 方法常用接收格式:

  • “月/日/年”,如 6/13/2004;
  • “英文月名 日,年”,如 January 12,2004;
  • “英文星期几 英文月名 日 年 时:分:秒 时区”,如 Tue May 25 2004 00:00:00 GMT-0700。
  • ISO 8601 扩展格式 YYYY-MM-DDTHH:mm:ss.sssZ(例如 2004-05-25T00:00:00)。

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

var someDate = new Date(Date.parse("May 25, 2004"));
// Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间) 

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

var someDate = new Date("May 25, 2004"); 
// Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间) 

  这行代码将会得到与前面相同的日期对象。

3.1.2 Date.UTC() 方法

  Date.UTC()方法同样也返回表示日期的毫秒数。
  Date.UTC()的参数分别是年份、月份、天份、时、分、秒以及毫秒。在这些参数中,只有前两个参数(年和月)是必需的。
  如果没有提供月中的天数,则假设天数为 1;
  如果省略其他参数,则统统假设为 0。
  以下是两个使用 Date.UTC()方法的例子:

// 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() 方法相同,如果直接将表示日期的字符串传递给 Date 构造函数,也会在后台调用 Date.UTC()。

// 本地时间 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); 

3.1.3 Data.now() 方法

  Data.now() 方法返回调用这个方法时的日期和时间的毫秒数:

//取得开始时间
var start = Date.now(); 

//调用函数
doSomething(); 

//取得停止时间
var stop = Date.now(), 
	result = stop – start; 

  支持 Data.now()方法的浏览器包括 IE9+、Firefox 3+、Safari 3+、Opera 10.5 和 Chrome。在不支持它的浏览器中,使用+操作符把 Data 对象转换成字符串,也可以达到同样的目的:

//取得开始时间
var start = +new Date(); 

//调用函数
doSomething(); 

//取得停止时间
var stop = +new Date(), 
	result = stop - start; 

3.2 操作日期对象

3.2.1 toLocaleString()、toString()和 valueOf()方法

  与其他引用类型一样,Date 类型也重写了 toLocaleString()、toString()和 valueOf()方法。
  toLocaleString()方法时间格式中会包含 AM 或 PM,但不会包含时区信息(当然,具体的格式会因浏览器而异)。
  toString()方法则通常返回带有时区信息的日期和时间。
  valueOf()方法,则根本不返回字符串,而是返回日期的毫秒表示,类型为 number。因此,可以方便使用比较操作符(小于或大于)来比较日期值。

3.2.2 日期格式化方法

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

方法 作用
toDateString() 把 Date 对象的日期部分转换为字符串。
toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部分转换为字符串。
toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部分转换为字符串。
toLocaleString() 据本地时间格式,把 Date 对象转换为字符串。
toString() 把 Date 对象转换为字符串。
toTimeString() 显示时、分、秒和时区。
toUTCString() 根据世界时,把 Date 对象转换为字符串。

3.2.3 获取和设置日期/时间的方法

方法 作用
getTime() 返回 1970 年 1 月 1 日至今的毫秒数;与valueOf()方法返回的值相同
setTime(毫秒) 以毫秒数设置日期,会改变整个日期
getFullYear() 取得4位数的年份(如2007而非仅07)
getUTCFullYear() 返回UTC日期的4位数年份
setFullYear(年) 设置日期的年份。传入的年份值必须是4位数字(如2007而非仅07)
setUTCFullYear(年) 设置UTC日期的年份。传入的年份值必须是4位数字(如2007而非仅07)
getMonth() 返回日期中的月份,其中0表示一月,11表示十二月
getUTCMonth() 返回UTC日期中的月份,其中0表示一月,11表示十二月
setMonth(月) 设置日期的月份。传入的月份值必须大于0,超过11则增加年份
setUTCMonth(月) 设置UTC日期的月份。传入的月份值必须大于0,超过11则增加年份
getDate() 返回日期月份中的天数(1到31)
getUTCDate() 返回UTC日期月份中的天数(1到31)
setDate(日) 设置日期月份中的天数。如果传入的值超过了该月中应有的天数,则增加月份
setUTCDate(日) 设置UTC日期月份中的天数。如果传入的值超过了该月中应有的天数,则增加月份
getDay() 返回日期中星期的星期几(其中0表示星期日,6表示星期六)
getUTCDay() 返回UTC日期中星期的星期几(其中0表示星期日,6表示星期六)
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时间相差的分钟数。例如,美国东部标准时间返回300。在某地进入夏令时的情况下,这个值会有所变化

四、RegExp 类型

  RegExp 类型链接

五、Function 类型-简介

5.1 创建函数

5.1.1 构造函数

var sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐,影响性能

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

5.1.2 函数声明

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

5.1.3 函数表达式

  这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式(Function Expression),因为赋值语句的等号右侧只能放表达式。

var sum = function(num1, num2){ 
	return num1 + num2; 
};  // 此处有分号

  非匿名写法:

var print = function x(){
  console.log(typeof x);
};

x
// ReferenceError: x is not defined

print()
// function

  这个x只在函数体内部可用,指代函数表达式本身,其他地方都不可用。这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)。因此,下面的形式声明函数也非常常见。

var f = function f() {};

5.1.4 函数声明与函数表达式的区别

  函数的表达式需要在语句的结尾加上分号,表示语句结束。而函数的声明在结尾的大括号后面不用加分号。

function sum(num1, num2){ 
	return num1 + num2; 
}  // 可以不写分号

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

  解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
  请看下面的例子:

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

  所以重命名时,即使function 命令写法在函数表达式后面,也会在函数表达式之前执行。结果是function 命令定义的函数,会被函数表达式定义的覆盖:

var f = function () {
  console.log('1');
}

function f() {
  console.log('2');
}

f() // 1

5.2 函数重复声明会覆盖:没有重载

  在其他语言(如 Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数的类型和数量)不同即可。
  而在JavaScript中,后面的函数会覆盖前面的函数。
  如下例所示:

function addSomeNumber(num){ 
	return num + 100; 
} 
function addSomeNumber(num) { 
	return num + 200; 
} 
var result = addSomeNumber(100); //300 

  我们换一种写法,就可以更直观的了解是怎么回事了:

var addSomeNumber = function (num){ 
	return num + 100; 
}; 
addSomeNumber = function (num) { 
	return num + 200; 
}; 

  在下面的 arguments 属性部分会介绍 JavaScript 实现类似重载的功能。

5.3 函数可以作为函数参数

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

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

function add10(num){ 
	return num + 10; 
} 

var result1 = callSomeFunction(add10, 10); 
alert(result1); //20 

function getGreeting(name){ 
	return "Hello, " + name; 
} 

var result2 = callSomeFunction(getGreeting, "Nicholas"); 
alert(result2); //"Hello, Nicholas" 

  作为结果返回:

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}]; 

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

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

  这里顺便回顾一下比较函数排序的用法:

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 

5.4 函数的属性和方法

5.4.1 arguments 对象

  arguments 对象是类数组(它并不是 Array 的实例),可以使用方括号语法访问它的每一个元素(即第一个元素是 arguments[0],第二个元素是 argumetns[1],以此类推),使用 length 属性来确定传递进来多少个参数。
  通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数:

function howManyArgs() { 
	alert(arguments.length); 
} 
howManyArgs("string", 45); //2 
howManyArgs(); //0 
howManyArgs(12); //1 

5.4.2 使用 arguments 对象实现-重载

  下例中,函数 doAdd()会在只有一个参数的情况下给该参数加上 10;如果是两个参数,则将那个参数简单相加并返回结果。因此,doAdd(10)会返回 20,而 doAdd(30,20) 则返回 50。虽然这个特性算不上完美的重载,但也足够弥补 ECMAScript 的这一缺憾了。

function doAdd() { 
	if(arguments.length == 1) { 
		alert(arguments[0] + 10); 
	} else if (arguments.length == 2) { 
		alert(arguments[0] + arguments[1]); 
	} 
} 
doAdd(10); //20 
doAdd(30, 20); //50 

  需要注意的是:没有传递值的命名参数将自动被赋予 undefined 值。这就跟定义了变量但又没有初始化一样。例如,如果只给 doAdd()函数传递了一个参数,则 num2 中就会保存 undefined 值。

5.4.3 apply() 和 call() 方法 – 扩充作用域

  每个函数都包含两个非继承而来的方法:apply()和 call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。
apply() 方法
  apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是arguments 对象。例如:

function sum(num1, num2){ 
	return num1 + num2; 
} 
function callSum1(num1, num2){ 
	return sum.apply(this, arguments); // 传入 arguments 对象
} 
function callSum2(num1, num2){ 
	return sum.apply(this, [num1, num2]); // 传入数组
} 
alert(callSum1(10,10)); //20 
alert(callSum2(10,10)); //20 

  在上面这个例子中,callSum1()在执行 sum()函数时传入了 this 作为 this 值(因为是在全局作用域中调用的,所以传入的就是 window 对象,在严格模式下,未指定环境对象而调用函数,则 this 值不会转型为 window。除非明确把函数添加到某个对象或者调用 apply()或 call(),否则 this 值将是undefined。)和 arguments 对象。而 callSum2 同样也调用了sum()函数,但它传入的则是 this 和一个参数数组。这两个函数都会正常执行并返回正确的结果。
call() 方法
  call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同。对于 call()方法而言,第一个参数是 this 值没有变化,传递给函数的参数必须逐个列举出来,如下面的例子所示。

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 

  sayColor()也是作为全局函数定义的,而且当在全局作用域中调用它时,它确实会显示"red"——因为对 this.color 的求值会转换成对 window.color 的求值。而 sayColor.call(this)和 sayColor.call(window),则是两种显式地在全局作用域中调用函数的方式,结果当然都会显示"red"。但是,当运行 sayColor.call(o)时,函数的执行环境就不一样了,因为此时函数体内的 this 对象指向了 o,于是结果显示的是"blue"。

猜你喜欢

转载自blog.csdn.net/qq_27127385/article/details/86721497