一:call方法
- es6实现
Function.prototype.myCall = function(content, ...args){
content = content || window;
content.fn = this;
const res = content.fn(...args);
delete content.fn;
return res;
};
- es5实现
Function.prototype.myCall = function (context) {
context = context || window;
context.fn = this;
var args = [];
for(let i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context.fn(' + args +')');
delete context.fn;
return result;
}
二:apply方法
- es6实现
Function.prototype.myApply = function (content, args) {
content = content || window;
content.fn = this;
const res = content.fn(...args);
delete content.fn;
return res;
};
- es5实现
Function.prototype.myApply = function (content, arr=[]) {
content = content || window;
content.fn = this;
var args = [];
for(var i=0; i<arr.length; i++){
args.push("arr["+i+"]")
}
var res = eval("content.fn("+args+")");
delete content.fn;
return res;
};
三:bind方法
注意点:bind返回的函数可通过new实例化(需要确保bind后的函数与原函数在同一原型链)
Function.prototype.myBind = function (content) {
const args = Array.prototype.slice.call(arguments, 1); // bind层参数
const func = this;
const bindFunc = function () {
func.apply(content, args.concat([...arguments]))
};
bindFunc.prototype = Object.create(func.prototype);
return bindFunc
};
四:上面用到了Object.create方法
简单实现:
Object.create = function(proto){
function F() {};
F.prototype = proto;
F.prototype.constructor = F;
return new F();
}
五:实现call,apply存在小瑕疵
content.fn = this; // 原来对象中可能就存在 fn 属性,会存在覆盖
/* ---> 替换 */
const fn = Symbol("fn");
content[fn] = this;