Deep understanding of the new operator

In JavaScript, the new operator creates an instance of a user-defined object type or an instance of a built-in object with a constructor. Creating an object is simple, why do we have to use the new operator in one fell swoop? What kind of magic is it?

Meet the new operator

Use the following example to understand the new operator:

function Person (name) {
  this.name = name
}

Person.prototype.getName = function () {
  console.log(this.name)
}

var joe = new Person('joe')

joe.sayHello = function () {
  console.log('Hello!')
}

joe.getName() // joe
joe.sayHello() // Hello!

Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function

Person is an ordinary function, and when it is used with the new operator, Person is a constructor. The new object joe obtained by new Person ('joe') inherits the properties of Person, and at the same time, this also points to the joe instance. The attribute sayHello added for joe does not affect Person, ie joe is a new object that distinguishes from Person.

Therefore, a prototype chain is established between the instance object created by new and the constructor, and the instance object is given the ability to inherit properties through the prototype chain .

The principle and implementation of new

Through the above analysis, the new operator does the following four operations internally:

  • Create an empty simple JavaScript object (ie {});
  • Link the new object (that is, set the constructor of the new object) to the function object;
  • Use the newly created object as the context of this;
  • If the function does not return an object, it returns the newly created object.

The implementation of new is as follows:

function newOperator (ctor, ...args) {
  var obj = {};
  obj.__proto__ = ctor.prototype
  var res = ctor.apply(obj, args)
  return res || obj;
}

Optimize the code:

function newOperator (ctor, ...args) {
  var o = Object.create(ctor.prototype) // 合并第一和第二步:创建一个空的简单 JavaScript 对象(即{}),链接新对象(即设置该新对象的构造函数)到函数对象
  return fn.apply(o, args) || o
}

Use the newOperator function to test the above Person example:

function Person(name) {
  this.name = name
}

Person.prototype.getName = function () {
  console.log(this.name)
}

var joe = newOperator(Person, 'joe')

joe.sayHello = function () {
  console.log('Hello!')
}

joe.getName() // joe
joe.sayHello() // Hello!

Person.sayHello() // Uncaught TypeError: Person.sayHello is not a function

The results are consistent.

A better way to check is:

function Person(name) {
  this.name = name
}

console.log(new Person('joe')) // @1
console.log(newOperator(Person, 'joe')) // @2

The display information of @ 1 and @ 2 in the console is exactly the same.

Guess you like

Origin www.cnblogs.com/jofun/p/12731473.html