手写一个Call函数
1、call的实现
定义:
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
使用方法:
const foo = {
name: 'kaiwen'
}
const getName = function() {
console.log(this.name)
}
getName.call(foo) // kaiwen
可以看出:call改变了this的指向并执行了getName
实现的思路:
首先,我们可以把getName加到foo对象当中,这样就完成了this的绑定,然后在函数内部执行getName,执行完成后为了避免影响对象,再用delete把该函数删掉。
实现代码:
Function.prototype.myCall = function(obj) {
obj.fn = this // this指代当前函数
const res = obj.fn() // 执行函数返回结果
delete obj.fn // 删除函数
return res
}
这样就完成了一个简易版的call,但call应该要支持传参,例如:
const foo = {
name: 'kaiwen'
}
const getName = function(age) {
console.log(this.name)
console.log(age)
}
getName.call(foo, 19) // kaiwen 19
这里可以选择es6的...运算符。
Function.prototype.myCall = function (params, ...args) {
// 获取函数
params['fn'] = this
const res = params.fn(...args)
// 删除函数
delete params['fn']
return res
}
es3的实现方法:
Function.prototype.call2 = function(context) {
context.fn = this;
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
const res = eval('context.fn(' + args +')');
delete context.fn;
return res
}
要注意一下this的值可以为null,当为null的时候指向window。
最终版:
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;
}
参考文章:JavaScript深入之call和apply的模拟实现
手写一个Apply
1、apply与call的区别:主要是在传参上有区别,apply需要的参数为一个数组。这里直接给出参考代码。
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
Function.prototype.bind = function(){
const fn = this, // 保存函数
args = Array.prototype.slice.call(arguments), // 参数
object = args.shift(); //绑定对象
return function(){
return fn.apply(object,args.concat(Array.prototype.slice.call(arguments)));
};
};