The interviewer is very busy, but I am not just a hot spot, the topic of today’s chat is absolutely the knowledge point with a high hit rate in the interview. When I was reviewing javascript functions, I noticed an interesting point about the explicit return constructor, which led to a wave of brainstorming……

We know that the following steps will happen to the new constructor if we do nothing special.

  • First create a new object, the new object’s__proto__Property that points to the constructorprototypeattribute
  • At this point the constructor executes in the environmentthisPoint to this new object
  • Execute the code in the constructor, usually bythisAdds a new member property or method to a new object.
  • Finally, return the new object.

Let’s verify:

function Test() {
  console.log(JSON.stringify(this));
  console.log(this.__proto__.constructor === Test);
  this.name = 'jack';
  this.age = 18;
 console.log(JSON.stringify(this)); } var a = new Test(); // The Chrome console will print the following / / {} // true // {"name":"jack","age":18} Copy the code

That’s exactly what we know. Nothing wrong with it.

Implement a new

So after recognizing the key steps in the new instantiation process, we can also answer a common interview question: How do you implement a new?

Implementing a new means you can’t use the new keyword, so you have to do a series of steps, of course, through functions.

// func is the constructor,... Args are the arguments that need to be passed to the constructor
function myNew(func, ... args) {
  // Create an empty object and specify func.prototype
  var obj = Object.create(func.prototype);
  // The new constructor executes the function and specifies this
func.call(obj, ... args); // Finally return the object  return obj; } Copy the code

With these four key steps as a guide, we quickly wrote the code implementation. From this POINT I can also realize the importance of thinking, don’t be a tool person, code is a tool!

That’s not a problem from the implementation logic, so let’s verify that.

function Test(name, age) {
  this.name = name;
  this.age = age;
}

myNew(Test, 'Ming'.18); // The Chrome console will print the following // Test {name: "小明", age: 18} Copy the code

The constructor returns explicitly

An explicit return is when an Object is returned in the constructor. An explicit return is when an Object is returned in the constructor.

We can try this:

function Test() {
  this.name = 'jack';
  this.age = 18;
  return {
    content: 'I have a freestyle'
 } } new Test(); // The Chrome console will print the following // {content: "freestyle"} Copy the code

How useful is a return of a normal type? Like strings, numbers? Try it.

function Test() {
  this.name = 'jack';
  this.age = 18;
  return 'I have a freestyle'
}
new Test(); // The Chrome console will print the following // Test {name: "jack", age: 18} Copy the code

As you can see, when we return a data of a normal type, it doesn’t affect the result, it still returns the new object from new.

We should also know that the new constructor is designed to create objects. It doesn’t make any sense for you to return a normal type of data such as a string, so our concern should be to return a special object. Please read on.

No new instantiation

By “no new instantiation”, we mean that the object is instantiated without the new keyword (of course, this is not new, just at the call level, the bottom level is still new). We’ve already experienced this with jQuery.

// Instantiate a jQuery object without using new
var ele = jQuery('<div>freestyle</div>');
Copy the code

So how does this dark technology work?

As mentioned earlier, we can return a custom object with an explicit return in the constructor, so there is room here. Let’s take a look at a simple example:

function Shadow() {
  this.name = 'jack';
  this.age = 18;
}

function jQuery() {  return new Shadow(); }  var obj1 = jQuery(); console.log(obj1) // The Chrome console will print the following // Shadow {name: "jack", age: 18} Copy the code

JQuery () uses a trick to instantiate the object. The hidden new Shadow() lets you think you can create an instance without calling new directly.

If we try new jQuery(), we’ll see, “Wow, that’s exactly what jQuery() does!”

var obj2 = new jQuery();
console.log(obj2)
// The Chrome console will print the following
// Shadow {name: "jack", age: 18}
Copy the code

This is because the new constructor explicitly returns new Shadow(), so the result returned is the object instantiated by new Shadow(). Instead of calling jQuery() directly with new, we just execute jQuery() as if it were a normal function. The result is, of course, the object instantiated by new Shadow().

So, new jQuery() and jQuery() are equivalent here.

JQuery has become less and less used, but its design ideas are well worth learning. So what’s so cool about jQuery? It’s a lot of things, chaining, plugins and all of those features that we’ve heard a lot about. Without going too far, let’s take a quick look at how jQuery instantiates.

I’ve got jQuery v1.12.4 code here, which is about 1W lines, which is pretty comfortable.

Scrolling through the pages, I came to line 71 and saw the following code:

jQuery = function( selector, context ) {
  return new jQuery.fn.init( selector, context );
}
Copy the code

Isn’t that what we’re familiar with? Jquery.fn. Init seems to be the Shadow in the example above. It’s starting to look like it, but it’s worth studying.

Why do you want jquery.fn?

Jquery. fn is an alias for jquery. prototype. Refer to line 91 of the source code for this.

jQuery.fn = jQuery.prototype = {
/ /...
Copy the code

How do you ensure that the prototype is pointing?

We know that there is a problem with just using new jquery.fn. init(selector, context). The problem is that the instance is not an instance of jQuery, but an instance of jquery.fn. init. So how to deal with this problem?

If we look at line 2866 of the source code, we can see:

init = jQuery.fn.init = function( selector, context, root ) {
  // Create instance logic
}
Copy the code

The details of how init methods create a jQuery object and what logic they do are not the focus of this article. What we need to focus on is, how does jQuery ensure that the instantiated object’s prototype is pointing correctly? How else would the instantiated object use the various methods mounted on jquery.prototype, such as this.show() and this.hide()?

And then on line 2982, I have the answer:

init.prototype = jQuery.fn;
Copy the code
frigging awesome

Brilliant, this hand fixes the problem perfectly by modifying the operation that the prototype points to. In this way, the instance of new init() is also an instance of jQuery.

jQuery.prototype.init.prototype === jQuery.prototype; // true
var a = $('<div>123</div>')
a instanceof jQuery // true
a instanceof jQuery.fn.init // true
Copy the code

In this way, we can get a basic design idea:

function myModule(params) {
  return new myModule.fn.init(params);
}
myModule.fn = myModule.prototype = {
  constructor: myModule
} myModule.fn.init = function(params) {  // You can perform various operations on instance objects } myModule.fn.init.prototype = myModule.prototype; Copy the code

From there, we can extend the static methods and prototype methods, and the myModule module becomes richer and richer.

The last

Nice, a constructor that got me thinking…… Help me up! I can still learn!

Learn the front end together

This article uses mdnice smart blue theme layout