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
- Bind can be used to bind
this
Execute as an object passed in - The bind method returns a function (higher-order function) that implements a simple
bind
methods
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
f1
Is the constructorFoo
An instance of the__proto__
Point to the prototype of the constructorFoo.prototype
Foo.prototype.constructor
Pointing constructorFoo
.Foo
theprototype
Point to its prototypeFoo
The 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