apply,call,bind实现原理

155 阅读1分钟
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')())