模擬實現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…
相關文章
相關標籤/搜索