object-oriented javascript
DESCRIPTION
사내 기술 세미나를 다시 시작한다. 나는 그 첫번째 주제로 `Object-oriented Javascript`를 택했다. 예전에 학습했던 [Tuts+ 강의](https://code.tutsplus.com/courses/object-oriented-javascript)를 다시 정리하는 계기가 되었다.TRANSCRIPT
Object-oriented JavascriptDaniel Ku (http://kjunine.net/)
Primitives and Objects
“Is Everythingin JavaScriptan object?”
WRONG!
Primitives» string
» number
» boolean
» undefined
» null
Everything else is object.
“WHAT?Strings haveproperties and methods!”
var p = 'hello';p.test = 'test';console.log(p.test); // ?
var o = new String('hello');o.test = 'test';console.log(o.test); // ?
var p = 'hello';p.test = 'test';console.log(p.test); // undefined
var o = new String('hello');o.test = 'test';console.log(o.test); // test
typeof 'hello'; // stringtypeof new String('hello'); // objecttypeof 10 // numbertypeof new Number(10); // objecttypeof false; // booleantypeof new Boolean(true); // objecttypeof undefined; // undefinedtypeof null; // object ???
HOWto create an object?
Factory Functions
var createPerson = function(firstName, lastName) { return { firstName: firstName, lastName: lastName, sayHi: function() { return 'Hi there'; } };};
var john = createPerson('John', 'Doe');var jane = createPerson('Jane', 'Doe');
IT WORKS! BUT,
BAD PRACTICE!
The this keyword
thisis
» window in global context
» the object in an object
var name = 'Jane';
var greet = function() { return 'My name is ' + this.name;}
var person = { name: 'John', greet: greet};
greet(); // ?person.greet(); // ?
var name = 'Jane';
var greet = function() { return 'My name is ' + this.name;}
var person = { name: 'John', greet: greet};
greet(); // My name is Janeperson.greet(); // My name is John
var requestAsync = function(url, callback) { var data = 10; callback(data);};
var requestor = { value: 20, process: function(data) { var sum = this.value + data; console.log(sum); }, request: function() { var url = 'http://example.com'; requestAsync(url, this.process); }};
requestor.request(); // ?
var requestAsync = function(url, callback) { var data = 10; callback(data);};
var requestor = { value: 20, process: function(data) { var sum = this.value + data; console.log(sum); }, request: function() { var url = 'http://example.com'; requestAsync(url, this.process); }};
requestor.request(); // NaN
Function.prototype.bind» reference
» es5-shim
var requestAsync = function(url, callback) { var data = 10; callback(data);};
var requestor = { value: 20, process: function(data) { var sum = this.value + data; console.log(sum); }, request: function() { var url = 'http://example.com'; requestAsync(url, this.process.bind(this)); }};
requestor.request(); // 30
Constructor Functions
var Person = function(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; this.sayHi = function() { return 'Hi~'; };};
var person = new Person('John', 'Doe');
Also,
BAD PRACTICE!Do like next.
var Person = function(firstName, lastName) { this.firstName = firstName; this.lastName = lastName;};
Person.prototype.sayHi = function() { return 'Hi~';};
var person = new Person('John', 'Doe');
The Prototype
Object.getPrototypeOf» reference
» es5-shim
person.constructor === Person; // trueperson.__proto__ === Person.prototype; // trueObject.getPrototypeOf(person) === Person.prototype; // true
person.hasOwnProperty('firstName'); // trueperson.hasOwnProperty('lastName'); // trueperson.hasOwnProperty('sayHi'); // falseperson.constructor .prototype .hasOwnProperty('sayHi'); // true
Properties and Property Descriptors
var person = {};
Object.defineProperty(person, 'firstName', { // descriptor object (data descriptor) value: 'John', writable: true});
Object.defineProperty(person, 'lastName', { value: 'Doe', writable: false});
person.firstName; // 'John'person.lastName; // 'Doe'
person.firstName = 'Jane';person.firstName; // 'Jane'
person.lastName = 'Dummy';person.lastName; // 'Doe'
var person = {};
Object.defineProperties(person, { firstName: { value: 'John', writable: true }, lastName: { value: 'Doe', writable: true }, fullName: { // accessor descriptor get: function() { return this.firstName + ' ' + this.lastName; }, set: function(value) { var splits = value.split(' '); this.firstName = splits[0]; this.lastName = splits[1]; } }});
person.fullName; // 'John Doe'person.fullName = 'Jane Eyre'person.firstName; // 'Jane'person.lastName; // 'Eyre'person.fullName; // 'Jane Eyre'
var person = {};
Object.defineProperty(person, 'firstName', { value: 'John', enumerable: true});
Object.defineProperty(person, 'lastName', { value: 'Doe', enumerable: false});
for (var key in person) { console.log(key, '=>' , person[key]);}// 'firstName => John'
Object.defineProperty» Property Descriptors
» Data Descriptors
» Accessor Descriptors
» reference
» es5-shim
Common Keys of Descriptors» configurable (default: false)
» enumerable (default: false)
Keys of Data Descriptors» value (default: undefined)
» writable (default: false)
Keys of Accessor Descriptors» get (default: undefined)
» set (default: undefined)
Constructors and the Prototype REVISITED
var Person = function(firstName, lastName) { Object.defineProperty(this, 'firstName', { value: firstName, writable: true, enumerable: true }); Object.defineProperty(this, 'lastName', { value: lastName, writable: true, enumerable: true });};
Object.defineProperties(Person.prototype, { sayHi: { value: function() { return 'Hi there'; } }, fullName: { get: function() { return this.firstName + ' ' + this.lastName; }, enumerable: true }});
var person = new Person('John', 'Doe');
HOWto do inheritance?
Prototypical Inheritance
Object.create» reference
» es5-shim
var person = { firstName: 'John', lastName: 'Doe'};
var employee = Object.create(person);
Object.getPrototypeOf(employee) === person; // true
Object.getOwnPropertyDescriptor» reference
» es5-shim
var Person = function(firstName, lastName) { this.firstName = firstName; this.lastName = lastName;};
Person.prototype.sayHi = function() { return 'Hi~';};
var person = new Person('John', 'Doe');
Object.getOwnPropertyDescriptor(Person.prototype, 'sayHi');// {value: function, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(person, 'firstName');// {value: "John", writable: true, enumerable: true, configurable: true}
Let's Do Inheritance
var Person = function(firstName, lastName) { Object.defineProperties(this, { firstName: { value: firstName, writable: true, enumerable: true }, lastName: { value: lastName, writable: true, enumerable: true } });};
Object.defineProperties(Person.prototype, { sayHi: { value: function() { return 'Hi there'; } }, fullName: { get: function() { return this.firstName + ' ' + this.lastName; }, enumerable: true }});
var Employee = function(firstName, lastName, position) { Person.call(this, firstName, lastName); Object.defineProperties(this, { position: { value: position, writable: true, enumerable: true } });};
Employee.prototype = Object.create(Person.prototype, { sayHi: { value: function() { return Person.prototype.sayHi.call(this) + ' and here'; } }, fullName: { get: function() { var descriptor = Object.getOwnPropertyDescriptor(Person.prototype, 'fullName'); return descriptor.get.call(this) + ' ' + this.position; }, enumerable: true }, constructor: { value: Employee }});
var employee = new Employee('John', 'Doe', 'Manager');
for (var key in employee) { console.log(key, '=>' , employee[key]);}// 'firstName => John'// 'lastName => Doe'// 'position => Manager'// 'fullName => John Doe Manager'
Prototypical Inheritance
Object.getPrototypeOf(employee) === Employee.prototype; // true
employee.__proto__ === Employee.prototype; // trueemployee.__proto__.__proto__ === Person.prototype; // trueemployee.__proto__.__proto__.__proto__ === Object.prototype; // trueemployee.__proto__.__proto__.__proto__.__proto__ === null; // true
References» Object-Oriented JavaScript on Tuts+
» Inheritance revisited on MDN
» ECMA-262-5 in detail by Dmitry Soshnikov
THE END