본문 바로가기
JavaScript & JQuery

[생활코딩] this, call, 프로토타입, 상속 등 개

by 작심평생 2019. 6. 9.

// this

/*
var kim = {
name : 'kim',
first : 10,
second : 20,
sum : function(f, s){
return f+s;
}
}
console.log(kim.sum(kim.first, kim.second));
*/

var kim = {
name : 'kim',
first : 10,
second : 20,
sum : function(){
return this.first+this.second; // 메소드가 속해있는 객체를 가리키는 것 = this
// 왜? 유연성! kim이건 k이건 상관 없음. 그 객체를 가리키기 떄문
}
}
console.log("this이용", kim.sum());


자바스크립트에선 함수도 객체...!

this
: 함수에서는 (window.)abc();  생략된 것임. 즉, 함수를 호출할 때 this는 widow를 가리킴
  • 함수는 이런 형태
            ex) function Func(){
            funcThis = this;
            }

var o2 = new Func();
if(funcThis === o2){
document.write('o2 <br />');
}

만약 이렇게 new를 통해서 생성자를 호출하게 되면 객체를 만들게 되고 이는 o2에 담기게 되는 것이다. 이때 this는 생성자가 만든 객체(o2인듯.)를 가리킴.
하지만 Func()에 if(o2 == this){}를 추가하게 된다면 undefined가 나오게 됨. ==> Func()를 다 실행 후에 o2에 할당이 되는 것이기 때문.




apply & call
: this값을 제어할 수 있음.

[ 들어가기 앞서...tip ] 
=> function sum(x,y) {return x+y;} 는 var sum = new Function('x','y','return x+y;'); 와 같은 의미. 이를 함수 리터럴(literal)이라고 함.
=> 여기서 sum은 객체고 객체는 프로퍼티(속성)을 가질 수 있음.

var o = {} // 객체생성
var p = {} // 객체생성
function func(){
switch(this){
case o:
document.write('o<br />');
break;
case p:
document.write('p<br />');
break;
case window:
document.write('window<br />');
break;
}
}
func(); // this는 window를 가리킴
func.apply(o); // this는 o를 가리킴
func.apply(p); // this는 p를 가리킴

이처럼 .apply는 함수를 호출함.

apply 형식 => apply(객체(없으면null), [인자값1, 인자값2,...]); 인자값이 없으면 생략가능.
apply와 this를 잘 사용하면 마치 파라미터 값을 가진 것 처럼 동작하게 해줌.



상속(inheritance)
: 객체의 로직을 그대로 물려받은 또 다른 객체를 만들 수 있는 기능. 기존 로직 수정, 변경해서 파생된 새로운 객체를 만들 수 있게 해준다.



상속의 위한 준비로, 생성자를 통해서 프로퍼티를 셋팅할 수 도 있고 아래 처럼 셋팅할 수도 있음. (프로퍼티 : 객체를 생성할 때 객체가 기본적으로 가지고 있어야할 속성)
여기서 prototype라는 프로터티에 name이라는 프로퍼티를 준 것. prototype에는 어떤 객체가 들어가 있고 .name을 통해 값을 넣어주는 것.

function Person(name){
this.name = name;
}
Person.prototype.name=null;
Person.prototype.introduce = function(){
return 'My name is '+this.name;
}
function Programmer(name){
this.name = name;
}
Programmer.prototype = new Person(); // Person이란 객체를 prototype에 상속받게 되어 introduce를 사용할 수 있게 됨
var p1 = new Programmer('egoing');
document.write(p1.introduce()+"<br />");

위의 코드를 보면 일단 쉽게 이해하기 위해선, 
어떤 객체(Person)를 상속받고 싶다면 그 객체를 생성자(Programmer)의 prototype에 할당시키면된다!

동작원리를 설명해보자면,,,,(19.05.14 이해기준)
: new Person(); 을 하면 Person이라는 생성자에 의해 객체가 생성이 되는데 이때 prototype 이라는 속성을 생성자 함수가 가지고 있는지 자바스크립트가 확인함. (Person.prototype 이부분)
  그러면 생성자 함수(Person) 안에 있는 객체(name, introduce)와 똑같은 객체를 리턴해줌. (복제느낌인데..)

즉, 여기선 Person 객체가 만들어지는데 name이 null이고 introduce 함수를 가지고 있는 객체가 만들어지게 되고 이게 Programmer의 prototype으로 할당이 됨.
그 상태에서 new programmer를 통해 programmer가 '객체화' 되고 앞에서 나온 programmer.prototype(programmer 객체의 속성 prototype의 어떤 객체에 Person 객체가 담겨있는 상태)를 보면 '객체화'가 되었기 때문에 programmer라는 객체의 속성값인 prototype도 이용할 수 있다...! 뭐 이런 식인듯함..


prototype(프로토타입)
prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결된다. 

var o = new Sub(); 이거나 var o = {}; 둘 다 객체를 만드는 방법이다. 전자는 생성자 함수를 불러서 만들고 후자는 객체 리터럴을 이용하는 것
하지만 둘은 차이가 있음! 후자는 그냥 빈 객체을 전달해주는 것이고 전자처럼 생성자를 이용해서 객체를 만드는 경우
해당 생성자함수의 prototype의 property에 저장되어있는 객체를 꺼내서 리턴해주게 되는것!

function Ultra(){}
Ultra.prototype.ultraProp = true;
function Super(){}
Super.prototype = new Ultra();
function Sub(){}
Sub.prototype = new Super();
var o = new Sub();
console.log(o.ultraProp);

생성자 Sub를 통해서 만들어진 객체 o가 Ultra의 프로퍼티 ultraProp에 접근 가능한 것은 prototype 체인으로 Sub와 Ultra가 연결되어 있기 때문이다. 내부적으로는 아래와 같은 일이 일어난다.
  1. 객체 o에서 ultraProp를 찾는다.
  2. 없다면 Sub.prototype.ultraProp를 찾는다.
  3. 없다면 Super.prototype.ultraProp를 찾는다.
  4. 없다면 Ultra.prototype.ultraProp를 찾는다.
prototype는 객체와 객체를 연결하는 체인의 역할을 하는 것이다. 이러한 관계를 prototype chain이라고 한다.
주의할점으로  Super.prototype = Ultra.prototype 으로하면 안된다. 이렇게하면 Super.prototype의 값을 변경하면 그것이 Ultra.prototype도 변경하기 때문
Super.prototype = new Ultra();는 Ultra.prototype의 원형으로 하는 객체가 생성되기 때문에 
new Ultra()를 통해서 만들어진 객체에 변화가 생겨도 Ultra.prototype의 객체에는 영향을 주지 않는다.


표준내장객체(Standard Built-in Object)
: 자바스크립트가 기본적으로 가지고 있는 객체들을 의미
: 자바스크립트 내장 객체 : Object, Function, Array, String, Boolean, Number, Math, Date, RegExp(정규표현식)
: 하지만 호스트환경에 따라 더 많을 수 있음. (즉, html이라면 내장 객체가 위에 꺼에 더 추가되는 것)




Object
: Object객체는 가장 기본적인 형태를 가지고 있는 객체 (= 아무것도 상속받지 않은 순수한 객체)
: 모든 객체는 Object 객체를 상속받음(암시적으로)

https://developer.mozilla.org/ko/ 참고하면 좋은 URL(MDN) 자바스크립트, 여기서 API 확인할때 Browse(브라우저버젼), Specifications(에크마스크립트 버젼) 호환 확인하자.

  • Object.key() : Key값을 출력해줌 => 사용은 Object.key(인자값) 여기서 Object는 생성자함수.
  • Object.prototype.toString() : 객체가 가지고 있는 값이나 상태를 사람이 보기 편하게 출력.=> 사용은 .toString()

여기서 주목해야하는건 어떤건 Object.~ 어떤건 Object.prototype.~ 이런 형식
사용하는 방법이 다름! => 인자를 받아야하거나 그냥 쓰거나

즉, prototype으로 정의되어 있다면 new ~();를 했을 때 사용할 수 있게 됨. 왜냐면 암시적으로 Object를 상속받고 있기 때문이고 toString은
Object.prototype.toString이기 때문에 이 기능을 사용할 수 있는 것.

Object객체의 확장
: 이역시 prototype을 이용해서 function을 만들어 정의하면 되는데 권장하지 않음.
: 왜냐하면 모든 객체에 영향을 주기 때문이다. 

Object.prototype.contain = function(neddle) {
for(var name in this){
if(this[name] === neddle){
return true;
}
}
return false;
}
var o = {'name':'egoing', 'city':'seoul'}
console.log(o.contain('egoing'));
var a = ['egoing','leezche','grapittie'];
console.log(a.contain('leezche'));

이렇게 소스코드를 구성하고 콘솔에서 실행을 시킨다 했을 때
0를 출력해보면, 위에와 다르게 contain이라는게 추가되어 있는 모습을 보임. 그래서 for - in문에서 Object 확장 시 작성한 함수가 같이 출력이 됨
==> 우리가 정의한 {'name':'egoing', 'city':'seoul'}도 Object이기 때문에 contain이 암시적으로 포함되어져 버린 것. a도 마찬가지.

  • .hasOwnpProperty(인자) : 해당 객체가 인자로 전달한 값을 자신의 property로 '직접적으로' 가지고 있는지 체크(true/false) - 상속받은게 아닌.



원시데이터 타입(primitive type)
: =기본 데이터 타입
: 객체 데이터 타입(=참조 데이터 타입)과 반대
: 숫자, 문자열, 불리언, null, undefined가 원시 데이터 타입임.

래퍼 객체
: Number, String, Boolean 이 있음. null, undefinded는 없음.
: 원시 데이터형을 객체처럼 다룰 수 있도록 하기 위한 객체.
: 자바스크립트는 자동으로 처리해줌.



참조 / 복제
: 원시 데이터 타입인 경우 복제가 발생.
: 반면 변수에 담겨있는 데이터가 객체면 참조가 발생.

함수에서는..? =마찬가지!




댓글