call
先看call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
两点:
- call 改变了 this 的指向
- 执行了
实现思路, 举个例子:
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
想想: 我们把bar函数挂载到foo下不就行了吗
var foo = {
value: 1,
bar: function() {
console.log(this.value)
}
};
foo.bar(); // 1
ok, 仔细想想, 要求如下:
- 将函数设为对象的属性
- 若传入为null, 指向window
- 可能带有参数
- 执行该函数
- 可能有返回值
- 删除该函数
实现es5:
Function.prototype.call = function (context) {
// 若传入为null, 指向window
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;
}
实现es6:
Function.prototype.call = function (context) {
// 若传入为null, 指向window
var context = context || window;
context.fn = this;
// 拿到参数
var [a, ...args] = [...arguments];
// 执行
var result = context.fn(...args);
// 删除
delete context.fn
// 返回值
return result;
}
apply
与call一致, 只是参数格式是数组而已
bind
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
bind 函数的两个特点:
- 返回一个函数
- 可以传入参数
实现es5:
Function.prototype.bind = function (context) {
var self = this;
// 获取bind2函数从第二个参数到最后一个参数
var args = Array.prototype.slice.call(arguments, 1);
return function () {
// 这个时候的arguments是指bind返回的函数传入的参数
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(context, args.concat(bindArgs));
}
}
实现es6:
Function.prototype.bind = function (context) {
var self = this;
// 获取bind2函数从第二个参数到最后一个参数
var [a, ...args] = [...arguments];
return function () {
// 这个时候的arguments是指bind返回的函数传入的参数
var [a, ...bindArgs] = [...arguments];
return self.apply(context, args.concat(bindArgs));
}
}