var name='window上的name'
var obj ={
name: "obj上的name",
getName: function(i){
console.log(this.name, i);
}
}
var obj2 = {
name: "obj2上的name"
}
1 绑定上下文
Function.prototype.myApply=function(context){
// 获取调用`myApply`的函数本身,用this获取
context.fn = this;
// 执行这个函数
context.fn();
// 从上下文中删除函数引用
delete context.fn;
}
obj.getName(); // obj上的name undefined
obj.getName.myApply(obj2); // obj2上的name undefined
2 给定参数
Function.prototype.myApply=function(context){
// 获取调用`myApply`的函数本身,用this获取
context.fn = this;
//获取传入的数组参数
var args = arguments[1];
//没有传入参数直接执行
if (args == undefined) {
// 执行这个函数
context.fn()
} else {
// 执行这个函数
context.fn(...args);
}
// 从上下文中删除函数引用
delete context.fn;
}
obj.getName(1); // obj上的name 1
obj.getName.myApply(obj2, [2]); // obj2上的name 2
上面用到了es6的扩展元素运算符
下面是不用扩展运算符,使用eval 方法拼成一个函数
eval('context.fn(' + args +')')
args 会自动调用 Array.toString() 这个方法
Function.prototype.myApply=function(context){
// 获取调用`myApply`的函数本身,用this获取
context.fn = this;
//获取传入的数组参数
if (!arguments[1]) {
// 执行这个函数
context.fn();
}
else {
var args = [];
for(var i = 0, len = arguments[1].length; i < len; i++) {
args.push('arguments[1][' + i + ']');
}
// 执行这个函数
eval('context.fn(' + args +')');
}
// 从上下文中删除函数引用
delete context.fn;
}
obj.getName(1); // obj上的name 1
obj.getName.myApply(obj2, [2]); // obj2上的name 2
或者
Function.prototype.myApply=function(context, arr){
// 获取调用`myApply`的函数本身,用this获取
context.fn = this;
//获取传入的数组参数
if (!arr) {
// 执行这个函数
context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
// 执行这个函数
eval('context.fn(' + args +')');
}
// 从上下文中删除函数引用
delete context.fn;
}
3 当传入apply的this为null或者为空时,或函数具有返回值
Function.prototype.myApply=function(context){
// 获取调用`myApply`的函数本身,用this获取,如果context不存在,则为window
var context = context || window;
context.fn = this;
var r;
//获取传入的数组参数
if (!arguments[1]) {
// 执行这个函数
r = context.fn();
}
else {
var args = [];
for(var i = 0, len = arguments[1].length; i < len; i++) {
args.push('arguments[1][' + i + ']');
}
// 执行这个函数
r = eval('context.fn(' + args +')');
}
// 从上下文中删除函数引用
delete context.fn;
return r;
}
obj.getName(1); // obj上的name 1
obj.getName.myApply(null, [2]); // window上的name 2
4 call模拟
Function.prototype.myCall=function(context){
// 获取调用`myApply`的函数本身,用this获取,如果context不存在,则为window
var context = context || window;
context.fn = this;
var r;
//获取传入的数组参数
var args = [];
for(var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
// 执行这个函数
r = eval('context.fn(' + args +')');
// 从上下文中删除函数引用
delete context.fn;
return r;
}
注意:arguments从1开始遍历
参考:https://github.com/axuebin/articles/issues/7
https://github.com/mqyqingfeng/Blog/issues/11