乐趣区

手动实现call和apply方法

call 实现

语法:
fun.call(thisArg, arg1, arg2, ...)

参数:
thisArg

  • 在 fun 函数运行时指定的 this 值。if(thisArg == undefined|null) this = window,if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()

arg1, arg2, ...

  • 指定的参数列表。
Function.prototype.call2 = function (thisArg) {if (thisArg === undefined || thisArg === null) {thisArg = window;} else {switch (typeof thisArg) {
            case 'number':
                thisArg = new Number();
                break;
            case 'boolean':
                thisArg = new Boolean();
                break;
            case 'string':
                thisArg = new String();
                break;
        }
    }

    thisArg.fn = this;

    let result;
    if (arguments.length <= 1) {result = thisArg.fn();
    } else {let args = [];
        for (let i = 1; i < arguments.length; i++) {args.push('arguments[' + i + ']');
        }
    
        result = eval(`thisArg.fn(${args})`)
    }

    delete thisArg.fn;
    return result;
}

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {Product.call2(this, name, price);
  this.category = 'food';
}

function Toy(name, price) {Product.call2(this, name, price);
  this.category = 'toy';
}

var cheese = new Food('feta', 5);
console.log('cheese:', cheese);
var fun = new Toy('robot', 40);
console.log('fun:', fun);

apply 实现

语法:
func.apply(thisArg, [argsArray])

参数:
thisArg

  • 可选的。在 func 函数运行时使用的 this 值。请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。

argsArray

  • 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。从 ECMAScript 5 开始可以使用类数组对象。浏览器兼容性 请参阅本文底部内容。
Function.prototype.apply2 = function (thisArg, argsArray) {
    thisArg = thisArg || window;
    thisArg.fn = this;

    let result;
    if (!argsArray) {result = context.fn();
    } else {var tempArgs = [];
        for (var i = 0, len = argsArray.length; i < len; i++) {tempArgs.push('args[' + i + ']');
        }
        result = eval(`thisArg.fn(${tempArgs})`)
    }
    
    delete thisArg.fn;
    return result;
}

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {Product.apply2(this, [name, price]);
  this.category = 'food';
}

function Toy(name, price) {Product.apply2(this, [name, price]);
  this.category = 'toy';
}

var cheese = new Food('feta', 5);
console.log('cheese:', cheese);
var fun = new Toy('robot', 40);
console.log('fun:', fun);

总结

实现难点:

  1. 需要考虑传入的 thisArg 的多种类型
  2. 将函数设置成 thisArg 的属性,来实现 this 的绑定,调用完成后需要 delete 该属性
  3. 使用 eval 来实现需要传参给该函数的情况
退出移动版