apply,call,bind实现原理
思路来源冴羽的博客
前置代码:
var param = "window";
var foo = {param: "foo value"};
function bar(height, width) {
return {
height,
width,
param: this.param
}
}
apply实现
bar.apply(foo, ['this is height', 'this is width'];// 改变bar的this指向,指向foo
相当于========
var foo = {
param: "foo value",
bar: function (height, width) {
return {
height,
width,
innerparam: this.param // bar的this指向foo
}
}
}
思路:将bar作为foo的元素,传入参数(参数的长度是不确定的),执行bar函数得到返回值
Function.prototype.myApply = function (context) {
var context = context || window; // 当myApply第一个参数传null,默认指向window
context.fn = this; // 此时的this指向bar
var args = [];
var param = arguments[1] // 取传入参数['kenvin',18]
for (let i = 0; i < param.length; i++) {
args.push('param[' + i + ']'); // 字符串拼接将'param[0]','param[1]'当作字符串使用eval执行
};
var result = eval('context.fn(' + args + ')');
delete context.fn
return result
}
======== or
Function.prototype.myApply = function (context,arr) {
var context = context || window;
context.fn = this; // context.fn = bar;
var args = [];
for (let i = 0; i < arr.length; i++) {
args.push('arr[' + i + ']');
};
var result = eval('context.fn(' + args + ')');
delete context.fn
return result
}
console.log(bar.myApply(foo, ['this is height', 'this is width']));
call实现(思路同apply)
Function.prototype.myCall = function (param) {
var param = param || window;
param.fn = this;
var args = [];
for (var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('param.fn(' + args + ')');
delete param.fn;
return result;
}
=========or
Function.prototype.myCall = function(param, ...args) {
let param1 = param || window;
param1.fn = this;
let result = param1.fn(...args);
delete param1.fn;
return result
}
bind的传参和call相同,返回一个函数
Function.prototype.myBind = function () {
let _this = this
let context = [].slice.call(arguments)[0]
let param = [].slice.call(arguments).slice(1)
return function() {
return _this.myCall(context,...param)
}
}
console.log(bar.myBind(foo, 'height', 'width')())