이듬 강의_JavaScript 인터랙션 디자인(2)
12 Jul 2023인터랙션 디자인(JavaScript)
객체 / 상속
JavaScript의 모든 객체는 Object 자손.
//객체 생성 : {} , new Object();
var o = {};
//속성 추가
o.name = "객체";
//속성 삭제
delete o.name;
//속성을 객체가 소유했는지 여부 확인
//'property' in object
"name" in o;
//객체 순환
//for in
객체 병합 : Mixin
var mixin = function() {
var mixin_obj = {};
for(var i = 0; l = arguments.length; i < l; i++) {
var o = arguments[i];
for(var key in o) {
var value = o[key];
if(o.hasOwnProperty(key)) {
mixin_obj[key] = value;
}
}
}
}
var car = { /* */ };
var extended_car_features = { /* */ };
var super_car = mixin(car, extended_car_features);
- 객체 속성 정의
- 객체 및 속성을 갖는 새 객체를 만듦
- Object.create(객체명);
- 객체에 직접 새로운 속성을 정의하거나 이미 존재하는 객체를 수정한 뒤 그 객체를 반환
- Object.defineProperty(obj, property, descriptor)
- writable: false, //할당 연산자를 통한 값 변경 가능 여부
- enumerable: false, //객체의 속성으로 열거 가능 여부
- configurable: false, //객체의 속성 제거 가능 여부
- value: undefined //객체 속성 값 설정
Object.defineProperty(o, "use", {
value: "office",
writable: true,
});
- 데이터 접근 기술
- getter : 속성의 값을 얻는 목적으로 사용. 함수 반환 값이 객체 속성 값이 됨(get: undefined)
- value, get을 동시에 사용하면 오류 발생.
- setter : 속성의 값을 설정하기 위한 함수. 오직 하나의 인자만 받음. 속성 값으로 할당(set: undefined)
(function() {
var visible = true;
Object.defineProperty(o, 'visible', {
get: function() {console.log('getter')}; return visible;
set: function(value) {console.log('setter')}; visible = value;
})
})();
o.visible //getter true
o.visible = false //setter false
- Object.defineProperties(obj, props)
- 이미 존재하거나 새로운 프로퍼티들의 각종 속성들을 재정의할 수 있음
(function() {
var pad = 0;
Object.defineProperties(o, {
margin: {
value: '외부 여백'
},
padding: {
get: function() { return pad; },
set: function(value) { pad = value; }
})
})();
- 객체 확장 차단
- 새로운 속성을 추가하지 못함(지우는 것은 가능)
- Object.preventExtensions(객체명);
- Object.isExtensible(객체명) // 확장 가능 여부 확인
- 객체 밀봉(Sealing)
- 새로운 속성 추가할 수 없고, 모든 속성을 설정 불가능 상태로 만들어줌
- 쓰기 가능한 속성(Writable)의 값은 밀봉 후에도 변경 가능
- Object.seal(객체명);
- Object.isSealed(객체명)
- 객체 동결(Freezing)
- 객체의 속성을 지우거나 바꿀 수 없음
- 밀봉 + 속성 값 변경 차단
- Object.freeze(객체명);
- Object.isFrozen(객체명);
- Object 객체의 인스턴스 메서드
- .hasOwnProperty() 메서드 // 본인 속성인지 확인 - true, false
생성자 / 프로토타입
- 객체는 생성자 함수를 통해 생성
new 연산자 뒤에 생성자 함수 실행하면, 내장 객체 또는 사용자 정의 객체 인스턴스를 생성
- 함수를 작성하여 객체 타입을 정의
- 첫 글자를 대문자로 작성해, 일반 함수와 구분(String(), Number(), Array())
- 모든 함수 객체는 정의와 동시에 자동으로 함수의 프로토타입 객체를 참조하는 속성 가지게 됨(객체명.prototype, Array.prototype)
- new 연산자로 객체 인스턴스 생성
- .prototype을 상속하는 새로운 객체가 하나 생성됨
- 이 객체에 바인드된 this와 함께 생성자 함수가 호출됨
- 생성된 객체는 함수의 결과물로 반환됨(return 기본값 === return this)
ES6부터는 class 문법 사용 가능
var tab1 = new Tab();
tab1.constructor === Tab;
tab1 instanceof Tab;
//생성자 함수에 연결되어 있는 prototype 객체에 접근하는 법
body_tab.constructor.prototype;
body_tab.__proto__;
Object.getPrototypeOf(body_tab);
- 생성자 함수는 객체를 생성하는 모체 역할 수행
- prototype 객체는 생성자를 통해 생성된 모든 객체가 공통으로 상속하는 속성/메서드 집합
- 생성자는 전달 인자를 통해 객체 고유의 속성을 설정할 수 있음
객체 지향 프로그래밍
function inherit(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
}
// -------------------------------------------------------------------------
// JavaScript 객체 지향 프로그래밍(OOP, Object Oriented Programming) & 상속
// -------------------------------------------------------------------------
// 각 객체를 생성하는 생성자 함수를 만들고,
// 공통적인 부분을 생성자 함수의 프로토타입 객체에 설정하는 것.
(function () {
"use strict";
/**
* @constructor: Animal
* 생성자 함수: `동물`
*/
function Animal() {
"use strcit";
}
// @prototype: Animal
// 프로토타입 객체: `동물`
Animal.prototype.type = "동물";
Animal.prototype.brain = true;
Animal.prototype.legs = 0;
Animal.prototype.run = function () {};
/**
* @constructor: Pet
* 생성자 함수: `애완동물`
*/
function Pet() {
"use strcit";
}
// @prototype: Pet
// 프로토타입 객체: `애완동물`
Pet.prototype.type = "애완동물";
Pet.prototype.brain = true;
Pet.prototype.legs = 4;
Pet.prototype.fleas = 0;
Pet.prototype.run = function () {};
/**
* @constructor: Cat
* 생성자 함수: `고양이`
*/
function Cat(name, gender, color) {
"use strcit";
this.name = name;
this.color = color;
this.gender = gender;
}
// @prototype: Cat
// 프로토타입 객체: `고양이`
Cat.prototype.type = "고양이";
Cat.prototype.brain = true;
Cat.prototype.legs = 4;
Cat.prototype.fleas = 4;
Cat.prototype.run = function () {};
})();
// 즉, Animal이 가진 속성/메서드는 Cat이 모두 가진다는 것.
// `상속`을 활용해 효율적으로 관리할 수 있음
(function () {
"use strict";
/**
* @constructor: Animal
* 생성자 함수: `동물`
*/
function Animal() {
"use strcit";
}
// @prototype: Animal
// 프로토타입 객체: `동물`
Animal.prototype.type = "동물";
Animal.prototype.brain = true;
Animal.prototype.legs = 0;
Animal.prototype.run = function () {
return this.type + " 달리다";
};
/**
* @constructor: Pet
* 생성자 함수: `애완동물`
*/
function Pet() {
"use strcit";
}
// @inheritance: Pet ⇐ Animal
// 상속: `동물`의 속성/메서드를 `애완동물`에게
// Pet.prototype = Object.create(Animal.prototype);
// Pet.prototype.constructor = Pet;
// 헬퍼함수
function inherit(sub_class, super_class) {
try {
sub_class.prototype = Object.create(super_class.prototype);
sub_class.prototype.constructor = sub_class;
} catch (e) {
console.error(e.message);
}
}
// Pet ⇐ Animal 상속
inherit(Pet, Animal);
// @prototype: Pet
// 프로토타입 객체: `애완동물`
Pet.prototype.type = "애완동물";
Pet.prototype.legs = 4;
Pet.prototype.fleas = 0;
/**
* @constructor: Cat
* 생성자 함수: `고양이`
*/
function Cat(name, gender, color) {
"use strcit";
this.name = name;
this.color = color;
this.gender = gender;
}
// Cat ⇐ Pet 상속
inherit(Cat, Pet);
// @prototype: Cat
// 프로토타입 객체: `고양이`
Cat.prototype.type = "고양이";
Cat.prototype.fleas = 4;
})();
// 캡슐화(Encapsulation)? 즉시 실행 함수식(IIFE) 패턴
// IIFE 패턴을 사용해 생성자 함수와 상속, 프로토타입 객체를 한데 묶어 관리
객체 지향 프로그래밍 용어 풀이
대표적인 객체 지향 프로그래밍 언어 : JavaScript, Java, C#, Ruby, Python, Objective-C.
- 객체 지향 프로그래밍은 추상화(Abstraction)를 사용하여 모델을 만드는 프로그래밍.
- 모듈성, 다형성 및 캡슐화를 포함한 여러 기술을 사용.
- OOP에서 각 객체는 메시지를 수신하고 데이터를 처리하며 메시지를 다른 객체로 보낼 수 있음
- 각 개체는 별개의 역할이나 책임이 있는 독립적인 작은 컴퓨터로 볼 수 있음
- 객체 지향 프로그래밍은 프로그래밍의 유연성과 유지 보수성을 높이기 위한 것.
- 특징
- Class -객체 속성(Properties)을 정의합니다. ( 예: 설계 도면 )
- Object - Class의 인스턴스(Instance) 입니다. ( 예: 설계 도면을 통해 구현된 실제 제품 )
- Property - 객체의 속성을 말합니다. ( 예: color 등과 같은 명사 형태 )
- Method - 객체의 기능을 말합니다.( 예: walk() 등과 같은 동사 형태 )
- Constructor - 인스턴스 생성 순간에 호출 실행되는 메서드입니다.
- Inheritance - Class는 다른 Class로 부터 속성들을 상속받을 수 있습니다. (Super Class ⇒ Sub Class)
- Encapsulation - Class는 해당 객체의 속성, 메서드 만 정의할 수 있습니다. (외부 접근 불가)
- Abtsraction - 복잡한 상속, 메서드, 객체 속성의 결합은 반드시 현실 모델을 시뮬레이션할 수 있어야 합니다.
- Polymorphism - 다른 Class 들이 같은 메서드나 속성으로 정의될 수 있습니다.
함수형 vs 객체 지향 프로그래밍
// -------------------------------------------------------------------------
// JavaScript 함수형 프로그래밍 VS 객체 지향 프로그래밍
// DOM 스크립팅을 목표로 하는 프로그래밍 패러다임 별 사용법을 알아봅시다.
// -------------------------------------------------------------------------
// <함수형 프로그래밍>
(function (global, document) {
"use strict";
var namespace = "y9";
function el(selector, context) {
return (context || document).querySelector(selector);
}
function els(selector, context) {
return (context || document).querySelectorAll(selector);
}
function each(list, callback) {
for (var i = 0, l = list.length; i < l; i++) {
callback(list[i], i);
}
}
function on(el, type, handler) {
el.addEventListener(type, handler);
}
function off(el, type, handler) {
el.removeEventListener(type, handler);
}
function hasClass(el, name) {
return el.classList.contains(name);
}
function addClass(el, name) {
var names = name.split(" ");
each(names, function (name) {
el.classList.add(name);
});
return el;
}
function removeClass(el, name) {
name ? el.classList.remove(name) : (el.className = "");
return el;
}
function toggleClass(el, name) {
return hasClass(el, name) ? removeClass(el, name) : addClass(el, name);
}
Object.defineProperty(global, namespace, { value: {} });
[
// 내보낼 함수를 추가
el,
els,
on,
off,
hasClass,
addClass,
removeClass,
toggleClass,
each,
].forEach(function (fn) {
global[namespace][fn.name] = fn;
});
Object.freeze(global[namespace]);
})(window, document);
// -------------------------------------------------------------------------
// <객체 지향 프로그래밍>
(function (global, document) {
// @constructor
function Dom(selector, context) {
try {
if (typeof selector === "string") {
var _els = (document || selector).querySelectorAll(selector);
var i = 0,
l = _els.length;
for (; i < l; ++i) {
this[i] = _els[i];
}
this.length = l;
} else if (selector && selector.nodeType === 1) {
this[0] = selector;
this.length = 1;
} else {
this.length = 0;
}
} catch (e) {
console.error(e.message);
}
}
// @static__methods
Dom.each = function (list, callback) {
var count = list.length;
for (var i = 0; i < count; i++) {
callback(list[i], i);
}
};
// @prototype
// @instance__methods
(function () {
this.version = "0.0.1";
this.each = function (callback) {
Dom.each(this, callback);
};
this.on = function (type, handler) {
Dom.each(this, function (item, i) {
item.addEventListener(type, handler.bind(item, item, i));
});
};
this.hasClass = function (name) {
return this[0].classList.contains(name);
};
this.addClass = function (name) {
var names = name.split(" ");
Dom.each(this, function (item, i) {
Dom.each(names, function (name) {
item.classList.add(name);
});
});
return this;
};
this.removeClass = function (name) {
Dom.each(this, function (item, i) {
name ? item.classList.remove(name) : (item.className = "");
});
return this;
};
this.toggleClass = function (name) {
Dom.each(this, function (item, i) {
if (item.classList.contains(name)) {
item.classList.remove(name);
} else {
item.classList.add(name);
}
});
return this;
};
this.eq = function (index) {
return new Dom(this[index]);
};
}).call(Dom.prototype);
// 공개
Object.defineProperty(global, "Dom", {
value: function (selector, context) {
return new Dom(selector, context);
},
});
Object.freeze(global.Dom);
})(window, document);
DOM API - 문서 프로그래밍 인터페이스
HTML, XML 문서를 오브젝트로 추상화하여 이들을 다루는 방법이 정의되어 있음.
DOM(Document Object Model) 선택 API 메서드
- getElementById()
- getElementsByTagName()
- getElementsByClassName()
- querySelector()
- querySelectorAll()
- matches()
Node(Element 상위 개념) 속성 - element, text 포함
- childNodes - 직계 자식만 가져옴
- children - 직계 요소 자식만 가져옴
- firstChild
- firstElementChild
- lastChild
- lastElementChild
- nextSibling
- nextElementSibling
- previousSibling
- previousElementSibling
- parentNode
- nodeType
- nodeName
- nodeValue(텍스트 노드에 접근해 string 가져오고 싶을 때는 textContent 사용 권장)