call和apply
作用:调用一个对象的一个方法,以另一个对象替换当前对象。
区别:调用参数形式不同。(call参数依次给出,apply通过Array对象传入)
this:谁调用我,我就指向谁
首先看个调用call的栗子:
var foo = {
value: 1
};
function fn() {
console.log(this.value);
}
fn.call(foo); // 1
注意:
1、call改变了this的指向,指到foo
2、fn函数执行
即可将上面的代码改变成下面这种形式:
var foo = {
value: 1,
fn: function() {
console.log(this.value)
}
};
foo.fn(); // 1
即将fn作为对象foo的属性,然后进行调用。
则可总结出模拟实现的步骤:
1、将函数设置为对象的属性,注意该函数逇参数处理。
2、执行该函数;
3、删除该函数。
故call的模拟实现如下:
Function.prototype.myCall = function (context) {
var context = context || window; //如果this参数传的是null,则此处指向window
context.fn = this; //获取调用myCall的函数,因为最后是函数调用myCall,this指向该函数,故this可获取
var args = []; //用来接收函数的参数
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}//函数的参数第一个是this的指向,第二个以后才是自己的参数,故从1开始循环存入参数
var result = eval('context.fn(' + args +')');//args可自动调用Array.toString()方法
delete context.fn;
return result; //函数的返回值
}
apply的实现跟call类似,只是后面的参数为一个数组,实现方法如下:
Function.prototype.myApply = function (context, arr) {
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) { //如果函数没有其他参数
result = context.fn();
}
else {
var args = []; //此处直接获取传入的数组的值
for (var i = 0, len = arr.length; i len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn;
return result;
}
bind:bind() 方法会创建一个新函数。
当这个新函数被调用时,bind()的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
特点:
1. 返回一个函数
2. 可以传入参数
根据这两个特点可模拟如下:
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
} //如果调用bind的不是函数则报错
var self = this; //self指调用该方法的函数
var args = Array.prototype.slice.call(arguments, 1);//获取bind2函数从第二个参数到最后一个参数
var fNOP = function () {};
//用一个空函数作为中转,将fbound.prototype = this.prototype
var fbound = function () {
self.apply(this instanceof self ? this : context,args.concat(Array.prototype.slice.call(arguments)));
}
//当作为构造函数时,this指向实例,self指向绑定函数,当结果为true时,this指向实例
//当作为普通函数时,this指向window,self指向绑定函数,当结果为false时,this指向绑定的context
fNOP.prototype = this.prototype;
fbound.prototype = new fNOP();
//修改返回函数的prototype为绑定函数的prototype,实例就可以继承函数原型中的值
return fbound;
}