每一个JavaScript函数都会有不少附属的(attached)方法,包括toString()、call()以及apply()。听起来,你是否会感到奇怪,一个函数可能会有属于它本身的方法,可是记住,JavaScript中的每一个函数都是一个对象。看一下 这篇文章 ,复习一下(refresher)JavaScript特性。你可能还想知道JavaScript中函数和方法的区别。我认为“函数”和“方法”的描述,仅仅是JavaScript的习惯约定而已。函数立足于它们本身(例如:alert()),而方法是函数内部一个对象的属性(dictionary),咱们经过对象来调用方法。每一个JavaScript对象都有一个toString()方法,下面经过代码举例说明,在一个函数对象中,咱们能够使用toString()方法。程序员
1
2
3
4
|
function
foo(){
alert(
'x'
);
}
alert(foo.toString());
|
由于函数都是对象,它们有本身的属性和方法。咱们能够把它们看做数据(data)。这篇文章,咱们只关注两个函数的方法apply()以及call()。数组
咱们从下面的代码开始:app
1
2
3
4
5
|
var
x = 10;
function
f(){
alert(
this
.x);
}
f();
|
咱们定义了一个全局函数f()。f()经过this关键字访问变量x,可是须要注意的是,咱们不能经过一个对象的实例来调用这个函数。this指向的是什么对象呢?this会指向这个全局对象。咱们的变量x就是在这个全局对象中定义的。上面的代码可以正常运行,运行结果会显示一个对话框,对话框中显示10。函数
咱们能够经过this来调用call()和apply()。正以下面的例子展现如何使用call():this
1
2
3
4
5
6
7
|
var
x = 10;
var
o = { x : 15};
function
f(){
alert(
this
.x);
}
f();
f.call(o);
|
首先调用f()将会显示10的对话框,由于this这个时候指向的是全局对象。而后咱们调用f函数的call()方法,传入的参数是o,运行结果显示的是o中x属性的值15。call()方法会用它的第一个参数做为f函数的this指针。也就是说,咱们会告诉运行时,f函数中的this指向的是哪一个对象。spa
this跳转听起来有些滑稽,甚至对于C++、Java以及C#程序员来讲有些反常。这些都是ECMAScript中有趣的部分。.net
经过call()也能够给函数传递参数:指针
1
2
3
4
5
6
7
|
var
x = 10;
var
o = { x : 15};
function
f(){
alert(
this
.x);
}
f();
f.call(o);
|
apply()和call()相似的,只是apply()要求第二个参数必须是一个数组。这个数组会做为参数传递给目标函数。code
1
2
3
4
5
6
7
8
|
var
x = 10;
var
o = {x : 15};
function
f(message) {
alert(message);
alert(
this
.x);
}
f(
'invoking f'
);
f.apply(o, [
'invoking f through apply'
]);
|
apply()方法是颇有用的,由于咱们能够建立一个函数而不用去关心目标方法的参数。这个函数能够经过apply()的第二个数组参数来传递额外的参数给方法。htm
1
2
3
4
5
6
7
8
9
10
11
12
|
var
o = {x : 15};
function
f1(message1) {
alert(message1 +
this
.x);
}
function
f2(message1, message2) {
alert(message1 + (
this
.x *
this
.x) + message2);
}
function
g(object, func, args) {
func.apply(object, args);
}
g(o, f1, [
'the value of x = '
]);
g(o, f2, [
'the value of x squared = '
,
'. Wow!'
]);
|
这样的语法有点问题。为了调用apply()方法,咱们强制目标函数使用数组中的参数。幸运的是,有一个方法可让这种语法更简单。在此以前,咱们必须先介绍一个:参数标识符。
在JavaScript中,其实每一个函数都有一个可变长度的参数列表。这意味着,即便一个函数只有一个参数的时候,咱们也能够传递5个参数给它。下面的代码不会有错误,并且结果显示的是“H”。
1
2
3
4
|
function
f(message) {
alert(message);
}
f(
'H'
,
'e'
,
'l'
,
'l'
,
'o'
);
|
在f()中,若是咱们不想去接受其余的参数,咱们能够用关键字arguments。arguments表明一个参数对象,它有一个表明长度的属性相似于数组。
1
2
3
4
5
6
7
8
9
|
function
f(message) {
// message的值和arguments[0]是同样的
for
(
var
i = 1; i < arguments.length; i++){
message += arguments[i];
}
alert(message);
}
// 结果显示“Hello”
f(
'H'
,
'e'
,
'l'
,
'l'
,
'o'
);
|
你应该知道,严格来说,arguments不是一个数组。arguments有一个length属性,可是没有split、push、pop方法。在前面的g()函数中,咱们能够从arguments中拷贝须要的参数,组成数组,而后把这个数组传递给apply()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var
o = {x : 15};
function
f(message1, message2) {
alert(message1 + (
this
.x *
this
.x) + message2);
}
function
g(object, func) {
// arguments[0] = object
// arguments[1] = func
var
args = [];
for
(
var
i = 2; i < arguments.length; i++) {
args.push(arguments[i]);
}
func.apply(object, args);
}
g(o, f,
'The value of x squared = '
,
'. Wow!'
);
|
当咱们调用g(),we can pass additional arguments as parameters instead of stuffing the arguments into an array。