I’ll write the 1 out front

The apply, call, and bind methods in Javascript are very important concepts in front-end code development and are closely related to the orientation of this. In this article we’ll delve into the power of this keyword and try to write a manual replay.

Before reading the article, we carry out research with a few questions:

  • What kind of ideas can be used to new keywords?
  • What are the differences between apply, bind, and call?
  • How to manually implement an Apply, bind, and call?

2 new keywords

The new keyword executes a constructor that returns an instance object and determines whether it is acceptable to pass the argument.

2.1 Principle of New

Instantiate an object using new by:

  1. Create a new empty object, {}
  2. Assign the scope of the object’s constructor to the new object, this pointing to the new object (that is, the new object as the context of this)
  3. Execute the code in the constructor to add attributes to the new object
  4. If the object constructor does not return an object, return this
function Person(){ this.name = "yichuan" } const p = new Person(); console.log(p.name); //"yichuan"Copy the code

We can see that when instantiated with new, we can point the constructor’s this to the new object P. When new is not used, the constructor’s this points to the window.

function Person(){ this.name = "yichuan" } const p = Person(); console.log(p); //undefined console.log(name); //"yichuan" window.name console.log(p.name); //"yichuan" is undefinedCopy the code

When we directly return an object unrelated to this in a constructor, we use the new keyword to instantiate the object. The newly generated object is the object returned by the constructor, not the object of the constructor’s this.

function Person(){ this.name = "yichuan"; return {age:18}; } const p = new Person(); console.log(p); //{age:18} console.log(p.name); //"undefined" console.log(p.age); / 18Copy the code

In addition, when the constructor returns not an object but the value of the underlying data type, using new to create a new object gives the value returned by the constructor to the new object as an object.

function Person(){ this.name = "yichuan"; return "onechuan"; } const p = new Person(); console.log(p); //{name:"yichuan"} console.log(p.name); //"yichuan"Copy the code

The execution of the new keyword always returns an object, either an instance or the object specified by the return statement.

2.2 Implementation of handwriting New

What roughly does new do when it’s called?

  1. Give instances access to private properties
  2. Give instances access to properties on the constructor. Prototype chain
  3. The last result returned by the constructor is a reference data type
function new_object(ctor,... Args){// If (typeof ctor! == "function"){ throw "ctor must be a function"; } // Create an empty Object const obj = new Object(); __proto__ = object.create (ctor. Prototype); Const res = ctor.apply(obj,... args); Const isObject = typeof res === "object" && typeof res! == null; const isFunction = typeof res === "function"; return isObject || isFunction ? res : obj; }Copy the code

Of course, we can also optimize the following:

Const ctor = [].shift.call(arguments); function new_object() {// const ctor = [].shift.call(arguments); Const obj = object.create (ctor. Prototype); const obj = object.create (ctor. Prototype); Const ret =ctor.apply(obj, arguments); const ret =ctor.apply(obj, arguments); Return ret instanceof Object? ret : obj; };Copy the code

3Apply, bind, and call

Apply, bind, and call are the three methods that mount the Function object, and they must be called by a Function.

3.1 the apply

The apply() method calls a function with a given this value and the arguments supplied as an array (or array-like object). The apply() method changes the orientation of this and executes the function immediately.

Note: Chrome 14 and Internet Explorer 9 still don’t accept array-like objects. If an array-like object is passed in, they throw an exception.

func.apply(thisArg, [param1,param2,...] );Copy the code

When using Apply, this of func is changed to point to thisArg, and then [param1,param2,…] Parameter arrays are input as parameters.

func(["red","green","blue"]);
func.apply(newFun, ["red","green","blue"]);
Copy the code

We can see that when both funcs are executed, the first func function’s this points to the window global object and the second func function’s this points to newFun.

Function.prototype.apply = function (context, arr) { context = context ? Object(context) : window; context.fn = this; let result; If (! arr) { result = context.fn(); } else { result = context.fn(... arr); } // const result = eval("context.fn(... arr)"); delete context.fn return result; }Copy the code

3.2 the bind

The bind() method creates a new function, and when bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function.

bind(thisArg,param1,param2,...) ;Copy the code

Bind does not need to execute the result directly. Instead, bind returns the result as a function, and then executes the result.

Bind is called by specifying a new object called this, passing in an argument that returns a defined function, and then using a call called Currization. Similarly, we can manually wrap a bind function based on these features:

Function.prototype.bind = Function (context){// If (typeof this! == "function"){ throw new Error("this bind function must be userd to function"); } // Store this to const self = this; / / the context is the target of a new object this, and parameters is after the first parameter of const args = Array. The prototype. Slice. The call (the arguments, 1); // Create an empty object const funBind = function(){} // return a function const funBind = function() Array.prototype.slice.call(arguments); // Merge the passed arguments into a new array of arguments, as the second argument to self.apply() return self.apply(this instanceof fun? this : context, args.concat(bindArgs)); / * * * * * * * * * * * * * * * * * * * * * * that * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /} / / empty object prototype to binding function prototype fun. The prototype = this. The prototype; Prototype funBind. Prototype = new fun(); return funBinf; }Copy the code

Supplementary notes:

  • this instanceof funWhen it returns true, fun is a constructor whose this refers to the instance and takes context directly as an argument
  • this instanceof funReturns false to indicate that fun is a normal function, whose this refers to the top-level object Window, and which binds the function to context

Of course, we could also write it like this:

Function.prototype.bind = function(context,... If (typeof this! Args){// If (typeof this! == "function"){ throw new Error("this bind function must be userd to function"); } // Store this to const self = this; const fBind = function(){ self.apply(this instanceof self ? this: context, args.concat(Array.prototype.slice.call(arguments))); } if(this.prototype){ fBind.prototype = Object.create(this.prototype); } return fBind; }Copy the code

Note: Object.create() is a new feature introduced by es2015 syntax and is therefore not supported in IE<9 browsers.

3.3 the call

The call() method calls a function with a specified this value and one or more arguments given separately. Call the return value of the function with the this value and arguments provided by the caller. If the method returns no value, undefined is returned.

function.call(thisArg, param1, param2, ...)
Copy the code

Note: The syntax and actions of this method are similar to those of apply(), except that call() accepts a list of arguments, while apply() accepts an array of arguments.

Implementation of the call function:

Function.prototype.call = function(context,... Args) {/ / set the function attributes of the object to the context = context | | window; context.fn = this; Const result = eval("context.fn(... args)"); // Delete the object property delete context.fn; return result; }Copy the code

4 Reference Article

  • Parse the bind principle and Implement it by Hand
  • Parse the Call/Apply principle and write the Call/Apply Implementation by hand
  • The Core Principles of Javascript

5 at the end

In this article, we know that the difference between apply, bind, and call is:

  • When apply or call changes this, it calls the function immediately and returns the result of execution
  • Bind, after changing this, returns a function that needs to be called again
  • Both bind and call pass the first argument to the object to which this will point, followed by a case-by-case input
  • The first argument passed by apply is also the object to which this will point, and the second argument passed after that is an array of arguments