JavaScript 中apply()、call()和bind()方法的使用

时间:2023-01-01 09:28:20

apply()和call()

我们可以将call()和apply()看做是某个对象的方法,通过调用此方法来简介调用函数。
call()和apply()两个方法实际上差别不大,只是在方法的第二个参数类别上有区别,call()第二个参数为一系列参数,而apply()第二个参数为一个数组,即如下所示。

f.call(obj,1,2,...);
f.apply(obj,[1,2,...]);

这是这两个方法的参数区别,他们第一个参数调用上下文实参,估计很多朋友都不理解上下文实参是个啥,其实这也是我看的书上这么说的,我的理解就是传入一个对象,这个对象决定了此方法使用时候的上下文。
下面介绍几个例子来说明:

    function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.showName = function() {
console.log('Person showName -' + this.name);
};
Person.prototype.setName = function(name) {
this.name = name;
console.log('setName-' + name);
};
Person.prototype.showAge = function() {
console.log('Person showAge - ' + this.age)
};

function Women(name,age) {
Person.call(this,[name,age]);//this Women对象调用Person中所有方法
this.sex = 'male';
}
Women.prototype = Person.prototype;
Women.prototype.showSex = function() {
console.log('Women showSex-' + this.sex)
};
Women.prototype.showName = function() {
console.log('Women showName - ' + this.name);
};

var women = new Women('cyl', 22);
women.showName();
women.showSex();
women.setName('sf');//此处更改this.name调用了Person.setName()的方法
women.showName();
//Women showName - cyl,22
//Women showSex-male
//setName-aaa
//Women showName - sf
//将对象o中名为m()的方法替换为另一个方法
//可以在调用原始的方法之前和之后记录日志消息
function trace(o, m){
var original = 0[m]; //在闭包中保存原始方法
o[m] = function(){ //定义新的方法
console.log(new Date(), "Entering:", m);//输出日志信息
var result = original.apply(this, arguments);//调用原始函数
console.log(new Date(), "Exiting:", m);
return result;
};
}

trance()函数接收两个参数,一个对象和一个方法名,它将指定的方法替换为一个新方法,这个新方法是“包裹”原始方法的另一个泛函数。这种动态修改已有方法的做法有时候也成为“monkey-patching”。

bind()方法
这个方法的主要作用就是将函数绑定到某个对象上,一个函数调用bind()方法将返回一个新的函数。举个例子吧:

function f(y){return this.x + y;}   //这个是待绑定的函数
var o = {x: 1}; //将要绑定的对象
var g = f.bind(o); //通过调用g(x) 来调用 o.f(x)
g(2); // => 3

可以通过如下代码轻易实现这种绑定:

//返回一个函数,通过调用它来调用o中的方法f()
//传递它所有实参
function bind(f, o){
if(f.bind) return f.bind(o);//如果bind方法存在的话使用bind方法
else return function(){
return f.apply(o,arguments);
}
}

当然bind()方法不仅仅是将函数绑定值一个对象,它还附带一些其他的应用:除了第一个实参之外,传入bind()的实参也会绑定值this,之歌附带的应用是一种常见的函数式编程技术,有时也被成为“柯里化(currying)”。参考下面的例子中的方法的实现:

    var sum = function(x, y) {
//返回两个实参的和值
return x+y;
}
//创建一个类似sum的新函数,但是this的值绑定到null
//并且第一个参数绑定到1, 这个心的函数期望只传入一个实参
var succ = sum.bind(null, 1);
succ(2) // =>3 x 绑定到 1, 传入2作为实参

function f(y, z) {
return this.x + y+ z;
}
var g = f.bind({x:1},2);
g(3) // =>6 this.x 绑定到{x:1}.x =1 y绑定到2, z传入3作为实参