객체지향 자바스크립트 (정리본)

Kim jae-eok·2020년 5월 5일
3

객체지향 (정리본)

출처

https://developer.mozilla.org/ko/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

https://dev.to/educative/acing-the-javascript-interview-top-questions-explained-59b7#oop-in-javascript

The Class

  • class문을 흔하게 볼 수 있는 C++이나 자바와는 달리 자바스크립트는 class문이 포함되지 않은 프로토타입 기반 언어이다.
  • 자바스크립트에서는 function을 class로서 사용한다
    function Person() { }

The Object (Class Instance)

  • obj라는 이름의 객체의 새로운 인스턴스를 만들 때에는 new obj라는 statement를 사용하고, 차후에 접근할 수 있도록 변수에 결과를 받는다.

    function Person() { }
    var person1 = new Person();
    var person2 = new Person();

The Constructor (생성자)

  • 생성자는 인스턴스화되는 순간(객체 인스턴스가 생성되는 순간) 호출된다

  • 자바스크립트에서는 함수 자체가 그 객체의 생성자 역할을 하기 때문에 특별히 생성자 메서드를 정의할 필요가 없다.

  • 클래스 안에 선언된 모든 내역은 인스턴스화되는 그 시간에 실행된다

  • 생성자는 주로 객체의 속성을 설정하거나 사용하기 위해 객체를 준비시키는 메서드를 호출할 때 주로 사용된다.

  • 클래스 메서드를 추가하고 정의하는 것은 나중에 설명한다.

  • Person 클래스의 생성자는 Person 이 인스턴스화되었을 때 alert 을 보여주게 된다.

    function Person() {
      alert('Person instantiated');
    }
    
    var person1 = new Person();
    var person2 = new Person();

The Property (object attribute)

  • 속성은 클래스 안에 있는 변수들을 말한다.

  • 객체의 모든 인스턴스는 그 인스턴스의 속성을 갖는다

  • 속성들의 상속이 바르게 이루어지려면 해당 클래스(function)의 프로토타입에 선언되어 있어야 한다.

    function Person(gender) {
      this.gender = gender;
      alert('Person instantiated');
    }
    
    var person1 = new Person('Male');
    var person2 = new Person('Female');
    
    //display the person1 gender
    alert('person1 is a ' + person1.gender); // person1 is a Male

메서드(The methods)

  • 메서드는 속성과 같은 방식을 따른다

  • 메서드는 function이기 때문에 function 형태로 정의된다

  • 메서드를 호출하는 것은 속성에 접근하는 것과 매우 유사한데 단지 끝에 ()를 추가하면 된다

  • 메서드를 정의하기 위해서는 클래스의 prototype에 명명된 속성에 함수를 할당하면 된다

  • 이때 할당된 이름은 해당 객체의 메서드를 호출할 때 사용되는 이름이다.

    function Person(gender) {
      this.gender = gender;
      alert('Person instantiated');
    }
    
    Person.prototype.sayHello = function(){
      alert ('hello');
    };
    
    var person1 = new Person('Male');
    var person2 = new Person('Female');
    
    // call the Person sayHello method.
    person1.sayHello(); // hello
  • 자바스크립트에서 메서드는 "컨텍스트에 관계 없이" 호출될 수 있는 속성으로서 클래스/객체에 연결되어 있다.

    예제코드

      function Person(gender) {
        this.gender = gender;
      }
    
      Person.prototype.sayGender = function() {
        alert(this.gender);
      };
    
      var person1 = new Person('Male');
      var genderTeller = person1.sayGender;
    
      person1.sayGender(); // alerts 'Male'
      genderTeller(); // alerts undefined
      alert(genderTeller === person1.sayGender); // alerts true
      alert(genderTeller === Person.prototype.sayGender); // alerts true

  • 이 예제는 자바스크립트에 "per-object methods" 가 존재하지 않는다는 것을 보여준다.

    • avaScript는 메서드에 대한 레퍼런스가 모두 똑같은 (프로토타입에 처음 정의한) 함수를 참조하고 있기 때문이다.

    • 자바스크립트는 어떤 객체의 메서드로서 함수가 호출될 때 현재 "객체의 컨텍스트"를 특별한 this 변수에 "연결한다".

      • function 객체의 call 메서드를 호출하는 것과 동일하다.
      genderTeller.call(person1); //alerts 'Male'

상속(Inheritance)

  • 상속은 하나 이상의 클래스를 특별한 버전의 클래스로 생성하는 하나의 방법이다.

  • 자식 클래스(child)와 부모 클래스(parent)라고 정의

  • 자바스크립트에서는 부모 클래스의 인스턴스를 자식 클래스에 할당함으로써 상속이 이루어진다.

  • 최신 브라우저에서는 Object.create 메서드를 사용해서 상속을 수행할 수도 있다.

    예제코드

    아래의 예제에서는, Student라는 클래스를 Person 클래스의 자식 클래스로 정의한다.

    그 후에 우리는 sayHello() 메서드를 재정의하고 sayGoodBye() 메서드를 추가한다.
    // define the Person Class
    function Person() {}
    
    Person.prototype.walk = function(){
      alert ('I am walking!');
    };
    Person.prototype.sayHello = function(){
      alert ('hello');
    };
    
    // define the Student class
    function Student() {
      // Call the parent constructor
      Person.call(this);
    }
    
    // inherit Person
    Student.prototype = new Person();
    
    // correct the constructor pointer because it points to Person
    Student.prototype.constructor = Student;
    
    // replace the sayHello method
    Student.prototype.sayHello = function(){
      alert('hi, I am a student');
    }
    
    // add sayGoodBye method
    Student.prototype.sayGoodBye = function(){
      alert('goodBye');
    }
    
    var student1 = new Student();
    student1.sayHello();
    student1.walk();
    student1.sayGoodBye();
    
    // check inheritance
    alert(student1 instanceof Person); // true 
    alert(student1 instanceof Student); // true

  • Object.create 를 사용하면 상속을 아래와 같이 수행할 수 있다.

Student.prototype = Object.create(Person.prototype);

캡슐화(Encapsulation)

이전의 예제에서, Student 클래스는 Person 클래스의 walk() 메서드가 어떻게 실행되는지에 대해 알 필요가 없고, walk() 메서드를 사용하는데에도 전혀 문제가 없다. 또 Student 클래스에서는 walk() 메서드의 내용을 바꾸려는게 아니라면 walk() 메서드를 특별히 정의할 필요도 없다. 자식 클래스는 부모 클래스의 모든 메서드를 상속받고, 상속받은 메서드중 일부를 수정하고 싶은 경우에만 해당 메서드를 정의하는 것을 우리는 캡슐화(encapsulation)이라고 부른다.

추상화(Abstraction)

추상화는 작업 문제의 현재 부분을 모델링할 수 있도록 하는 매커니즘이다. 추상화는 상속(specialization, 추상의 수준을 낮추는 것)과 합성으로 구현할 수 있다. 자바스크립트는 상속에 의해 특별화(specialization)를, 클래스들의 인스턴스를 다른 객체의 속성값이 되게 함으로써 합성을 구현한다.

자바스크립트 Function 클래스는 Object 클래스를 상속받고(이는 모델의 특별화를 보여준다), Function.prototype 속성은 Object의 인스턴스이다(이는 합성을 보여준다).

다형성(Polymorphism)

모든 메서드와 속성들은 prototype 속성에 선언되어 있고, 클래스가 다르다면 같은 이름의 메서드도 선언할 수 있다. 메서드들은 메서드가 선언된 클래스로 그 실행 영역이 한정된다. 물론 이건 두 개의 클래스들이 서로 부모-자식 관계가 아닐때에만 성립한다. 즉 다시 말해 부모-자식 관계의 상속 관계로 하나가 다른 하나에게서 상속받지 않았을 때에만 성립한다.

문제

isPrototypeOf

function isPrototype(){
  var obj1 = {x: 1};
  var obj2;

  console.log(
    obj1.isPrototypeOf(obj2)  
  ); 

}
isPrototype()

Output: false

코드에서 true를 리턴하도록 obj2에 대한 코드를 작성하라는 요청을받습니다. obj2의 프로토 타입 체인의 일부가 되려면 obj1이 필요합니다. 변수 obj2에 저장할 객체를 만드는 Object.create 함수를 사용하여이 작업을 수행 할 수 있습니다. Object.create는이를 매개 변수로 사용하고 obj1을 가리키는 프로토 타입 속성을 가진 객체를 반환합니다. 이렇게하면 obj1이 프로토 타입 체인이되므로 Object.getPrototypeOf (obj2)는 ​​obj1로 반환됩니다.

function isPrototype(){
  var obj1 = {x: 1};
  var obj2 = Object.create(obj1)
  console.log(
    obj1.isPrototypeOf(obj2)       
);
} 
isPrototype()

Output: true

ES6 classes

function Cat (name) {
  this.name = name
}
Cat.meow = function () {
  console.log(this.name + ' says meow')
}
let catty = new Cat('catty')
catty.meow()

에러발생

오류를 해결하기 위해 코드를 수정하라는 메시지가 표시되지만 ES6 클래스 만 사용할 수 있습니다. 이 코드의 오류는 meow가 프로토 타입 Cat에 정의되어 있지 않기 때문에 오브젝트 catty에 의해 상속되지 않기 때문입니다. 프로토 타입으로 재정의해야하지만 키워드 함수를 클래스로 대체해야합니다.

class Cat {
  constructor (name) {
    this.name = name
  }

  meow () {
    console.log(this.name + ' says meow')
  }
}

let catty = new Cat('catty') 
catty.meow()

Output: catty says meow

Prototypal Inheritance

JavaScript는 프로토 타입 기반 상속 언어이므로 기술을 테스트하기 위해 이와 같은 질문을 기대할 수 있습니다. 다음 코드가 제공되었다고 가정하십시오.

function Human(name, age) {
    this.name = name;
    this.age = age;
};

function Man(name) {
};

function check(){
    var obj = new Man("Tommy Tan");
    console.log(obj.name) 
    console.log(obj instanceof Human) 
}
check()

Output: undefined false

휴먼 클래스와 휴먼 클래스 사이의 상속을 구현하라는 요청을받습니다. 코드가 성공적으로 컴파일되어야합니다. 해결책을 봅시다.

function Human(name, age) {
    this.name = name;
    this.age = age;
};

function Man(name,age) {
    Human.call(this, name, age);
};

Man.prototype = Object.create(Human.prototype);
Man.prototype.constructor = Man;


function check(){
    var obj = new Man("Tommy Tan",20);
    console.log(obj.name) 
    console.log(obj instanceof Human) 
}
check()

Human is the parent, which the child Man inherits. In order for Man to inherit its properties, we must call the constructor of the parent in Man’s constructor function. This will initialize members desired from the parent, name and age.

Human은 부모이며, Man 은 자식입니다. Man이 속성을 상속 받으려면 Man의 생성자 부모의 생성자를 호출해야합니다. 부모, 이름 및 연령에서 원하는 멤버를 초기화합니다.

Pure function

순수한 함수는 중요한 JavaScript 기술입니다. 문제 해결 능력을 테스트하는 이와 같은 질문을 기대할 수 있습니다.

다음 코드에는 부적절한 함수 addAndPrint가 있습니다. 순수한 기능으로 수정하십시오.

const addAndPrint = (a, b) => { 
  const sum = a+b;
  console.log(`The sum is ${sum}`);
  return sum;
};
const ans = addAndPrint(4,5)

Output: The sum is 9

먼저, 왜 기능이 불완전한 지 알아 내야합니다. addAndPrint는 외부 상태에 부정적인 부작용이없는 것으로 보입니다. 그러나 console.log 문에는 결과가 변경 가능한 객체의 돌연변이와 같은 side effect을 일으키지 않아야한다는 규칙을 위반하는 부작용이 있습니다. console.log를 제거하여 순수 함수로 변환해야합니다

const addAndPrint = (a, b) => { 
  const sum = a+b;
  return sum;
};
const ans = addAndPrint(4,5)
console.log("The sum is " + ans)

Shallow copying

JavaScript에서 얕은 복사에 대한 질문을 기대할 수 있습니다. 다음 코드가 주어지고 출력을 요청했다고 가정 해보십시오.

const girl = {
  name: 'Anna',
  info: { age: 20, number: 123 }
};

const newGirl = { ...girl };
newGirl.info.age = 30;
console.log(girl.info.age, newGirl.info.age);

올바른 출력은 30 30입니다. 왜 그렇습니까? 객체 girl 는 속성 nameinfo 를 가지고 있습니다. 스프레드 연산자를 사용하여 해당 객체의 속성을 newGirl 으로 복사하면 얕은 복사본이 만들어집니다. 객체는 JavaScript에서 참조를 통해 전달되므로 둘 다 참조를 공유합니다.

즉, 객체에 변수를 할당하면 해당 객체의 ID와 연결됩니다. girlnewGirl에 할당하면 newGirlgirl과 동일한 객체를 가리 키므로 속성이 변경되면 둘 다 변경됩니다.

Higher order functions

고차 함수에 대한 질문은 JavaScript 인터뷰에서 눈에 띄는 데 중요합니다. 이런 질문을 기대할 수 있습니다.

const func1 = function(num){
  return function(){
    if(typeof num == 'NaN'){
      return "Not a number"
    }else{
      return typeof(num)
    }
  }
}

고차 함수는 함수를 매개 변수로 승인하거나 함수를 출력으로 리턴하는 함수입니다. 코드를 살펴보면 func1이 함수를 매개 변수로 사용하지 않는다는 것을 알 수 있습니다. 그러나 2 행을 더 자세히 살펴보면 함수가 출력으로 함수를 반환한다는 것을 알 수 있습니다. 따라서 고차 함수입니다.

Hide and Show

또한 텍스트 숨기기 및 표시와 같은 DOM 관련 기능을 구현할 수있는 능력을 보여 주어야합니다. 예를 들어, 버튼을 클릭하면 Hello World!라는 텍스트가 숨겨지는 텍스트 숨기기 기능을 구현하라는 메시지가 표시됩니다. 솔루션을 살펴보십시오.

function hideShow() {
  var ele = document.getElementById("hideDiv");
  if (ele.style.display === "none") {
    ele.style.display = "block";
  } else {
    ele.style.display = "none";
  }
}

hideShow 함수를 실행하는 버튼과 텍스트가있는 div를 만듭니다. getElementById를 사용하여 해당 div 요소에 액세스합니다. 3 행에서 style.display 속성이 none (일명 숨김)인지 확인합니다. 참이면 display 속성을 block 으로 설정하여 요소를 표시합니다. False이면 표시 값을 none 으로 설정하여 숨깁니다.

profile
블로그 이전 중 (https://www.notion.so/My-blog-0d569b9028434fb6a99a3e66b6e807b1)

0개의 댓글