banner
Aglorice

Aglorice

Life is a coding,I will debug it.
github
twitter
telegram
bilibili

Explore Constructors and the new Command

1684925475841

It's late at night...

1. Preface#

Before exploring constructors in JavaScript, we need to understand what a constructor is. As the name suggests, its purpose is to construct something. Next, let's see what it constructs.

Before we continue, we need to clarify that a constructor is actually a function, but it has its own characteristics and usage. However, we will find out how to distinguish and use constructors, which cannot be separated from the new keyword in JavaScript.

2. The new Keyword#

When explaining constructors in JavaScript, we cannot bypass its two characteristics:

  1. The this keyword is used inside the function body, representing the object instance to be generated.
  2. When creating an object, the new keyword must be used.

1. Basic Usage of the new Command#

The following is the most basic usage of the new command to instantiate a constructor:

let MyNew = function (){
        this.say_hello = function (){
            console.log('hello world')
        }
    }
let mynew = new MyNew

The above operation uses the new command to make the constructor MyNew generate an instance object, and assigns the result to mynew, so mynew obtains the properties in the constructor.

2. Constructor with Parameters#

In practice, we cannot construct a large number of identical objects with a single constructor, so we can pass parameters when newing a constructor.

let MyNew_1 = function (name){
    this.name = name
}
let mynew_1 = new MyNew_1('张三')
console.log(mynew_1.name) // '张三'

The above operation is to pass the corresponding parameters when instantiating an object using the new keyword.

3. Specifications of the new Keyword#

Because when using the new keyword to instantiate a constructor, it will be automatically executed at the end, so you can find out when using the new keyword.

let mynew_2 = new MyNew_1 // Not recommended

let mynew_3 = new MyNew_1() // Recommended

Although both of the above methods can be used, the second one is more recommended. Compared with the first one, it is easier to identify.

4. Note#

When using a constructor, if we forget to use the new keyword, it will be executed as a function.

let MyNew_1 = function (name){
        this.name = name
}
let test = MyNew_1()
console.log(test.name) // undefined

The reason why undefined is output in the above example is that when MyNew_1 is treated as a function, its scope is global, and the internal this points to window, but window does not declare this variable, so undefined is finally output.

So how can we avoid such things from happening?

  1. Use strict mode

In addition to normal running mode, ECMAScript 5 added a second running mode: "strict mode". As the name suggests, this mode makes Javascript run under stricter conditions.

function Fubar(foo, bar){
    'use strict';
    this._foo = foo;
    this._bar = bar;
}
Fubar()

After using strict mode, if you use a constructor as a function, it will throw an error directly. The result is as follows:

image-20230208230605804

The reason for the error is mainly due to the fact that in strict mode, the this inside the function cannot point to the global object by default, and it is equal to undefined, which causes an error when calling without new (JavaScript does not allow adding properties to undefined).

  1. Use the instanceof keyword

We can use the instanceof keyword to judge.

function Fubar_1(foo, bar) {
    if (!(this instanceof Fubar_1)) {
        return new Fubar(foo, bar);
    }

    this._foo = foo;
    this._bar = bar;
}
console.log(Fubar_1(1, 2)._foo)// 1
console.log((new Fubar_1(1, 2))._foo) // 1

As shown in the above code, we only need to judge whether this is an instance object of Fubar_1 to know whether the constructor uses the new keyword. If not, it will help you new and return the instantiated object.

3. The Principle of the new Keyword#

When we use the new keyword, it actually performs the following steps:

  1. Create an empty object as the object instance to be returned.
  2. Set the prototype of this empty object to the prototype property of the constructor.
  3. Assign this empty object to the this keyword inside the function.
  4. Start executing the code inside the constructor.

The code conversion is as follows:

function _new(/* constructor */ constructor, /* constructor parameters */ params) {
  // Convert the arguments object to an array
  var args = [].slice.call(arguments);
  // Take out the constructor
  var constructor = args.shift();
  // Create an empty object that inherits the prototype property of the constructor
  var context = Object.create(constructor.prototype);
  // Execute the constructor
  var result = constructor.apply(context, args);
  // If the return result is an object, return it directly, otherwise return the context object
  return (typeof result === 'object' && result != null) ? result : context;
}

// Example
var actor = _new(Person, '张三', 28);

Continue to learn more later 🧐🧐🧐

4. Return Values in Constructors#

When there is a return statement in the constructor, we just need to remember that if it returns an object, the final return value will be this object, otherwise it will return this.

let MyNew_2 = function (){
    this.count = 0
    return this.count
}
(new MyNew_2()) === 0 // false
let MyNew_3 = function (){
    this.count = 0
    return {count:this.count}
}
(new MyNew_3()).count === 0 // true

5. new.target#

This is a new property introduced by ECMASript 6. It has two main functions:

  1. When we call a constructor using the new operator, the value of the new.target property is the constructor, otherwise it is undefined.

    function Person (fullName) {
            if (typeof new.target !== 'undefined') {
                this.fullName = fullName;
            } else {
                throw new Error('Person must be called with the new keyword.');
            }
        }
    let student = new Person('aa');
    let student_1 = Person('aa'); // Throws an error
    
  2. It can check whether new.target is called by a specific constructor.

    function Person (fullName, age) {
        if (typeof new.target === Person) {
            this.fullName = fullName;
            this.age = age;
        } else {
            throw new Error('Person must be called with the new keyword.');
        }
    }
    
    function Dog (fullName, age) {
        Person.call(this, fullName, age)
    }
    
    let dog = new Dog('HeHe', 3)
    
    console.log(dog)
    

In es5, if we also want to determine whether a constructor is used, we will think of instanceof for the first time.

Like this:

function Person (name) {
    if(this instanceof Person){
        this.name = name
    } else {
        throw new Error('Not called with new')
    }
}
var person2 = Person('Hello') // Throws an error

With the above operation, we can determine whether the constructor uses the new keyword. However, it is not good enough, for example, in the following example:

function Person (name) {
    if(this instanceof Person){
        this.name = name
    } else {
        throw new Error('Not called with new')
    }
}
var person1 = new Person('Hello')
var person2 = Person.call(person1,'Hello') // Executes normally

In the above code, using the call method sets this to an instance of person1. For the function itself, it is impossible to distinguish whether Person.call or the new keyword obtains an instance of Person. However, this can be achieved through new.target 😍😍😍

6. References#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.