callfunction

  • Features:
    • 1) We can change the this reference of our current function
    • 2) It also makes the current function execute
Function.prototype.call = function (context) {
 if (typeof this! = ='function') {
    throw new TypeError(`The ${this} is not a function`)
  }
  context = Object(context) || window;
  context.fn = this;
  let args = [];
  for (let i = 1; i < arguments.length; i++) {
    args.push('arguments['+i+'] '); 
  }
  let r = eval('context.fn('+args+') ');
  delete context.fn;
  return r;
}
Copy the code

The title self-test

function fn1() {
  console.log(this.arguments);
  console.log(1);
  
}
function fn2() {
  console.log(this.arguments);
  console.log(2);
}
fn1.call(fn2,1.2); / / fn2 [1, 2] 1
fn1.call.call.call.call.call(fn2,1.2); // {number:1} [2] 2
Copy the code
  • Thinking analytical
    • Fn1. Call (fn2, 1, 2)
      • 1)callPerform incomingfn2.1.2Three parameters
      • 2)callFunction of the internalcontext = Object(fn2) = fn2
      • 3)fn2.fn = fn1
      • 4)Args = [' the arguments [1] 'and' the arguments [2] '] = [1, 2]
      • 5)The eval (' context. Fn (' + args + ') ') = fn2. Fn (1, 2) = fn2. Fn1 (1, 2)
    • Fn1. Call. The call. The call. The call. The call (fn2, 1, 2)
      • 1)callPerform incomingfn2.1.2Three parameters
      • 2)callFunction of the internalcontext = Object(fn2) = fn2
      • 3)fn2.fn = call
      • 4)Args = [' the arguments [1] 'and the arguments [2]] = [1, 2]
      • 5)The eval (' context. Fn (' + args + ') ') = fn2. Fn (1, 2) = fn2. Call (1, 2)
      • 6)callPerform incoming1.2Two parameters
      • 7)callFunction of the internalcontext = Object(1) = Number{1}
      • 8)Number{1}.fn = fn2
      • 9)args=['arguments[1]']=[1]
      • 10)eval('context.fn('+args+')') = Number{1}.fn(2) = Number{1}.fn2(2)
      • Note: Multiple callscall“Is actuallycallIt is called internally again at execution timecall, called twice in total

applyfunction

  • Features:
    • 1) We can change the this reference of our current function
    • 2) It also makes the current function execute
Function.prototype.apply = function (context,args) {
  if (typeof this! = ='function') {
     throw new TypeError(`The ${this} is not a function`)
   }
   context = Object(context) || window;
   context.fn = this;
   if(! args){return context.fn();
   }
   let r = eval('context.fn('+args+') ');
   delete context.fn;
   return r;
 }
Copy the code

newThe operator

  • The characteristics of
    • Freshmen become objects
    • Link to the prototype
    • The bindingthis
    • Return an object
/* * Basic use */
function Animal(type) {
  this.type = type ; 
}
Animal.prototype.say = function () {
  console.log('say');
}
let tiger = new Animal('tiger');
console.log(tiger);
--------------------------------------------------------
The /* * method implements */
function mockNew(){
    let Constructor = [].shift.call(arguments);
    let obj = {}; // Freshmen become objects
    obj.__proto__ = Constructor.prototype; // Link to the prototype
    let r = Constructor.apply(obj,arguments) / / bind ` this `
    return r instance Object ? r : obj; // Return an object
}
let tiger = mockNew(Animal,'tiger');
console.log(tiger);
Copy the code

bindfunction

  • The characteristics of
    • The bindingthisPoint to the
    • Return a bound function (higher-order function principle)
    • If the bound function isnewTo execute the current functionthisIs the current instance
    • newThe result is a prototype of the original class
Function.prototype.bind = function (context) {
  if (typeof this! = ='function') {
    throw new TypeError(`The ${this} is not a function`)}let that = this;
  let bindArgs = Array.prototype.slice.call(arguments.1);
  function Fn() {};function bindFn() {
    let args = Array.prototype.slice.call(arguments);
    /* * Bind 'this' to * if the bound function is executed by' new ', the 'this' of the current function is the current instance */
    that.apply(this instanceof bindFn ? this : context, bindArgs.concat(args)); 
  }
  /* 'new' results can find the original class prototype */
  Fn.prototype = that.prototype; 
  bindFn.prototype = new Fn();
  /* Returns a bound function */
  return bindFn; 
}
Copy the code