|
| 1 | +# Constructor, operator "new" |
| 2 | + |
| 3 | +The regular `{...}` syntax allows to create one object. But often we need to create many similar objects, like multiple users or menu items and so on. |
| 4 | + |
| 5 | +That can be done using constructor functions and the `"new"` operator. |
| 6 | + |
| 7 | +## Constructor function |
| 8 | + |
| 9 | +Constructor functions technically are regular functions. There are two conventions though: |
| 10 | + |
| 11 | +1. They are named with capital letter first. |
| 12 | + |
| 13 | +2. They should be executed only with `"new"` operator. |
| 14 | + |
| 15 | +For instance: |
| 16 | + |
| 17 | +``` |
| 18 | +function User(name) { |
| 19 | + this.name = name; |
| 20 | + this.isAdmin = false; |
| 21 | +} |
| 22 | +
|
| 23 | +let user = new User("Jack"); |
| 24 | +
|
| 25 | +alert(user.name); // Jack |
| 26 | +alert(user.isAdmin); // false |
| 27 | +``` |
| 28 | + |
| 29 | +When a function is executed as `new User(...)`, it does the following steps: |
| 30 | + |
| 31 | +1. A new empty object is created and assigned to `this`. |
| 32 | + |
| 33 | +2. The function body executes. Usually it modifies `this`, adds new properties to it. |
| 34 | + |
| 35 | +3. The value of `this` is returned. |
| 36 | + |
| 37 | +In other words, `new User(...)` does something like: |
| 38 | + |
| 39 | +``` |
| 40 | +function User(name) { |
| 41 | + // this = {}; (implicitly) |
| 42 | +
|
| 43 | + // add properties to this |
| 44 | + this.name = name; |
| 45 | + this.isAdmin = false; |
| 46 | +
|
| 47 | + // return this; (implicitly) |
| 48 | +} |
| 49 | +``` |
| 50 | + |
| 51 | +So the result of new `User("Jack")` is the same object as: |
| 52 | + |
| 53 | +``` |
| 54 | +let user = { |
| 55 | + name: "Jack", |
| 56 | + isAdmin: false |
| 57 | +}; |
| 58 | +``` |
| 59 | + |
| 60 | +Now if we want to create other users, we can call `new User("Ann")`, `new User("Alice")` and so on. Much shorter than using literals every time, and also easy to read. |
| 61 | + |
| 62 | +That’s the main purpose of constructors – to implement reusable object creation code. |
| 63 | + |
| 64 | +Let’s note once again – technically, any function can be used as a constructor. That is: any function can be run with `new`, and it will execute the algorithm above. The “capital letter first” is a common agreement, to make it clear that a function is to be run with `new`. |
| 65 | + |
| 66 | +*** |
| 67 | + |
| 68 | +#### new function() { ... } |
| 69 | + |
| 70 | +If we have many lines of code all about creation of a single complex object, we can wrap them in constructor function, like this: |
| 71 | + |
| 72 | +``` |
| 73 | +let user = new function() { |
| 74 | + this.name = "John"; |
| 75 | + this.isAdmin = false; |
| 76 | +
|
| 77 | + // ...other code for user creation |
| 78 | + // maybe complex logic and statements |
| 79 | + // local variables etc |
| 80 | +}; |
| 81 | +``` |
| 82 | + |
| 83 | +The constructor can’t be called again, because it is not saved anywhere, just created and called. So this trick aims to encapsulate the code that constructs the single object, without future reuse. |
| 84 | + |
| 85 | +*** |
| 86 | + |
| 87 | +## Dual-syntax constructors: new.target |
| 88 | + |
| 89 | +Inside a function, we can check whether it was called with `new` or without it, using a special `new.target` property. |
| 90 | + |
| 91 | +It is empty for regular calls and equals the function if called with `new`: |
| 92 | + |
| 93 | +``` |
| 94 | +function User() { |
| 95 | + alert(new.target); |
| 96 | +} |
| 97 | +
|
| 98 | +// without new: |
| 99 | +User(); // undefined |
| 100 | +
|
| 101 | +// with new: |
| 102 | +new User(); // function User { ... } |
| 103 | +``` |
| 104 | + |
| 105 | +That can be used to allow both `new` and regular syntax to work the same: |
| 106 | + |
| 107 | +``` |
| 108 | +function User(name) { |
| 109 | + if (!new.target) { // if you run me without new |
| 110 | + return new User(name); // ...I will add new for you |
| 111 | + } |
| 112 | +
|
| 113 | + this.name = name; |
| 114 | +} |
| 115 | +
|
| 116 | +let john = User("John"); // redirects call to new User |
| 117 | +alert(john.name); // John |
| 118 | +``` |
| 119 | + |
| 120 | +This approach is sometimes used in libraries to make the syntax more flexible. Probably not a good thing to use everywhere though, because omitting `new` makes it a bit less obvious what’s going on. With `new` we all know that the new object is being created, that’s a good thing. |
| 121 | + |
| 122 | +## Return from constructors |
| 123 | + |
| 124 | +Usually, constructors do not have a `return` statement. Their task is to write all necessary stuff into `this`, and it automatically becomes the result. |
| 125 | + |
| 126 | +But if there is a `return` statement, then the rule is simple: |
| 127 | + |
| 128 | +* If `return` is called with object, then it is returned instead of `this`. |
| 129 | +* If `return` is called with a primitive, it’s ignored. |
| 130 | + |
| 131 | +In other words, `return` with an object returns that object, in all other cases `this` is returned. |
| 132 | + |
| 133 | +For instance, here `return` overrides `this` by returning an object: |
| 134 | + |
| 135 | +``` |
| 136 | +function BigUser() { |
| 137 | +
|
| 138 | + this.name = "John"; |
| 139 | +
|
| 140 | + return { name: "Godzilla" }; // <-- returns an object |
| 141 | +} |
| 142 | +
|
| 143 | +alert( new BigUser().name ); // Godzilla, got that object ^^ |
| 144 | +``` |
| 145 | + |
| 146 | +And here’s an example with an empty `return` (or we could place a primitive after it, doesn’t matter): |
| 147 | + |
| 148 | +``` |
| 149 | +function SmallUser() { |
| 150 | +
|
| 151 | + this.name = "John"; |
| 152 | +
|
| 153 | + return; // finishes the execution, returns this |
| 154 | +
|
| 155 | + // ... |
| 156 | +
|
| 157 | +} |
| 158 | +
|
| 159 | +alert( new SmallUser().name ); // John |
| 160 | +``` |
| 161 | + |
| 162 | +Usually constructors don’t have a `return` statement. Here we mention the special behavior with returning objects mainly for the sake of completeness. |
| 163 | + |
| 164 | +*** |
| 165 | + |
| 166 | +#### Omitting parentheses |
| 167 | + |
| 168 | +By the way, we can omit parentheses after new, if it has no arguments: |
| 169 | + |
| 170 | +``` |
| 171 | +let user = new User; // <-- no parentheses |
| 172 | +// same as |
| 173 | +let user = new User(); |
| 174 | +``` |
| 175 | + |
| 176 | +Omitting parentheses here is not considered a “good style”, but the syntax is permitted by specification. |
| 177 | + |
| 178 | +*** |
| 179 | + |
| 180 | +## Methods in constructor |
| 181 | + |
| 182 | +Using constructor functions to create objects gives a great deal of flexibility. The constructor function may have parameters that define how to construct the object, and what to put in it. |
| 183 | + |
| 184 | +Of course, we can add to `this` not only properties, but methods as well. |
| 185 | + |
| 186 | +For instance, `new User(name)` below creates an object with the given `name` and the method `sayHi`: |
| 187 | + |
| 188 | +``` |
| 189 | +function User(name) { |
| 190 | + this.name = name; |
| 191 | +
|
| 192 | + this.sayHi = function() { |
| 193 | + alert( "My name is: " + this.name ); |
| 194 | + }; |
| 195 | +} |
| 196 | +
|
| 197 | +let john = new User("John"); |
| 198 | +
|
| 199 | +john.sayHi(); // My name is: John |
| 200 | +
|
| 201 | +/* |
| 202 | +john = { |
| 203 | + name: "John", |
| 204 | + sayHi: function() { ... } |
| 205 | +} |
| 206 | +*/ |
| 207 | +``` |
| 208 | + |
| 209 | +## Summary |
| 210 | + |
| 211 | +* Constructor functions or, briefly, constructors, are regular functions, but there’s a common agreement to name them with capital letter first. |
| 212 | + |
| 213 | +* Constructor functions should only be called using `new`. Such a call implies a creation of empty `this` at the start and returning the populated one at the end. |
| 214 | + |
| 215 | +We can use constructor functions to make multiple similar objects. |
| 216 | + |
| 217 | +JavaScript provides constructor functions for many built-in language objects: like `Date` for dates, `Set` for sets and others that we plan to study. |
| 218 | + |
| 219 | +*** |
| 220 | + |
| 221 | +#### Objects, we’ll be back! |
| 222 | + |
| 223 | +In this chapter we only cover the basics about objects and constructors. They are essential for learning more about data types and functions in the next chapters. |
| 224 | + |
| 225 | +After we learn that, in the chapter Objects, classes, inheritance we return to objects and cover them in-depth, including inheritance and classes. |
| 226 | + |
| 227 | +*** |
0 commit comments