IT

JavaScript의 상속 유형 상속의 좋은 예

lottoking 2020. 9. 9. 08:14
반응형

JavaScript의 상속 유형 상속의 좋은 예


저는 10 년 넘게 OOP 언어로 해 왔지만 지금은 JavaScript를 배우고 처음부터 프로그래밍 기반 상속을 접한 것입니다. 저는 좋은 코드를 공부하여 가장 빨리 배우는 경향이 있습니다. 유형 유형 상속을 사용하는 JavaScript 애플리케이션 (또는 라이브러리)의 잘 보관 예는 무엇입니까? 그리고 어디에서 어디서부터 읽기를 시작해야합니까?


Douglas Crockford에는 JavaScript Prototypal Inheritance 에 대한 멋진 페이지가 있습니다 .

5 년 전에 저는 JavaScript로 Classical Inheritance작성 합니다. JavaScript는 클래스가없는 표현력이있는 언어이며 클래식 시스템을 시뮬레이션한다는 표현력을 가지고 있습니다. 내 프로그래밍 스타일은 좋은 프로그래머가해야하는 것처럼 그 이후로 발전했습니다. 나는 고전적 모델의 한계에서 벗어나 자신을 해방 정당습니다.

Dean Edward의 Base.js , Mootools의 클래스 또는 John Resig의 단순 상속 작업은 JavaScript에서 고전적인 상속 을 수행하는 방법 입니다.


Douglas Crockford의 영화는 이유에 대한 좋은 설명을 제공하며 방법을 다룹니다. 그러나 몇 줄의 JavaScript에 있는지 여부 :

// Declaring our Animal object
var Animal = function () {

    this.name = 'unknown';

    this.getName = function () {
        return this.name;
    }

    return this;
};

// Declaring our Dog object
var Dog = function () {

    // A private variable here        
    var private = 42;

    // overriding the name
    this.name = "Bello";

    // Implementing ".bark()"
    this.bark = function () {
        return 'MEOW';
    }  

    return this;
};


// Dog extends animal
Dog.prototype = new Animal();

// -- Done declaring --

// Creating an instance of Dog.
var dog = new Dog();

// Proving our case
console.log(
    "Is dog an instance of Dog? ", dog instanceof Dog, "\n",
    "Is dog an instance of Animal? ", dog instanceof Animal, "\n",
    dog.bark() +"\n", // Should be: "MEOW"
    dog.getName() +"\n", // Should be: "Bello"
    dog.private +"\n" // Should be: 'undefined'
);

그러나이 방법의 발생은 개체를 만들 때마다 개체를 다시 생성 것입니다. 또 다른 접근 방식은 다음과 같이 준비된 스택에서 선언하는 것입니다.

// Defining test one, prototypal
var testOne = function () {};
testOne.prototype = (function () {
    var me = {}, privateVariable = 42;
    me.someMethod = function () {
        return privateVariable;
    };

    me.publicVariable = "foo bar";
    me.anotherMethod = function () {
        return this.publicVariable;
    };

    return me;

}());


// Defining test two, function
var testTwo = ​function() {
    var me = {}, privateVariable = 42;
    me.someMethod = function () {
        return privateVariable;
    };

    me.publicVariable = "foo bar";
    me.anotherMethod = function () {
        return this.publicVariable;
    };

    return me;
};


// Proving that both techniques are functionally identical
var resultTestOne = new testOne(),
    resultTestTwo = new testTwo();

console.log(
    resultTestOne.someMethod(), // Should print 42
    resultTestOne.publicVariable // Should print "foo bar"
);

console.log(
    resultTestTwo.someMethod(), // Should print 42
    resultTestTwo.publicVariable // Should print "foo bar"
);



// Performance benchmark start
var stop, start, loopCount = 1000000;

// Running testOne
start = (new Date()).getTime(); 
for (var i = loopCount; i>0; i--) {
    new testOne();
}
stop = (new Date()).getTime();

console.log('Test one took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');



// Running testTwo
start = (new Date()).getTime(); 
for (var i = loopCount; i>0; i--) {
    new testTwo();
}
stop = (new Date()).getTime();

console.log('Test two took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');

자기 성찰과 관련하여 약간의 단점이 있습니다. testOne을 덤핑하면 정보가 덜 유용합니다. 또한 "testOne"의 개인 속성 "privateVariable"은 모든 경우에 공유되며 shesek의 답변에서 유용하게 참조됩니다.


function Shape(x, y) {
    this.x = x;
    this.y = y;
}

// 1. Explicitly call base (Shape) constructor from subclass (Circle) constructor passing this as the explicit receiver
function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r = r;
}

// 2. Use Object.create to construct the subclass prototype object to avoid calling the base constructor
Circle.prototype = Object.create(Shape.prototype);

나는 YUI 와 Dean Edward의 Base도서관을 상상 볼 것입니다 : http://dean.edwards.name/weblog/2006/03/base/

YUI의 경우 lang 모듈 , esp를 빠르게 살펴볼 수 있습니다 . YAHOO.lang.extend의 방법. 그런 다음 일부 위젯 또는 유틸리티의 소스를 찾아보고 해당 방법을 사용하는 방법을 볼 수 있습니다.


Microsoft의 ASP.NET Ajax 라이브러리, http://www.asp.net/ajax/도 있습니다.

객체 지향 기술을 사용 하여 고급 웹 응용 프로그램 만들기를 포함 하여 좋은 MSDN 가이드도 많이 있습니다.


다음은 Mixu의 Node 책 ( http://book.mixu.net/node/ch6.html ) 에서 가장 명확한 예입니다 .

상속보다 구성을 선호합니다.

구성-개체의 기능은 다른 개체의 인스턴스를 포함하여 서로 다른 클래스의 집합체로 구성됩니다. 상속-객체의 기능은 자체 기능과 상위 클래스의 기능으로 구성됩니다. 상속이 필요한 일반 오래된 JS를 사용하십시오.

상속을 구현해야한다면, 또 다른 비표준 구현을 사용하지 않습니다. 다음은 순수 ES3에서 합산 ​​팩스를 구현하는 방법입니다 (프로토 타입에서 속성을 정의하지 않는 규칙을 따르는 한).

function Animal(name) {
  this.name = name;
};
Animal.prototype.move = function(meters) {
  console.log(this.name+" moved "+meters+"m.");
};

function Snake() {
  Animal.apply(this, Array.prototype.slice.call(arguments));
};
Snake.prototype = new Animal();
Snake.prototype.move = function() {
  console.log("Slithering...");
  Animal.prototype.move.call(this, 5);
};

var sam = new Snake("Sammy the Python");
sam.move();

이것은 고전적인 상속과는입니다. 그러나 표준 생성에서는 이해하기 쉬운 자바 선언이며 사람들이 주로 찾는 기능을 가지고 있습니다 : 체인 가능한 수퍼 자와 클래스의 메소드를 호출하는 능력.


ES6 classextends

ES6 classextends이전에 가능한 조합 식 체인 단지 구문, 그래서 틀림없이 가장 표준적인 설정입니다.

먼저 https://stackoverflow.com/a/23877420/895245. 에서 프로토-type 체인 및 속성 조회에 대해 자세히 알아보십시오 .

이제 무슨 일이 일어나는지 분해 해 봅시다.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// https://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

사전 정의 된 모든 개체가없는 단순화 된 다이어그램 :

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

PrototypeJS의 Class.create :
83 행 @ http://prototypejs.org/assets/2009/8/31/prototype.js를 보는 것이 좋습니다 .


내가 본 최고의 예는 Douglas Crockford의 JavaScript : The Good Parts에 있습니다. 언어에 대한 균형 잡힌 견해를 제공하기 위해 구매할 가치가 있습니다.

Douglas Crockford 는 JSON 형식을 담당하며 Yahoo에서 JavaScript 전문가가 일하고 있습니다.


ECMAScript 버전 별 구현 이있는 스 니펫 JavaScript 유형 기반 상속 이 있습니다. 현재 실행에 따라 ES6, ES5 및 ES3 구현 중 사용할 항목을 자동으로 선택합니다.


Javascript에서 Prototype 기반 상속의 예를 추가합니다.

// Animal Class
function Animal (name, energy) {
  this.name = name;
  this.energy = energy;
}

Animal.prototype.eat = function (amount) {
  console.log(this.name, "eating. Energy level: ", this.energy);
  this.energy += amount;
  console.log(this.name, "completed eating. Energy level: ", this.energy);
}

Animal.prototype.sleep = function (length) {
  console.log(this.name, "sleeping. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "completed sleeping. Energy level: ", this.energy);
}

Animal.prototype.play = function (length) {
  console.log(this.name, " playing. Energy level: ", this.energy);
  this.energy -= length;
  console.log(this.name, "completed playing. Energy level: ", this.energy);
}

// Dog Class
function Dog (name, energy, breed) {
  Animal.call(this, name, energy);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function () {
  console.log(this.name, "barking. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "done barking. Energy level: ", this.energy);
}

Dog.prototype.showBreed = function () {
  console.log(this.name,"'s breed is ", this.breed);
}

// Cat Class
function Cat (name, energy, male) {
  Animal.call(this, name, energy);
  this.male = male;
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.meow = function () {
  console.log(this.name, "meowing. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "done meowing. Energy level: ", this.energy);
}

Cat.prototype.showGender = function () {
  if (this.male) {
    console.log(this.name, "is male.");
  } else {
    console.log(this.name, "is female.");
  }
}

// Instances
const charlie = new Dog("Charlie", 10, "Labrador");
charlie.bark();
charlie.showBreed();

const penny = new Cat("Penny", 8, false);
penny.meow();
penny.showGender();

ES6는 생성자와 슈퍼 키워드를 사용하는 것보다 훨씬 더 쉬운 상속 구현을 사용합니다.

참고 URL : https://stackoverflow.com/questions/2064731/good-example-of-javascripts-prototype-based-inheritance

반응형