Manual implementation of call and apply methods

call implementation

Syntax:
fun.call(thisArg, arg1, arg2, ...)

Parameters:
thisArg

  • This value is specified when the fun function runs. If (thisArg = undefined | null) this = window, if (thisArg = number | Boolean | string) this = new Number ()| new Boolean ()| new String ()

arg1, arg2, ...

  • List of specified parameters.

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 implementation

Syntax:
func.apply(thisArg, [argsArray])

Parameters:
thisArg

  • Optional. This value is used when the func function runs. Note that this may not be the actual value that this method sees: if the function is in a non-strict mode, null or undefined will be automatically replaced by pointing to the global object, and the original value will be wrapped.

argsArray

  • Optional. An array or class array object in which the array elements are passed to the func function as separate parameters. If the value of this parameter is null or undefined, it means that no parameters need to be passed in. Class array objects can be used starting with ECMAScript 5. See the bottom of this article for browser compatibility.

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);

summary

Difficulties in implementation:

  1. Consider the various types of thisArg that are passed in
  2. Set the function as the property of thisArg to implement the binding of this. After the call is completed, delete the property is required.
  3. Use eval to implement the case where you need to pass parameters to the function

Tags: Javascript ECMAScript

Posted on Sun, 06 Oct 2019 19:50:59 -0700 by gojakie