In the actual development process, when a function is wrapped, it is not sure who is calling the external function. When a function is called, it may be a window call, and an error will be reported. Call, apply, and bind are often used to bind this reference.

Function.prototype.call()

The call() method calls a function with a specified this value and arguments supplied separately.

This method is similar to apply(), except that call() accepts several parameters, whereas Apply () accepts an array of parameters.

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

Call can inherit

Inheritance is implemented through the call constructor of the parent class

function Product(name, price) {
    this.name = name;
    this.price = price;
  }
  function Food(name, price) {
    Product.call(this, name, price);
    this.category = 'food';
  }
  var cheese = new Food('feta', 5);
  console.log(cheese)
  // Food { name: 'feta', price: 5, category: 'food' }
Copy the code

Each instance will have the name and price attributes added to the Product constructor, but the category attribute is defined in the respective constructor.

The call method calls an anonymous function

var animals = [
    { species: 'Lion', name: 'King' },
    { species: 'Whale', name: 'Fail'}];for (var i = 0; i < animals.length; i++) {
    (function(i) {
        console.log(The '#' + i + ' ' + this.species + ':' + this.name) }
    ).call(animals[i], i);
  }
Copy the code

Inside the for loop, we create an anonymous function and execute that anonymous function with each array element as the specified this value by calling the call method of that function.

The call method specifies the this of the context

function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}
var obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj);
// cats typically sleep between 12 and 16 hours
Copy the code

Call the principle

Function.prototype.myCall = function(context) {
   context = context ? Object(context) : window
   context.fn = this
   let args = [...arguments].slice(1)
   let r = context.fn(args)
   delete context.fn
   return r
}
Copy the code

Function.prototype.apply()

Apply () calls a function that specifies the value of this, receiving arguments supplied as an array or array-like object

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

Apply adds an array to another array

var array = ['a'.'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.log(array); / / /"a"."b", 0, 1, 2]
Copy the code

Apply finds the maximum and minimum values

var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers)
var min = Math.min.apply(null, numbers);
Copy the code

If the argument group is very large, slice the argument array and loop through the target method:

function minOfArray(arr) {
    var min = Infinity;
    var QUANTUM = 32768;
  
    for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
      var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
      min = Math.min(submin, min);
    }
  
    return min;
  }
  
  var min = minOfArray([5, 6, 2, 3, 7]);
  console.log(min) // 2
Copy the code

Apply the principle of

Function.prototype.myApply = function(context) {
  context = context ? Object(context) : window
    context.fn = this
    let args = [...arguments][1]
    if(! args) {return context.fn()
    }
    let r = context.fn(args)
    delete context.fn;
    return r
 }
Copy the code

Function.prototype.bind()

The bind() method creates a new function that sets the this keyword to the supplied value when called.

And when the new function is called, the given parameter list is taken as the first several items of the parameter sequence of the original function. Bind (thisArg, [arg1[, arg2[,…]]])

Creating a binding function

his.x = 9; // In the browser, this points to global"window"Var module = {x: 81, getX:function() { returnthis.x; }}; module.getX(); // 81 var retrieveX = module.getX; retrieveX(); // Returns 9 - because the function is called in global scope var boundGetX = retrievex.bind (module); // Create a new function'this'Bind to the Module object boundGetX(); / / 81Copy the code

Partial function

function list() {
  return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
    returnarg1 + arg2 } var list1 = list(1, 2, 3); // [1, 2, 3] var result1 = addArguments(1, 2); // 3 // Create a function with a list of default arguments. var leadingThirtysevenList = list.bind(null, 37); Var addThirtySeven = addarguments.bind (null, 37); // Create a function with the default first argument var addThirtySeven = addarguments.bind (null, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3] var result2 = addThirtySeven(5); // 37 + 5 = 42 var result3 = addThirtySeven(5, 10); // 37 + 5 = 42, the second argument is ignoredCopy the code

When fn1.myCall(fn2), bind this to context.fn = this is equivalent to the context.fn = fn1 call when context.fn() is equivalent to fn2.fn() where this is fn2 and fn1 is executed.

When fn1.mycall. myCall(fn2) is, the myCall function is executed, this is window, and fn2 is executed.

Bind the principle


let obj = {
    name: 'joker'
}

function fn() {
    console.log(this.name)
}
Function.prototype.bind = function(context) {

}
let bindFn = fn.bind(obj)
bindFn()
// joker
Copy the code

You can see from the example above

  1. Bind can be used to bindthisExecute as an object passed in
  2. The bind method returns a function (higher-order function) that implements a simplebindmethods
Function.prototype.bind = function(context) {
   let _me = this
    return function() {
        return _me.apply(context)
    }
}
Copy the code

Bind can also pass arguments multiple times.

let obj = {
    name: 'joker'
}

function fn(name, age) {
    console.log(this.name + 'this year' + name + age + 'old')}let bindFn = fn.bind(obj, 'about')
bindFn(10) // Joker is about 10 years old this yearCopy the code

Binding this passes a value, and bindFn passes a parameter, so the previous function needs to be modified

Function.prototype.bind = function(context) {
    let _me = this
    let bindArgs = [].slice.call(arguments, 1) // fetchbindThe parameter passed to the methodreturn function() {
        letFnArgs = [].slice.call(arguments) // Get the arguments passed by the function executionreturn _me.apply(context, bindArgs.concat(fnArgs))
    }
}
Copy the code

If the currently bound function is new, this is used when this is an instance of the current function

let obj = {
    name: 'joker'
}
functionFn (name, age) {console.log(this) // this is fn}let bindFn = fn.bind(obj)
let instance = new bindFn()
Copy the code

If this is an instance of fBound, meaning new, then this is an instance of the function, otherwise context

Function.prototype.bind = function(context) {
    let _me = this
    let bindArgs = [].slice.call(arguments, 1)
    function Fn() {}
    let fBound = function() {
        let fnArgs = [].slice.call(arguments)
        return _me.apply(this instanceof fBound ? this : context, bindArgs.concat(fnArgs))
    }
    Fn.prototype = this.prototype
    fBound.prototype = new Fn();
    return fBound
}
Copy the code

The principle of the new

If you want to understand the principle of new, you need to understand the prototype mechanism of JS

let f1 = new Foo()
Copy the code
  1. f1Is the constructorFooAn instance of the__proto__Point to the prototype of the constructorFoo.prototype
  2. Foo.prototype.constructorPointing constructorFoo.FootheprototypePoint to its prototype
  3. FooThe prototype of the__proto__In the end toObject

The implementation of the new

function Animal(type) {
    this.type = type;
}
Animal.prototype.say = function() {
    console.log('say')}function mockNew() {
    letConstructor = [].shift.call(arguments); // Get the constructorletConstructor. Prototype Constructor. Apply (obj, arguments)return obj
}
let animal = mockNew(Animal, 'dog')
    
console.log(animal.type) // dog
animal.say() // say
Copy the code