|
| 1 | +/* #09 HERENCIA Y POLIMORFISMO */ |
| 2 | +// bibliography |
| 3 | +//Professional JavaScript for web developers by Matt Frisbie [Frisbie, Matt] (z-lib.org) |
| 4 | +//GTT |
| 5 | + |
| 6 | +/* In JavaScript, inheritance is a mechanism that allows one object to acquire the properties and methods of another object. This is typically achieved through prototypes, where an object can inherit from another object's prototype, enabling code reuse and the creation of hierarchical relationships between objects. JavaScript supports both classical inheritance (using constructor functions and the `prototype` property) and modern inheritance (using `class` syntax introduced in ES6). |
| 7 | +All objects have an internal property called [[Prototype]], which is a reference to another object. This prototype chain allows for inheritance, where an object can access properties and methods from its prototype. |
| 8 | +When you create an object using a constructor function, you can set its prototype using the prototype property. |
| 9 | +With the introduction of ES6, JavaScript introduced class syntax, which is essentially syntactic sugar over the existing prototype-based inheritance. When you define a class, JavaScript still uses prototypes behind the scenes*/ |
| 10 | + |
| 11 | +// short for console.log() |
| 12 | +let log = console.log; |
| 13 | + |
| 14 | +window.addEventListener('load', ()=>{ |
| 15 | + const body = document.querySelector('body'); |
| 16 | + const title = document.createElement('h1'); |
| 17 | + |
| 18 | + body.style.setProperty('background', '#000'); |
| 19 | + body.style.setProperty('text-align', 'center'); |
| 20 | + |
| 21 | + title.textContent = 'Retosparaprogramadores #9.'; |
| 22 | + title.style.setProperty('font-size', '3.5vmax'); |
| 23 | + title.style.setProperty('color', '#fff'); |
| 24 | + title.style.setProperty('line-height', '100vh'); |
| 25 | + |
| 26 | + body.appendChild(title); |
| 27 | + |
| 28 | + setTimeout(()=>{ |
| 29 | + alert('Retosparaprogramadores #9. Please open the Browser Developer Tools.'); |
| 30 | + }, 2000); |
| 31 | + log( 'Retosparaprogramadores #9'); |
| 32 | +}); |
| 33 | + |
| 34 | + |
| 35 | +class Animal{ |
| 36 | + constructor(name, sound, type){ |
| 37 | + this._name = name || 'set no name'; |
| 38 | + this._sound = sound || 'set no sound'; |
| 39 | + this._type = type || 'set no type'; |
| 40 | + } |
| 41 | + |
| 42 | + get name(){ |
| 43 | + return this._name; |
| 44 | + } |
| 45 | + |
| 46 | + set name(name){ |
| 47 | + this._name = name; |
| 48 | + } |
| 49 | + |
| 50 | + speak(){ |
| 51 | + log(`${this.name} the ${this._type} say: ${this._sound}!`) |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +class Dog extends Animal{ |
| 56 | + constructor(name, sound, type){ |
| 57 | + super(name, sound, type); |
| 58 | + } |
| 59 | + |
| 60 | + eat(meal){ |
| 61 | + log(`${this._name} the ${this._type} eat some: ${meal}`) |
| 62 | + } |
| 63 | + |
| 64 | + move(){ |
| 65 | + log(`the ${this._type} moves it's tail`) |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +const capDog = new Dog('Capitan', 'I guau some pizza', 'Dog'); |
| 70 | +capDog.speak(); // Capitan the Dog say: I guau some pizza! |
| 71 | +capDog.eat('pizza'); // Capitan the Dog eat some: pizza |
| 72 | +capDog.move(); // the Dog moves it's tail |
| 73 | + |
| 74 | +class Cat extends Animal{ |
| 75 | + constructor(name, sound, type){ |
| 76 | + super(name, sound, type); |
| 77 | + } |
| 78 | + |
| 79 | + eat(meal){ |
| 80 | + log(`${this._name} the ${this._type} eat some: ${meal}`) |
| 81 | + } |
| 82 | + |
| 83 | + move(){ |
| 84 | + log(`the ${this._type} hunt the rat`) |
| 85 | + } |
| 86 | + |
| 87 | +} |
| 88 | + |
| 89 | +const blackJack = new Cat('BlackJack', 'Miuauuuu', 'Cat'); |
| 90 | +blackJack.speak(); // BlackJack the Cat say: Miuauuuu! |
| 91 | +blackJack.eat('rat snack'); // BlackJack the Cat eat some: rat snack |
| 92 | +blackJack.move(); // the Cat hunt the rat |
| 93 | + |
| 94 | +//Note: is interesting know that we can use variables like key-value assign to object properties, this also work with functions, see: |
| 95 | + |
| 96 | +const makePerson = (name, age, email)=> { |
| 97 | + return { name, age, email }; |
| 98 | +} |
| 99 | +const person = makePerson('Angy', 28, 'badgirl@greenhouse.net'); |
| 100 | +log(person); // { name: "Angy", age: 28, email: "badgirl@greenhouse.net" } |
| 101 | + |
| 102 | +//using destructuring |
| 103 | +let {name: personName, age: personAge, email: personEmail, personJob = 'Web Developer'} = person; |
| 104 | +log(personAge); // 28 |
| 105 | +log(personJob)// Web Developer |
| 106 | + |
| 107 | + |
| 108 | +class User { |
| 109 | + constructor(id, name, email, country) { |
| 110 | + try { |
| 111 | + this._id = this.setId(id); |
| 112 | + this._name = this.setName(name); |
| 113 | + this._email = this.setEmail(email); |
| 114 | + this._country = this.setCountry(country); |
| 115 | + this.validateProperties(); // Validate properties before freezing or sealing |
| 116 | + //Object.seal(this); // Seal the object to prevent further properties deletions |
| 117 | + } catch (error) { |
| 118 | + console.error('Error creating User:', error.message); |
| 119 | + // Handle the error as needed (e.g., set default values, rethrow, etc.) |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + get id() { |
| 124 | + return this._id; |
| 125 | + } |
| 126 | + |
| 127 | + get name() { |
| 128 | + return this._name; |
| 129 | + } |
| 130 | + |
| 131 | + get email() { |
| 132 | + return this._email; |
| 133 | + } |
| 134 | + |
| 135 | + get country() { |
| 136 | + return this._country; |
| 137 | + } |
| 138 | + |
| 139 | + set id(id) { |
| 140 | + this._id = this.setId(id); |
| 141 | + } |
| 142 | + |
| 143 | + set name(name) { |
| 144 | + this._name = this.setName(name); |
| 145 | + } |
| 146 | + |
| 147 | + set email(email) { |
| 148 | + this._email = this.setEmail(email); |
| 149 | + } |
| 150 | + |
| 151 | + set country(country) { |
| 152 | + this._country = this.setCountry(country); |
| 153 | + } |
| 154 | + |
| 155 | + setId(id) { |
| 156 | + const idString = String(id); |
| 157 | + const maxLength = 15; |
| 158 | + |
| 159 | + if (idString.length > maxLength) { |
| 160 | + throw new Error(`ID must be at most ${maxLength} characters long.`); |
| 161 | + } |
| 162 | + |
| 163 | + return idString; |
| 164 | + } |
| 165 | + |
| 166 | + setName(name) { |
| 167 | + const nameString = String(name); |
| 168 | + const maxLength = 35; |
| 169 | + |
| 170 | + if (nameString.length > maxLength) { |
| 171 | + throw new Error(`Name must be at most ${maxLength} characters long.`); |
| 172 | + } |
| 173 | + |
| 174 | + return nameString; |
| 175 | + } |
| 176 | + |
| 177 | + setEmail(email) { |
| 178 | + const emailRegex = /^[^\s@]+@[^\s@]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/; |
| 179 | + |
| 180 | + if (!emailRegex.test(email)) { |
| 181 | + throw new Error('Invalid email address format.'); |
| 182 | + } |
| 183 | + |
| 184 | + return email; |
| 185 | + } |
| 186 | + |
| 187 | + setCountry(country) { |
| 188 | + const countryString = String(country); |
| 189 | + const maxLength = 35; |
| 190 | + |
| 191 | + if (countryString.length > maxLength) { |
| 192 | + throw new Error(`Country must be at most ${maxLength} characters long.`); |
| 193 | + } |
| 194 | + |
| 195 | + return countryString; |
| 196 | + } |
| 197 | + |
| 198 | + validateProperties() { |
| 199 | + if (!this._id || !this._name || !this._email || !this._country) { |
| 200 | + throw new Error('All properties must be set before freezing the object.'); |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + userData() { |
| 205 | + return { id: this._id, name: this._name, email: this._email, country: this._country }; |
| 206 | + } |
| 207 | +} |
| 208 | + |
| 209 | + |
| 210 | +try { |
| 211 | + let sussy = new User('0067', 'Sussan', 'sussy45@something.dt', 'Canada'); |
| 212 | + console.log(sussy.userData()); |
| 213 | +} catch (error) { |
| 214 | + console.error('Failed to create user:', error.message); |
| 215 | +} |
| 216 | + |
| 217 | +//Note: if we use a number to set the value for id 0067 becomes 55 cause is turned to a decimal value |
| 218 | + |
| 219 | +class SuperUser extends User{ |
| 220 | + constructor(id, name, email, country){ |
| 221 | + super(id, name, email, country); |
| 222 | + this.permission = true; |
| 223 | + } |
| 224 | + |
| 225 | + hasPermission() { |
| 226 | + return this.permission; |
| 227 | + } |
| 228 | + |
| 229 | + displayUserInfo() { |
| 230 | + const userInfo = this.userData(); |
| 231 | + return `${userInfo.name} has permission: ${this.hasPermission()}`; |
| 232 | + } |
| 233 | +} |
| 234 | + |
| 235 | +const niko = new SuperUser('001', 'Niko', 'duendeintemporal@hotmail.com', 'Venezuela'); |
| 236 | +niko.country = 'undefined'; |
| 237 | +log(niko._id); // 001 |
| 238 | +log(niko.country) // undefined |
| 239 | +log(niko.permission); // true |
| 240 | +log(niko.userData()); // { id: "001", name: "Niko", email: "duendeintemporal@hotmail.com", country: "undefined" } |
| 241 | + |
| 242 | +// Extra Exercises |
| 243 | + |
| 244 | + |
| 245 | +class Employed { |
| 246 | + constructor(id, name, occupation) { |
| 247 | + try { |
| 248 | + this._id = this.setId(id); |
| 249 | + this._name = this.setName(name); |
| 250 | + this._occupation = this.setOccupation(occupation); |
| 251 | + this.validateProperties(); |
| 252 | + } catch (error) { |
| 253 | + console.error('Error creating Employed:', error.message); |
| 254 | + // Handle the error as needed (e.g., set default values, rethrow, etc.) |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + get id() { |
| 259 | + return this._id; |
| 260 | + } |
| 261 | + |
| 262 | + get name() { |
| 263 | + return this._name; |
| 264 | + } |
| 265 | + |
| 266 | + get occupation() { |
| 267 | + return this._occupation; |
| 268 | + } |
| 269 | + |
| 270 | + set id(id) { |
| 271 | + this._id = this.setId(id); |
| 272 | + } |
| 273 | + |
| 274 | + set name(name) { |
| 275 | + this._name = this.setName(name); |
| 276 | + } |
| 277 | + |
| 278 | + set occupation(occupation) { |
| 279 | + this._occupation = this.setOccupation(occupation); |
| 280 | + } |
| 281 | + |
| 282 | + setId(id) { |
| 283 | + const idString = String(id); |
| 284 | + const maxLength = 15; |
| 285 | + |
| 286 | + if (idString.length > maxLength) { |
| 287 | + throw new Error(`ID must be at most ${maxLength} characters long.`); |
| 288 | + } |
| 289 | + |
| 290 | + return idString; |
| 291 | + } |
| 292 | + |
| 293 | + setName(name) { |
| 294 | + const nameString = String(name); |
| 295 | + const maxLength = 35; |
| 296 | + |
| 297 | + if (nameString.length > maxLength) { |
| 298 | + throw new Error(`Name must be at most ${maxLength} characters long.`); |
| 299 | + } |
| 300 | + |
| 301 | + return nameString; |
| 302 | + } |
| 303 | + |
| 304 | + setOccupation(occupation) { |
| 305 | + const occupationStr = String(occupation); |
| 306 | + const maxLength = 50; |
| 307 | + |
| 308 | + if (occupationStr.length > maxLength) { |
| 309 | + throw new Error(`Occupation must be at most ${maxLength} characters long.`); |
| 310 | + } |
| 311 | + |
| 312 | + return occupationStr; |
| 313 | + } |
| 314 | + |
| 315 | + validateProperties() { |
| 316 | + if (!this._id || !this._name || !this._occupation) { |
| 317 | + throw new Error('All properties must be set before freezing the object.'); |
| 318 | + } |
| 319 | + } |
| 320 | + |
| 321 | + employedData() { |
| 322 | + return { id: this._id, name: this._name, occupation: this._occupation }; |
| 323 | + } |
| 324 | +} |
| 325 | + |
| 326 | +class Developer extends Employed { |
| 327 | + constructor(id, name, occupation, languages, area) { |
| 328 | + super(id, name, occupation); |
| 329 | + this._languages = languages; |
| 330 | + this._area = area; |
| 331 | + } |
| 332 | + |
| 333 | + functions() { |
| 334 | + log(`Developer ID: ${this._id} | Name: ${this._name} | Occupation: ${this._occupation} | Area: ${this._area} | Languages: ${this._languages.join(', ')}`); |
| 335 | + } |
| 336 | +} |
| 337 | + |
| 338 | +class Secretary extends Employed { |
| 339 | + constructor(id, name, occupation) { |
| 340 | + super(id, name, occupation); |
| 341 | + } |
| 342 | + |
| 343 | + functions() { |
| 344 | + log(`Secretary ID: ${this._id} | Name: ${this._name} | Occupation: ${this._occupation} | Responsibilities: Administrative operations and user attention.`); |
| 345 | + } |
| 346 | +} |
| 347 | + |
| 348 | +class Manager extends Employed { |
| 349 | + constructor(id, name, occupation, employeds) { |
| 350 | + super(id, name, occupation); |
| 351 | + this._employeds = employeds; // Expecting an array of employees |
| 352 | + } |
| 353 | + |
| 354 | + functions() { |
| 355 | + log(`Manager ID: ${this._id} | Name: ${this._name} | Occupation: ${this._occupation} | Supervising Employees: ${this._employeds.join(', ')}`); |
| 356 | + } |
| 357 | +} |
| 358 | + |
| 359 | +class GeneralManager extends Manager{ |
| 360 | + constructor(id, name, ocupation, employeds){ |
| 361 | + super(id, name, ocupation, employeds); |
| 362 | + } |
| 363 | + |
| 364 | + functions() { |
| 365 | + log(`General Manager ID: ${this._id} | Name: ${this._name} | Occupation: ${this._occupation} | Supervising Employees: ${this._employeds.join(', ')}`); |
| 366 | + } |
| 367 | +} |
| 368 | + |
| 369 | +const s1 = new Secretary('0023', 'Gabriela Mistral', 'Secretary'); |
| 370 | +const d12 = new Developer('0041', 'Niko Zen', 'Web Developer', ['Python, ','JavaScript', 'Rust', 'Ruby', 'Bash']); |
| 371 | +const m3 = new Manager('0098', 'Patty Smith', 'Manager', [s1.name, d12.name]); |
| 372 | +const mg2 = new GeneralManager('003', 'Lenny Kravitz', 'General Manager', [m3.name]); |
| 373 | + |
| 374 | +log(s1.employedData()); // id: "0023", name: "Gabriela Mistral", occupation: "Secretary" |
| 375 | +log(d12.functions()); // Developer ID: 0041 | Name: Niko Zen | Occupation: Web Developer | Area: undefined | Languages: Python, , JavaScript, Rust, Ruby, Bash |
| 376 | +log(m3.functions()); // Manager ID: 0098 | Name: Patty Smith | Occupation: Manager | Supervising Employees: Gabriela Mistral, Niko Ze |
| 377 | +log(mg2.functions()); // General Manager ID: 003 | Name: Lenny Kravitz | Occupation: General Manager | Supervising Employees: Patty Smith |
0 commit comments