模拟实现call和apply

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数git

上面是 call 的定义,apply 与 call 相似只是第二个参数是一个数组而 call 接收的则是一个参数列表。github

看一个例子数组

var obj = {
  name: "obj"
};
function foo() {
  return this.name;
}
foo.call(obj); //obj
复制代码

上面经过 call 改变了 this 的指向,下面就是模拟实现app

实现

call 和 apply 是 es5 的方法,既然是模拟实现那确定不能用 es5 方法了,咱们先分析一下怎么来指定 this,this 跟动态做用域相似是在执行时肯定,那咱们在指定 this 的属性上添加一个方法而且执行,那么这个方法的 this 就是指定 this函数

var obj = {
  name: "obj",
  foo: function foo() {
    return this.name;
  }
};

obj.foo();
复制代码

上面解决了this,下面来看下怎么实现参数的传递,call 方法能够传递任意参数列表,咱们能够经过arguments来获取,它是一个类数组。测试

function getName() {
  console.log(arguments); //Arguments(5) [1, 2, 3, 4, 5]
}
function foo() {
  var args = [];
  for (var i = 0; i < arguments.length; i++) {
    args.push("arguments[" + i + "]");
  }
  eval("getName(" + args + ")");
}
foo(1, 2, 3, 4, 5);
复制代码

OK,这两块已经搞定了,下面就是实现ui

call

Function.prototype.calls = function(con) {
  con.fn = this;
  // 获取参数
  var args = [];
  for (var i = 1; i < arguments.length; i++) {
    args.push("arguments[" + i + "]");
  }
  var result = eval("con.fn(" + args + ")");
  delete con.fn;
  return result;
};
复制代码

上面删除属性是为了不污染,这里的fn能够是任意属性名只要保证不重复就好了,不过仔细观察上面函数仍是有问题this

  1. call 的 this 能够是 null 或者 undefined
  2. 能够是字符串数字之类的,会转化为包装对象;
Function.prototype.calls = function(con) {
  if (con == null) {
    con = typeof window === "object" ? window : global;
  }
  con = Object(con);
  con.fn = this;
  // 获取参数
  var args = [];
  for (var i = 1; i < arguments.length; i++) {
    args.push("arguments[" + i + "]");
  }
  var result = eval("con.fn(" + args + ")");
  delete con.fn;
  return result;
};
复制代码

测试一下es5

function foo() {
  return this.length;
}
console.log(foo.calls("obj")); // 3
复制代码

撒花,这样就实现了 callspa

apply

与 call 十分相似,这里就直接贴代码了

Function.prototype.applys = function(con, arr) {
  if (con == null) {
    con = typeof window === "object" ? window : global;
  }
  con = Object(con);
  con.fn = this;
  var result;
  if (typeof arr === "object" && arr.length) {
    var args = [];
    for (var i = 0; i < arr.length; i++) {
      args.push("arr[" + i + "]");
    }
    result = eval("con.fn(" + args + ")");
  } else {
    result = eval("con.fn()");
  }
  delete con.fn;
  return result;
};
复制代码

参考

  1. developer.mozilla.org/zh-CN/docs/…
  2. github.com/mqyqingfeng…
相关文章
相关标签/搜索