5.1 Object
有两种方法创建 Object
实例,一种是 new
,一种是字面量方法。
new
方法:
var person = new Object();
person.name = "Nicholas";
person.age = 29;
字面量方法:注意,用字面量创建对象不会调用 Object
的构造函数
var person = {
name : "Nicholas",
age : 29
};
属性名也可以用字符串,也可以是数字,如果用数字将会自动被转换为字符串类型
var person = {
"name" : "Nicholas",
"age" : 29,
5: true
};
属性除了可以用点号访问外,还可以用方括号访问
alert(person["name"]); //"Nicholas"
alert(person.name); //"Nicholas"
使用方括号访问属性的好处是:可以使用变量,同时可以访问不规范的属性名
//使用变量
var propertyName = "name";
alert(person[propertyName]); //"Nicholas"
//不规范的属性名
person["first name"] = "Nicholas";
5.2 Array 类型
创建 Array
Array 也有两种创建方法,一种是 new
方法,一种是字面量方法
new
方法如下
//创建空数组
var colors = new Array();
//创建指定长度的数组
var colors = new Array(20);
//创建包含三个元素的数组
var colors = new Array("red", "blue", "green");
如果只传给构造函数一个参数,则分为两种情况:
- 参数为数字时,创建指定长度数组
- 参数为其它类型时,创建包含一个元素的数组
//创建长度为 3 的数组
var colors = new Array(3);
//创建包含一个元素的数组
var names = new Array("Greg");
也可以省略 new
操作符
//创建长度为 3 的数组
var colors = Array(3);
//创建包含一个元素的数组
var names = Array("Greg");
字面量创建数组的方法如下
var colors = ["red", "blue", "green"];
var names = [];
处理逗号的时候要小心!
下面的代码在 IE 浏览器下包含 3 个元素,在其它浏览器下只包含 2 个元素
var values = [1,2,];
同样,下面的代码在 IE 浏览器下包含 6 个 undefined
,而在其它浏览器下只有 5 个 undefined
var options = [,,,,,];
length 属性
length
属性保存 Array 的长度
var colors = ["red", "blue", "green"];
var names = [];
alert(colors.length); //3
alert(names.length); //0
length
是可以设置的,缩小数组后,一部分元素将被丢弃
var colors = ["red", "blue", "green"];
//缩小数组
colors.length = 2;
//最后一个元素被丢弃
alert(colors[2]); //undefined
增大数组后,新增的元素都是 undefined
var colors = ["red", "blue", "green"];
var colors = ["red", "blue", "green"];
//扩大数组
colors.length = 4;
//新增元素为 undefined
alert(colors[3]); //undefined
可以利用 length
属性方便的在数组尾部添加元素
var colors = ["red", "blue", "green"];
//在位置 3 添加元素
colors[colors.length] = "black"; //add a color (position 3)
//在位置 4 添加元素
colors[colors.length] = "brown"; //add another color (position 4)
访问 Array 中的元素
用索引访问 Array
中的元素
var colors = ["red", "blue", "green"];
alert(colors[0]);
colors[2] = "black";
colors[3] = "brown";
读取越界的索引将会返回 undefined
,设置越界元素将会扩大数组
var colors = ["red", "blue", "green"];
colors[99] = "black";
alert(colors.length); //100
5.2.1 检测数组
用 Array.isArray
方法检测一个对象是不是数组
if (Array.isArray(value)){
//do something on the array
}
5.2.2 转换方法
有四种转换方法:
-
toString
:返回数组的字符串形式,每个元素之间用逗号分隔。会调用每个元素的toString
方法 -
toLocaleString
:返回数组的字符串形式,每个元素之间用逗号分隔。会调用每个元素的toLocaleString
方法 -
valueOf
:原样返回数组 -
join
:指定一个分隔符号
> arr=[1,2,3]
[ 1, 2, 3 ]
> arr.toString()
'1,2,3'
> arr.toLocaleString()
'1,2,3'
> arr.valueOf()
[ 1, 2, 3 ]
> arr.join('-')
'1-2-3'
可以重写对象的 toString()
和 toLocaleString()
方法
var person1 = {
toLocaleString : function () {
return "Nikolaos";
},
toString : function() {
return "Nicholas";
}
};
var person2 = {
toLocaleString : function () {
return "Grigorios";
},
toString : function() {
return "Greg";
}
};
var people = [person1, person2];
alert(people); //Nicholas,Greg
alert(people.toString()); //Nicholas,Greg
alert(people.toLocaleString()); //Nikolaos,Grigorios
5.2.3 栈方法
有两个栈方法
-
push
:将数据压入数组尾部,返回当前数组的长度。可以一次压入多个数据。 -
pop
:弹出数组尾部的最后一个数据
结合 push 和 pop 可以模拟一个"尾部进,尾部出"栈结构
var colors = new Array(); //create an array
var count = colors.push("red", "green"); //push two items
alert(count); //2
count = colors.push("black"); //push another item on
alert(count); //3
var item = colors.pop(); //get the last item
alert(item); //"black"
alert(colors.length); //2
可以结合数组的 length
属性,以及数组自动扩大的性质使用栈方法
var colors = ["red", "blue"];
colors.push("brown"); //add another item
colors[3] = "black"; //add an item
alert(colors.length); //4
var item = colors.pop(); //get the last item
alert(item); //"black"
5.2.4 队列方法
shift
方法从数组的头部取出一个元素。
结合 push
方法和 shift
方法,可以模拟一个"尾部进,头部出"的队列结构
var colors = new Array(); //create an array
var count = colors.push("red", "green"); //push two items
alert(count); //2
count = colors.push("black"); //push another item on
alert(count); //3
var item = colors.shift(); //get the first item
alert(item); //"red"
alert(colors.length); //2
unshift
方法将数据从头部压入数组。结合 unshift
和 pop
方法可以模拟一个"头部进,尾部出"的反向队列
var colors = new Array(); //create an array
var count = colors.unshift("red", "green"); //push two items
alert(count); //2
count = colors.unshift("black"); //push another item on
alert(count); //3
var item = colors.pop(); //get the first item
alert(item); //"green"
alert(colors.length); //2
5.2.5 排序
reverse
反转数组的顺序
var values = [1, 2, 3, 4, 5];
values.reverse();
alert(values); //5,4,3,2,1
sort 将数组排序
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 {
return 0;
}
}
var values = [0, 1, 5, 10, 15];
values.sort(compare);
alert(values); //0,1,5,10,15
下面是按数值比较大小,降序排列
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
提示:sort
方法和 reverse
方法会改变原来的数组,同时也返回改变后的数组
> arr === arr.reverse()
true
5.2.6 操作方法
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
5.2.7 位置方法
位置方法可以查找元素在数组中的位置,如果没找到就返回 -1 ;可以从头开始查找,也可以从尾部开始查找
-
indexOf
从头部开始查找 -
lastIndexOf
从尾部开始查找 - 如果给出第二个参数,则从指定位置开始查找
- 位置方法使用全等来确定是不是要查找的元素
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
5.2.8 迭代方法
有五种迭代方法
-
every
接收一个函数,测试每一个元素,如果所有元素都返回true
,则every
返回true
-
some
接收一个函数,测试每一个元素,只要有一个元素返回true
,则some
返回true
-
map
接收一个函数,应用到所有元素上,返回值组成一个新的数组返回 -
filter
接收一个函数,应用到所有元素上,将能返回true
的元素组成一个新数组返回 -
forEach
接收一个函数,应用到所有元素上,只接受该原始数组,forEach
自己没有返回值
下面是 every
和 some
的例子
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
下面是 filter
的例子
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]
下面是 map
的例子
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]
下面是 forEach
的例子
var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
//do something here
});
5.2.9 归约函数
有两个归约函数
-
reduce
从左向右归约 -
reduceRight
从右向左归约
这两个函数都接受两个参数,第一个参数是一个函数;第二个参数可以设置一个初值,可以省略
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
从右向左只是方向相反而已,其他都是一样的
var values = [1,2,3,4,5];
var sum = values.reduceRight(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
5.3 Date 类型
可以不传递任何参数,直接创建一个"当前时间"的日期对象
> new Date()
Sat Jan 02 2016 20:25:20 GMT+0800 (中国标准时间)
也可以传入一个从 1970 年 1 月 1 日到指定时间的毫秒数,从而创建一个"指定时间"的日期对象
获得"指定时间"的毫秒数
Date.parse 和 Date.UTC 这两个方法可以返回指定时间的毫秒数
Date.parse 函数
Date.parse 方法接收一个时间字符串,格式规定如下:
- "月/日/年" (
6/13/2004
) - "英文月名 日, 年" (
January 12, 2004
) - "英文星期名 英文月名 日 年 小时:分钟:秒 时区" (
Tue May 25 2004 00:00:00 GMT-0700
) - "YYYY-MM-DDTHH:mm:ss.sssZ" (
2004-05-25T00:00:00
)
> Date.parse("May 25, 2004")
1085414400000
> new Date(Date.parse("May 25, 2004"))
Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
也可以直接像 Date 构造函数传递时间字符串,省略获取毫秒数这一步
> new Date("May 25, 2004")
Tue May 25 2004 00:00:00 GMT+0800 (中国标准时间)
Date.UTC 函数
Date.UTC 函数接收七个参数,只有前两个参数是必需的,其它参数如果省略则都为 0
- 年
- 月(0 到 11)
- 日(1 到 31)
- 小时(0 到 23)
- 分钟
- 秒
- 毫秒
> Date.UTC(2000,0)
946684800000
> new Date(Date.UTC(2000,0))
Sat Jan 01 2000 08:00:00 GMT+0800 (中国标准时间)
同样可以省略获取毫秒数这一步,直接将参数传给 Date 构造函数
> new Date(2000,0)
Sat Jan 01 2000 00:00:00 GMT+0800 (中国标准时间)
获取当前时间的毫秒数
Date.now 获取当前时间的毫秒数
> Date.now()
1451739376823
可以利用这个函数计算程序的运算时间
//get start time
var start = Date.now();
//call a function
doSomething();
//get stop time
var stop = Date.now(),
result = stop – start;
5.3.1 继承的方法
Date
对象重写了 toString
toLocaleString
和 valueOf
这三个方法
toString
和 toLocaleString
方法返回时间字符串,但是各个浏览器返回值不一样,因此用途不大。
valueOf
返回毫秒数,当两个时间对象比较大小时,会调用这个方法
var date1 = new Date(2007, 0, 1); //"January 1, 2007"
var date2 = new Date(2007, 1, 1); //"February 1, 2007"
alert(date1 < date2); //true
alert(date1 > date2); //false
5.3.2 日期格式化方法
有好几个日期格式化方法,但是各个浏览器都不兼容,标准推荐使用 toUTCString
方法
toDateString
toTimeString
toLocaleDateString
toLocaleTimeString
toUTCString
5.3.3 其他方法
方法 | 说明 |
---|---|
getTime() | 与 valueOf 返回值相同 |
setTime(milliseconds) | 重新设置毫秒数,会改变时间对象 |
年 ------------------ | |
getFullYear() | 4位数年份 |
getUTCFullYear() | 4位数年份 |
setFullYear(year) | 4位数年份 |
setUTCFullYear(year) | 4位数年份 |
月 ------------------ | |
getMonth() | 从 0 到 11 |
getUTCMonth() | |
setMonth(month) | 超过 11 则增加年份 |
setUTCMonth(month) | |
日 ------------------ | |
getDate() | 从 1 到 31 |
getUTCDate() | |
setDate(date) | 超过月份的最大天数则增加月份 |
setUTCDate(date) | |
星期 ------------------ | |
getDay() | 从 0 到 6 ,0 表示星期日 |
getUTCDay() | |
小时 ------------------ | |
getHours() | 从 0 到 23 |
getUTCHours() | |
setHours(hours) | 超过 23 则增加日期 |
setUTCHours(hours) | |
分钟 ------------------ | |
getMinutes() | 从 0 到 59 |
getUTCMinutes() | |
setMinutes(minutes) | 超过 59 则增加小时数 |
setUTCMinutes(minutes) | |
秒数 ------------------ | |
getSeconds() | 从 0 到 59 |
getUTCSeconds() | |
setSeconds(seconds) | 超过 59 则增加分钟数 |
setUTCSeconds(seconds) | |
毫秒 ------------------ | |
getMilliseconds() | |
getUTCMilliseconds() | |
setMilliseconds(milliseconds) | |
setUTCMilliseconds(milliseconds) | |
时区 ------------------ | |
getTimezoneOffset() | 返回与标准时间相差的分钟数,东八区返回 -480 |
5.4 RegExp 类型
正则表达式包括模式部分和标志部分。下面使用字面量的方法创建模式
var expression = /pattern/flags;
有三种标志
- i:忽略大小写
- g:全局模式,即不是遇到第一个匹配就停止
- m:多行模式
//匹配所有的 at
var pattern1 = /at/g;
//匹配第一个 bat 或者 cat,不区分大小写
var pattern2 = /[bc]at/i;
//匹配所有的以 at 结尾的三字符组合,不区分大小写
var pattern3 = /.at/gi;
模式中有些符号需要转义
( [ { \ ^ $ | ) ] } ? * + .
//匹配第一个 bat 或 cat,不区分大小写
var pattern1 = /[bc]at/i;
//匹配第一个 [bc]at,不区分大小写
var pattern2 = /\[bc\]at/i;
//匹配所有的以 at 结尾的三字符组合,不区分大小写
var pattern3 = /.at/gi;
//匹配所有的 .at ,不区分大小写
var pattern4 = /\.at/gi;
下面使用 RexExp 构造函数来创建模式。RexExp 构造函数接收两个字符串参数,第一个是模式,第二个是标志。
//匹配第一个 bat 或者 cat,不区分大小写
var pattern1 = /[bc]at/i;
//使用构造函数创建模式,与上面的字面量模式相同
var pattern2 = new RegExp("[bc]at", "i");
传给构造函数的的模式参数中,有些不能直接出现在字符串中的字符也需要转义
字面量模式 | 字符串模式 |
---|---|
/\[bc\]at/ |
"\\[bc\\]at" |
/\.at/ |
"\\.at" |
/name\/age/ |
"name\\/age" |
/\d.\d{1,2}/ |
"\\d.\\d{1,2}" |
/\w\\hello\\123/ |
"\\w\\\\hello\\\\123" |
在老版本浏览器中,相同的字面量模式会共享同一个实例,而相同的构造函数模式会创建不同的实例
var re = null,
i;
//共享一个实例。因此,第一次查找后,第二次查找将从第一次的位置之后开始
for (i=0; i < 10; i++){
re = /cat/g;
re.test("catastrophe");
}
//每次循环都是一个新实例,因此每次都从头开始查找
for (i=0; i < 10; i++){
re = new RegExp("cat", "g");
re.test("catastrophe");
}
新版浏览器已经改进了这个问题,字面量模式每次也会创建新的实例
5.4.1 RegExp 的属性
通过 RegExp 对象的属性可以了解正则表达式的一些信息
- global — 布尔值,是否设置了全局标志
- ignoreCase — 布尔值,是否设置了忽略大小写标志
- lastIndex — 下一次搜索开始的位置,从 0 开始
- multiline — 布尔值,是否设置了多行标志
- source — 返回规范的字面量正则表达式
var pattern1 = /\[bc\]at/i;
alert(pattern1.global); //false
alert(pattern1.ignoreCase); //true
alert(pattern1.multiline); //false
alert(pattern1.lastIndex); //0
alert(pattern1.source); //"\[bc\]at"
var pattern2 = new RegExp("\\[bc\\]at", "i");
alert(pattern2.global); //false
alert(pattern2.ignoreCase); //true
alert(pattern2.multiline); //false
alert(pattern2.lastIndex); //0
alert(pattern2.source); //"\[bc\]at"
从上面的代码可以看到,字面量模式和构造函数模式最后返回的 source 属性是相同的范字面量正则表达式
5.4.2 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"
exec 方法可以执行多次
- 如果没有使用全局标志,则每次都返回第一个匹配项
- 如果使用了全局标志,则每次返回下一个匹配项
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); //0
matches = pattern2.exec(text);
alert(matches.index); //5
alert(matches[0]); //bat
alert(pattern2.lastIndex); //8
test 方法
test 方法仅仅测试是否能够匹配,返回布尔值
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)){
alert("The pattern was matched.");
}
toString 和 toLocaleString 方法
都返回字面量模式
var pattern = new RegExp("\\[bc\\]at", "gi");
alert(pattern.toString()); // /\[bc\]at/gi
alert(pattern.toLocaleString()); // /\[bc\]at/gi
valueOf
返回模式对象自己
5.4.3 RegExp 静态属性
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); //false
}
下面是使用短属性名的例子
var text = "this has been a short summer";
var pattern = /(.)hort/g;
/*
* 注意:这些属性老旧浏览器都不支持
*/
if (pattern.test(text)){
alert(RegExp.$_); //this has been a short summer
alert(RegExp["$`"]); //this has been a
alert(RegExp["$’"]); // summer
alert(RegExp["$&"]); //short
alert(RegExp["$+"]); //s
alert(RegExp["$*"]); //false
}
还有多达 9 个属性用来存储捕获组
var text = "this has been a short summer";
var pattern = /(..)or(.)/g;
if (pattern.test(text)){
alert(RegExp.$1); //sh
alert(RegExp.$2); //t
}
5.5.4 模式的局限性
Javascript 相比其他语言的正则表达式,有一定的局限性,但是也很强大,完全够用。
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"); //not recommended
函数的名字仅仅是个指针,因此一个函数对象可以有多个名字
function sum(num1, num2){
return num1 + num2;
}
alert(sum(10,10)); //20
var anotherSum = sum;
alert(anotherSum(10,10)); //20
sum = null;
alert(anotherSum(10,10)); //20
5.5.1 没有重载(深入理解)
因为函数名就是个指针,因此一旦重载函数,函数名就会指向新的函数对象,所以无法像其他语言那样重载函数名。
function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //300
5.5.2 函数声明与函数表达式
Javascript 解析器首先会扫描所有的函数声明,然后再解析其他表达式,因此函数声明会被提升,即可以先使用后声明。
alert(sum(10,10));
function sum(num1, num2){
return num1 + num2;
}
而用表达式定义的函数不能这样使用
//会报错~~~~
alert(sum(10,10));
var sum = function(num1, num2){
return num1 + num2;
};
5.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
5.5.4 函数内部属性
argumnets.callee
属性
因为在 Javascript 中函数名仅仅是一个指针,因此,如果在递归中使用函数名可能会导致问题。
// 求阶乘的函数:使用函数名递归调用自身
function factorial(num){
if (num <= 1) {
return 1;
} else {
return num * factorial(num-1)
}
}
//用另外一个名字指向递归函数
var trueFactorial = factorial;
//原先的名字变成另外一个函数
factorial = function(){
return 0;
};
//调用会发生错误
console.info(trueFactorial(5)); //0
argumnets.callee
属性则代表函数对象自身,使用这个属性可以避免上述问题的发生
// 求阶乘的函数:使用 arguments.callee 属性递归调用自身
function factorial(num){
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num-1)
}
}
//用另外一个名字指向递归函数
var trueFactorial = factorial;
//原先的名字变成另外一个函数
factorial = function(){
return 0;
};
//这次不会发生错误
console.info(trueFactorial(5)); //120
函数内部的 this
对象
在函数内部还有一个 this 对象,这个对象代表调用函数的那个对象,他是动态可变的,定义函数的时候不需要知道他是谁。
//这个函数里面的 this 指向谁现在并不清楚
function sayColor(){
alert(this.color);
}
window.color = "red";
var o = { color: "blue" };
//全局调用,this 指向 window
sayColor(); //"red"
//这里 this 指向 o
o.sayColor = sayColor;
o.sayColor(); //"blue"
函数的 caller
属性
caller 属性指向调用当前函数的外部函数
function outer(){
inner();
}
//打印外部函数
function inner(){
alert(inner.caller);
}
outer();
更好的方法是不使用函数自己的名字,而是用 arguments.callee
function outer(){
inner();
}
//打印外部函数
function inner(){
alert(arguments.callee.caller);
}
outer();
5.5.5 函数的属性和方法
length 属性
表示函数声明的参数个数
function sayName(name){
alert(name);
}
function sum(num1, num2){
return num1 + num2;
}
function sayHi(){
alert("hi");
}
alert(sayName.length); //1
alert(sum.length); //2
alert(sayHi.length); //0
apply 方法 和 call 方法
apply 和 call 方法配合 this 指针,可以动态为函数指定所属对象。两个方法的区别不大,唯一的区别是参数列表组织方式不一样。
window.color = "red";
var o = { color: "blue" };
//现在 this 没有指定
function sayColor(){
alert(this.color);
}
sayColor(); //red
//this 指向 window
sayColor.call(this); //red
sayColor.call(window); //red
//this 指向 o
sayColor.call(o); //blue
bind 方法
bind 方法将函数的 this 指针绑定到一个明确的对象,然会返回这个新函数函数
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
//返回绑定到对象 o 的函数
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
5.6 基本包装类型
有三种包装器类型,一般不直接使用,只在后台供解析器使用。
Boolean
Number
String
每当代码调用"原生类型"的对象方法或属性时,解析器都会在后台创建对应的包装器对象,代替原生类型,这会让我们觉得在直接使用原生类型的属性和方法。当属性和方法使用完毕后,包装器对象会被销毁。
下面的语句
var s1 = "some text";
var s2 = s1.substring(2);
第二条语句实际上被转换成
//转换成包装器对象
var temp = new String("some text");
//使用其中的方法
var s2 = s1.substring(2);
//销毁包装器对象
temp = null;
无法为原生类型添加属性:因为包装器对象是临时的,使用完毕后会被销毁,为其添加的属性同样会销毁
var s1 = "some text";
s1.color = "red";
alert(s1.color); //undefined
将原生类型数据传给 Object 构造器当做参数,会到的对应的包装器对象
var obj = new Object("some text");
alert(obj instanceof String); //true
除非必须的情况下,一般不直接使用包装器对象,因为包装器对象的 typeof 运算总是返回 object
,而原生类型会返回明确的信息,二者在逻辑上有冲突。
var value = "25";
var number = Number(value); //转型函数
alert(typeof number); //"number"
var obj = new Number(value); //包装对象构造器
alert(typeof obj); //"object"
5.6.1 Boolean 类型
永远不要使用 Boolean 包装器,因为所有对象的真值为都是 True ,即使逻辑上是一个 False 值
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true
var falseValue = false;
result = falseValue && true;
alert(result); //false
而且 typeof 运算和 instanceof 运算返回的值也不一样
alert(typeof falseObject); //object
alert(typeof falseValue); //boolean
alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean); //false
5.6.2 Number 类型
Number 类型重写了几个常见的方法:
- valueOf:返回原生数据
- toString:返回字符串形式
- toLocaleString:返回字符串形式
toFixed 方法:指定小数位数
var num = 10;
alert(num.toFixed(2)); //"10.00"
var num = 10.005;
alert(num.toFixed(2)); //"10.01"
toExponential:科学计数法表示
var num = 10;
alert(num.toExponential(1)); //"1.0e+1"
toPrecision:设置显示精度
var num = 99;
alert(num.toPrecision(1)); //"1e+2"
alert(num.toPrecision(2)); //"99"
alert(num.toPrecision(3)); //"99.0"
一般情况下也不应使用 Number 包装器,原因也是 typeof 测试和 instanceof 测试会出现问题
var numberObject = new Number(10);
var numberValue = 10;
alert(typeof numberObject); //"object"
alert(typeof numberValue); //"number"
alert(numberObject instanceof Number); //true
alert(numberValue instanceof Number); //false
5.6.3 String 类型
String 对象的 valueOf 、toString、toLocaleString 这三个方法都返回字符串原生数据
length 属性
返回字符串的长度
var stringValue = "hello world";
alert(stringValue.length); //"11"
获取指定位置的字符
- charAt:获取指定位置的字符
- charCodeAt:获取指定位置的字符编码
var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
var stringValue = "hello world";
alert(stringValue.charCodeAt(1)); //outputs "101"
也可以将字符串看做是一个字符数组,直接索引字符
var stringValue = "hello world";
alert(stringValue[1]); //"e"
拼接字符串
concat 方法用来拼接字符串
var stringValue = "hello ";
var result = stringValue.concat("world");
alert(result); //"hello world"
alert(stringValue); //"hello"
concat 方法可以接受多个参数,一块拼接
var stringValue = "hello ";
var result = stringValue.concat("world", "!");
alert(result); //"hello world!"
alert(stringValue); //"hello"
更常见的用法还是使用加号
> "hello" + "world" + "!"
'helloworld!'
切分字符串
- slice:返回两个位置之间的字符串,第二个位置必须在第一个位置右边,则返回空字符串。两个位置都可以使用负数索引。
> s.slice(5,7)
'56'
> s.slice(7,5)
''
> s.slice(5,-3)
'56'
> s.slice(-3,5)
''
> s.slice(-5,-3)
'56'
> s.slice(-3,-5)
''
- substring:返回两个位置参数之间的字符串。负数索引都被转换为 0
> s.substring(5,7)
'56'
> s.substring(7,5)
'56'
> s.substring(5,-3)
'01234'
> s.substring(-3,5)
'01234'
> s.substring(-3,-5)
''
- substr:第一个参数指定切分位置,第二个参数指定切分数量,第一个参数接受负数,第二个参数输入负数会被转换为 0
> s.substr(5,2)
'56'
> s.substr(2,5)
'23456'
> s.substr(5,-2)
''
> s.substr(-5,2)
'56'
> s.substr(-5,-2)
''
索引和定位某个字符
使用 indexOf 和 lastIndexOf 这两个方法
var stringValue = "hello world";
alert(stringValue.indexOf("o")); //4
alert(stringValue.lastIndexOf("o")); //7
第二个参数可以指定搜索起始位置
var stringValue = "hello world";
alert(stringValue.indexOf("o", 6)); //7
alert(stringValue.lastIndexOf("o", 6)); //4
多次调用,并且每次改变第二个参数的,可以找到所有指定字符的位置
var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
var positions = new Array();
var pos = stringValue.indexOf("e");
while(pos > -1){
positions.push(pos);
pos = stringValue.indexOf("e", pos + 1);
}
alert(positions); //"3,24,32,35,52"
删除前缀及后缀空格
使用 trim trimLeft trimRight 这三个方法,返回新字符串,原是字符串不变
var stringValue = " hello world ";
var trimmedStringValue = stringValue.trim();
alert(stringValue); //" hello world "
alert(trimmedStringValue); //"hello world"
大小写转换
使用 toUpperCase、toLocaleUpperCase、toLowerCase、toLocaleLowerCase 这几个方法
var stringValue = "hello world";
alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD"
alert(stringValue.toUpperCase()); //"HELLO WORLD"
alert(stringValue.toLocaleLowerCase()); //"hello world"
alert(stringValue.toLowerCase()); //"hello world
正则匹配
var text = "cat, bat, sat, fat";
var pattern = /.at/;
//same as pattern.exec(text)
var matches = text.match(pattern);
alert(matches.index); //0
alert(matches[0]); //"cat"
alert(pattern.lastIndex); //0
正则搜索
返回搜索字符串的位置,如果没有找到则返回 -1
var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos); //1
正则替换
replace 方法返回一个新字符串,源字符串不变
var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
alert(result); //"cond, bat, sat, fat"
//第一个参数是个模式
result = text.replace(/at/g, "ond");
alert(result); //"cond, bond, sond, fond"
在第二个参数里可以使用美元符号,让替换更灵活
var text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)
属性名 | 短属性名 | 说明 |
---|---|---|
input | $_ | 最近一次要匹配的字符串 |
lastMatch | $& | 最近一次的匹配项 |
lastParen | $+ | 最近一次的匹配组 |
leftContext | $` | input 字符串中 lastMatch 之前的文本 |
multiline | $* | 是否所有表达时都使用多行模式 |
rightContext | $’ | input 字符串中 lastMatch 之后的文本 |
第二个参数可以是一个函数,函数接受三个参数
- 第一个参数:匹配字符串
- 第二个参数:匹配位置
- 第三个参数:原始字符串
如果模式中有组存在,则从第二个参数开始到倒数第三个参数,传入的都是组匹配,最后两个参数不变
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(/[^\,]+/); //["", ",", ",", ",", ""]
比较字符串大小 localeCompare
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”
HTML 方法
METHOD | OUTPUT |
---|---|
anchor(name) | <a name=“name”>string</a> |
big() | <big>string</big> |
bold() | <b>string</b> |
fixed() | <tt>string</tt> |
fontcolor(color) | <font color=“color”>string</font> |
fontsize(size) | <font size=“size”>string</font> |
italics() | <i>string</i> |
link(url) | <a href=“url”>string</a> |
small() | <small>string</small> |
strike() | <strike>string</strike> |
sub() | <sub>string</sub> |
sup() | <sup>string</sup> |
5.7 单体内置对象
5.7.1 Global 对象
全局属性和全局方法其实都是 Global 的属性和方法,例如 isNaN isFinite 等等,除此之外还有另外几个方法
URI 编码方法
- encodeURI 方法:不会对本身属于 URI 的字符进行编码,比如斜杠、冒号、问号、井号之类的。因此这个方法可以对 URI 串进行整体编码
- encodeURIComponent 方法:会对任何非标准字符串进行编码,因此只能对 URI 的部分串进行编码
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 方法
eval 方法对字符串进行求值操作
eval(“alert(‘hi’)”);
//相当于
alert(“hi”);
eval 方法中的代码与当前环境有相同的作用域链
var msg = “hello world”;
eval(“alert(msg)”); //”hello world”
同理,在 eval 中定义的对象在当前环境中也能访问(严格模式下不行)
var msg = “hello world”;
eval(“alert(msg)”); //”hello world”
Global 的属性
PROPERTY | DESCRIPTION |
---|---|
undefined | The special value undefined |
NaN | The special value NaN |
Infinity | The special value Infinity |
Object | Constructor for Object |
Array | Constructor for Array |
Function | Constructor for Function |
Boolean | Constructor for Boolean |
String | Constructor for String |
Number | Constructor for Number |
Date | Constructor for Date |
RegExp | Constructor for RegExp |
Error | Constructor for Error |
EvalError | Constructor for EvalError |
RangeError | Constructor for RangeError |
ReferenceError | Constructor for ReferenceError |
SyntaxError | Constructor for SyntaxError |
TypeError | Constructor for TypeError |
URIError | Constructor for URIError |
window 对象
window 对象就是浏览器中的 Global 对象
var color = “red”;
function sayColor(){
alert(window.color);
}
window.sayColor(); //”red”
如果不是在浏览器环境下,可以用下面的代码犬的 Global 对象
var global = function(){
return this;
}();
5.7.2 Math 对象
下面是 Math 对象中一些常用的常数
PROPERTY | DESCRIPTION |
---|---|
Math.E | The value of e, the base of the natural logarithms |
Math.LN10 | |
Math.LN2 | |
Math.LOG2E | |
Math.LOG10E | |
Math.PI | |
Math.SQRT1_2 | |
Math.SQRT2 |
求最大最小数
var max = Math.max(3, 54, 32, 16);
alert(max); //54
var min = Math.min(3, 54, 32, 16);
alert(min); //3
如果师数组,可以用 apply 方法
var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
舍入方法
- ceil :向上靠近
- floor:向下靠近
- round:四舍五入
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
随机数
返回某个范围内的随机数
number = Math.floor(Math.random() * 可能值的总数 + 第一个数)
//返回 1 到 10 之间的随机数
var num = Math.floor(Math.random() * 10 + 1);
//返回 2 到 9 之间的随机
var num = Math.floor(Math.random() * 9 + 2);
可以将这个算法写成一个函数
function selectFrom(lowerValue, upperValue) {
var choices = upperValue - lowerValue + 1;
return Math.floor(Math.random() * choices + lowerValue);
}
var num = selectFrom(2,10);
alert(num); //返回 1 到 10 之间的随机数
其他方法
METHOD | DESCRIPTION |
---|---|
Math.abs(num) | |
Math.exp(num) | |
Math.log(num) | |
Math.pow(num, power) | |
Math.sqrt(num) | |
Math.acos(x) | |
Math.asin(x) | |
Math.atan(x) | |
Math.atan2(y, x) | |
Math.cos(x) | |
Math.sin(x) | |
Math.tan(x) |