preface

Hi, I’m Wakawa. This is the first part of the interviewers’ questions series, which aims to help readers improve the basic knowledge of JS, including new, call, apply, this, inheritance related knowledge.

The interviewer asked the following article series: Interested readers can click here to read it.

Q: Can you simulate the JS new operator? Q: can you simulate the JS call and apply methods? Interviewer: JS inheritance

Those of you who have used Vuejs know that you need to instantiate with the new operator.

new Vue({
    el: '#app',
    mounted(){},
});
Copy the code

Then the interviewer may ask if they have thought about itnewWhat did you do and how do you simulate it.

There are already many articles that simulate the new operator, so why write it again? Learning is like a mountain. People climb the mountain along different paths and share the scenery they see. You may not be able to see the scenery others see, feel the mood of others. Only oneself go climbing, can see different scenery, experience is more profound.

What does New do

Let’s start with simple example 1:

Function Student(){} var Student = new Student(); console.log(student); // {} // Student is an object. console.log(Object.prototype.toString.call(student)); // [object object] new object (); // By the way, 'new Object' (not recommended) and Object() also have the same effect. // You can guess that the internal judgment is made, using new call /** if (! (this instanceof Object)) { * return new Object(); * } */ var obj = new Object(); console.log(obj) // {} console.log(Object.prototype.toString.call(student)); // [object Object] typeof Student === 'function' // true typeof Object === 'function' // trueCopy the code

From this example, we can see that a function usesnewOperator to generate a completely new object. andStudentandObjectIt’s all functions, it’s justStudentIt’s our custom,ObjectisJSIt’s built-in. Take a look at the console output, interested readers can try on the console.new Object()The generated objects are differentnew Student()There is also a layer nested between the generated objects__proto__, it’sconstructorisStudentThis function.

// constructor === student; Student.prototype.constructor === Student;Copy the code

Summary 1: From this simple example,newThe operator does two things:

  1. A completely new object is created.
  2. This object will be executed[[Prototype]](i.e.__proto__Links).

Let’s take a look at the upgraded version of example 2:

Function Student(name){console.log(' before assignment -this', this); // {} this.name = name; Console. log(' after assignment -this', this); // {name: 'wakawa '}} var student = new student (' wakawa '); console.log(student); // {name: 'ruokawa '}Copy the code

We can see that this in the Student function refers to the object Student generated by new Student().

Summary 2: From this example,newThe operator does one more thing:

  1. The generated new object is bound to the function callthis.

Let’s move on to the upgraded version of Example 3:

Function Student(name){this.name = name; // this.doSth(); } Student.prototype.doSth = function() { console.log(this.name); }; Var student1 = new Student(' if '); Var student2 = new Student(' student2 '); console.log(student1, student1.doSth()); // {name: 'if '}' if 'console.log(student2, student2.dosth ()); / / {name: 'sichuan'} 'sichuan' student1. __proto__ = = = Student. The prototype; // true student2.__proto__ === Student.prototype; // __proto__ is the browser implementation of the view prototype scheme. Object.getprototypeof (student1) === student.prototype; // true Object.getPrototypeOf(student2) === Student.prototype; // trueCopy the code

On the JS prototype relationship before the author saw this picture, feel very good, share to everyone.

Summary 3: This example 3 proves once againSummary 1In theThe second point. So this object is going to be executed[[Prototype]](i.e.__proto__Links). And throughnew Student()Each object created will eventually be[[Prototype]]Link to thisStudent.protytypeOn the object.

Careful students may notice that none of the functions in these three examples return a value. So what happens if you have a return value. So let’s look at example 4

Function Student(name){this.name = name; // Null (Null) // Undefined (Undefined) // Number (Number) 1 // String '1' // Boolean (Boolean) true // Symbol (Symbol) Function (){} // Array [] // Date() new Date() // RegExp (regular expression) /a/ // Error New Error() // return /a/; } var student = new student (' wakawa '); console.log(student); {name: 'wakawa '}Copy the code

After testing these seven types of MDN JavaScript types, I found that the first six basic types all return {name: ‘Ruokagu ‘}, and the following objects (including Functoin, Array, Date, RegExg, Error) all return these values directly.

Conclusion 4:

  1. If the function does not return an object typeObject(including,Functoin.Array.Date.RegExg.Error), thennewThe function call in the expression automatically returns the new object.

Combining these summaries, they add up to:

  1. A completely new object is created.
  2. This object will be executed[[Prototype]](i.e.__proto__Links).
  3. The generated new object is bound to the function callthis.
  4. throughnewEach object created will eventually be[[Prototype]]Link to this functionprototypeOn the object.
  5. If the function does not return an object typeObject(including,Functoin.Array.Date.RegExg.Error), thennewThe function call in the expression automatically returns the new object.

New Simulation implementation

Knowing these phenomena, we can simulate the implementation of the new operator. Post code and comments directly

/ simulation to realize the new operator * * * * @ param {Function} ctor/constructor * @ return {Object | Function | Regex | Date | Error} [return results] * / Function newOperator(ctor){ if(typeof ctor ! == 'function'){ throw 'newOperator function the first param must be a function'; } // ES6 new.target refers to the constructor newoperator. target = ctor; Create a new object, // 2. Execute the [[Prototype]] link // 4. Each object created with 'new' will eventually be linked to the function's 'Prototype' object by '[[Prototype]]'. var newObj = Object.create(ctor.prototype); ES6 [...arguments], Aarry. From (arguments); Var argsArr = [].slice.call(arguments, 1); var argsArr = [].slice.call(arguments, 1); // 3. The generated new object is bound to the function call 'this'. Var ctorReturnResult = ctor.apply(newObj, argsArr); Typeof NULL is also 'Object', so it is not equal to null. Null var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult! == null; var isFunction = typeof ctorReturnResult === 'function'; if(isObject || isFunction){ return ctorReturnResult; } // 5. If the function does not return the Object type 'Object' (including 'Functoin', 'Array', 'Date', 'RegExg', 'Error'), then the function call in the 'new' expression automatically returns the new Object. return newObj; }Copy the code

Finally, verify example 3 with the simulated newOperator function:

Function Student(name, age){this.name = name; this.age = age; // this.doSth(); // return Error(); } Student.prototype.doSth = function() { console.log(this.name); }; Var student1 = newOperator(Student, 'if ', 18); Var student2 = newOperator(Student, student2, 18); // var student1 = new Student(' if '); // var student2 = new Student(' chuan '); console.log(student1, student1.doSth()); // {name: 'if '}' if 'console.log(student2, student2.dosth ()); / / {name: 'sichuan'} 'sichuan' student1. __proto__ = = = Student. The prototype; // true student2.__proto__ === Student.prototype; // __proto__ is the browser implementation of the view prototype scheme. Object.getprototypeof (student1) === student.prototype; // true Object.getPrototypeOf(student2) === Student.prototype; // trueCopy the code

As you can see, it fits well with the new operator. Readers are welcome to point out any shortcomings or improvements they find. If you look back at the simulated new operator implementation, the biggest credit belongs to the OBJECT.create () API provided by ES5.

Object.create() Example usage

As I mentioned in a previous article, you can look at all the API parsing of JavaScript objects

MDN Object.create()

The object.create (proto, [propertiesObject]) method creates a new Object, using an existing Object to provide the __proto__ of the newly created Object. It takes two arguments, but the second optional argument is the property descriptor (less commonly used; the default is undefined).

Var anotherObject = {name: 'ruokawa'}; Var myObject = object.create (anotherObject, {age: {value: 18,},}); GetPrototypeOf (anotherObject) === object.prototype; // getPrototypeOf(anotherObject) === object.prototype; // Prototype object.getPrototypeof (myObject); // {name: "Wakawa "} myObject.hasownProperty ('name'); // false; Note that name is on the prototype. myObject.hasOwnProperty('age'); // true indicates that age is its own myobject.name; // myobject.age; / / 18;Copy the code

For browsers that do not support ES5, the PloyFill scheme is provided on the MDN.

if (typeof Object.create ! == "function") { Object.create = function (proto, propertiesObject) { if (typeof proto ! == 'object' && typeof proto ! == 'function') { throw new TypeError('Object prototype may only be an Object: ' + proto); } else if (proto === null) { throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument."); } if (typeof propertiesObject ! = 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument."); function F() {} F.prototype = proto; return new F(); }; }Copy the code

At this point, the article is basically finished. Thank you for reading this.

To sum up:

  1. newWhat was done:
  1. A completely new object is created.
  2. This object will be executed[[Prototype]](i.e.__proto__Links).
  3. The generated new object is bound to the function callthis.
  4. throughnewEach object created will eventually be[[Prototype]]Link to this functionprototypeOn the object.
  5. If the function does not return an object typeObject(including,Functoin.Array.Date.RegExg.Error), thennewThe function call in the expression automatically returns the new object.
  1. How to simulate it
Function newOperator(ctor){if(typeof ctor! == 'function'){ throw 'newOperator function the first param must be a function'; } newOperator.target = ctor; var newObj = Object.create(ctor.prototype); var argsArr = [].slice.call(arguments, 1); var ctorReturnResult = ctor.apply(newObj, argsArr); var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult ! == null; var isFunction = typeof ctorReturnResult === 'function'; if(isObject || isFunction){ return ctorReturnResult; } return newObj; }Copy the code

Readers are welcome to point out any shortcomings or improvements they find. In addition, I think it is well written, and I can point a like, which is also a kind of support for the author.

Selected articles by the author

Learn how to use sentry source code and build their own front-end exception monitoring SDK. Learn how to use lodash source code and build their own functional programming library. Q: Can you simulate the js call and apply methods? Q: Can you simulate the js bind method? Q: Can you simulate the js bind method? Can simulate the implementation of the JS new operator front end using puppeteer crawler to generate the React. JS small book PDF and merge

about

Author: often with the name of Ruochuan mixed in rivers and lakes. The front road lovers | | PPT know little, only good study. Personal blog segmentfault front view column, opened front view column, welcome to pay attention to ~ gold column, welcome to pay attention to ~ github front view column, welcome to pay attention to ~ github blog, find a star^_^~

Wechat public account Ruochuan Vision

[Wakawa Vision] may be more interesting wechat public account, welcome to follow. You can also add wechat Ruochuan12, indicate the source, pull you into [front view communication group].