Object-oriented Javascript

Preview:

DESCRIPTION

사내 기술 세미나를 다시 시작한다. 나는 그 첫번째 주제로 `Object-oriented Javascript`를 택했다. 예전에 학습했던 [Tuts+ 강의](https://code.tutsplus.com/courses/object-oriented-javascript)를 다시 정리하는 계기가 되었다.

Citation preview

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

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

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

var person = { firstName: 'John', lastName: 'Doe'};

var employee = Object.create(person);

Object.getPrototypeOf(employee) === person; // true

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

THE END

Recommended