- call
call方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
模拟call的思路:
- 将函数设置成为对象的属性(利用
this的隐式绑定规则) - 执行该函数
- 删除该函数
以上个例子为例,就是:
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn
整理一下代码:
Function.prototype.call2 = function (context) {
var context = context || window;
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')'); // 这句是真的骚,佩服
delete context.fn
return result;
}
// 测试一下
var value = 2;
var obj = {
value: 1
}
function bar(name, age) {
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call2(null); // 2
console.log(bar.call2(obj, 'kevin', 18));
// 1
// Object {
// value: 1,
// name: 'kevin',
// age: 18
// }
- apply
apply的实现跟call类似,在这里直接给代码
Function.prototype.apply = 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函数的三个特点:- 返回一个函数
- 可以传入参数
- 碰到new 关键字this的指向会失效
Function.prototype.bind2 = function (context) {
// 先判断调用自己的是不是函数
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
// 记载下 当前函数
var self = this;
// 拿出除了this指向外的后面的形参
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
var fBound = function () {
// 这个时候的arguments是指bind返回的函数传入的参数
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
// 不处理new 的情况
Function.prototype.bind2 = function () {
var _this = arguments[0];
var args = Array.prototype.slice(arguments, 1);
var fn = this;
return function () {
return n.apply(_this, args.concat(Array.prototype.slice(arguments)));
// 之所以要用到return 是考虑到调用者需要返回什么值
}
}