在一个对象中绑定函数,称为该对象的方法。
在JS中,对象的定义是这样的:
var xiaoming = {
name: '小明',
birth: 1990
};
但是,如果我们给xiaoming
绑定一个函数,就可以做更多的事情。比如, 写个age()
方法,返回xiaoming
的年龄:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age;
xiaoming.age();
this指向当前对象。但是this在JS设计中是一个很坑的东西。要保证this的指向正确,必须用obj.xxx()
的形式调用!
由于这是一个巨大的设计错误,要想纠正可没那么简单。ECMA决定,在strict模式下让函数的this
指向undefined
,因此,在strict模式下,你会得到一个错误:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
var fn = xiaoming.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
而且如果在方法的函数内部再指定函数,this又会指向undefined了(strict模式下)。this只在方法的函数中指向对象本身。
所以一个比较好的办法时,在方法的函数中先用一个变量that捕获this,然后在定义的函数中用that来代替this。
'use strict';
var xiaoming = {
name : '小明',
birth: 1990,
age: function () {
var that = this;//在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth;
}
return getAgeFromBirth();
}
};
xiaoming.age(); //25
apply
虽然在一个独立的函数调用中,根据是否是strict模式,this指向不同的对象,但是其实this指向的对象也是可以控制的。
要指定this指向的对象,可以用函数本身的apply方法,它接收两个参数,一个参数是需要绑定的this
变量,另一个是Array
,表示函数本身的参数。
用apply
修复getAge()
调用:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name : '小明',
birth: 1990,
age: getAge
};
xiaoming.age();
getAge.apply(xiaoming, []);
另一个类似的方法是call()
,唯一区别是:
- apply()把参数打包成
array
再传入; - call()把参数按照顺序传入。
比如调用Math.max(3, 5, 4)
,分别用apply()
和call()
实现如下:
Math.max.apply(null,[3,5,4]); // 5
Math.max.call(null,3,5,4);// 5
对普通函数调用,我们通常把this
绑定为null
。
利用apply()
我们还可以动态改变函数的行为。
JS的所有对象是动态的,即使内置的函数,我们也可以重新指向新的函数。
例如想要统计一个程序中调用了多少次parseInt(),,可以通过替换函数来完成:
'use strict';
car count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function() {
count += 1;
return oldParseInt.apply(null, arguments);// 调用原函数
};
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3