자바 스크립트의 구조체


112

이전에는 여러 관련 변수를 저장해야 할 때 클래스를 만들었습니다.

function Item(id, speaker, country) {
    this.id = id;
    this.speaker = spkr;
    this.country = country;
}
var myItems = [
    new Item(1, 'john', 'au'),
    new Item(2, 'mary', 'us')
];

그러나 이것이 좋은 습관인지 궁금합니다. Javascript에서 구조체를 시뮬레이션하는 다른 더 나은 방법이 있습니까?

답변:


184

객체 리터럴과 생성 된 객체의 유일한 차이점은 프로토 타입에서 상속 된 속성입니다.

var o = {
  'a': 3, 'b': 4,
  'doStuff': function() {
    alert(this.a + this.b);
  }
};
o.doStuff(); // displays: 7

구조체 팩토리를 만들 수 있습니다.

function makeStruct(names) {
  var names = names.split(' ');
  var count = names.length;
  function constructor() {
    for (var i = 0; i < count; i++) {
      this[names[i]] = arguments[i];
    }
  }
  return constructor;
}

var Item = makeStruct("id speaker country");
var row = new Item(1, 'john', 'au');
alert(row.speaker); // displays: john

27
... 그리고 공장 기능을 이해했습니다. +1은 공장 예시와 함께 명확하고 이해하기 쉽고 간결한 답변입니다.
John

이 접근 방식이 마음에 들지만 클로저 컴파일러를 사용하는 경우주의해야합니다. 이 경우 튜플은 속성 이름이 바뀌기 때문에 문자열로만 액세스 할 수 있습니다. (고급 모드에서 최소)
KAP

객체 리터럴에 비해이 방법의 효율성에 대해 궁금했습니다.
c0degeas

JS 클래스를 사용하는 것도 가능합니다.
SphynxTech

31

나는 항상 객체 리터럴을 사용합니다.

{id: 1, speaker:"john", country: "au"}

2
그렇게하면 유지 관리가 훨씬 더 어려워지고 (앞으로 새 필드를 추가해야하는 경우) 훨씬 더 많은 코드 (매번 "id", "speaker", "country"를 다시 입력)가 발생하지 않습니까?
nickf

5
JavaScript는 함수를 호출하는 인수의 수를 신경 쓰지 않기 때문에 클래스를 사용한 솔루션만큼 유지 관리가 가능합니다. Emacs와 같은 올바른 도구를 사용하는 경우 재 입력은 문제가되지 않습니다. 그리고 당신은 쓸모없는 주장을 바꾸는 것과 같은 실수를 만드는 것과 같은 것을 볼 수 있습니다.
vava

4
그러나 가장 큰 장점은 적은 코드를 작성하고 더 깨끗해질 것입니다. :)
vava

1
새로운 ___ (,,,) 아키타 입을 복사하는 것보다 더 많은 점프가 있기 때문에 @vava 재 입력은 여전히 ​​문제입니다. 또한 가독성이 없습니다. 코딩에 익숙해지면 머릿속이 new READABLE_PART(ignore everything in here)아닌 스캔하기 쉽고 자체 문서화가됩니다 {read: "ignore", everything: "ignore", in: "ignore", here: "ignore"} // and then come up with READABLE_PART. 첫 번째 버전은 빠르게 페이징하면서 읽을 수 있습니다. 두 번째는 이해하기 위해 구조체로 리팩토링하는 것입니다.
Christopher

19

진짜 문제는 언어의 구조가 참조 유형이 아닌 값 유형이어야한다는 것입니다. 제안 된 답변은 구조 대신 객체 (참조 유형)를 사용하는 것이 좋습니다. 이것이 그 목적을 달성 할 수 있지만, 프로그래머가 참조 유형 대신 값 유형 (프리미티브와 같은)을 사용하는 이점을 실제로 원한다는 점을 회피합니다. 값 유형은 메모리 누수를 일으키지 않아야합니다.


8

나는 당신이했던 것처럼 C와 같은 구조체를 시뮬레이션하는 클래스를 만드는 것이 가장 좋은 방법이라고 생각합니다.

관련 데이터를 그룹화하고 매개 변수를 함수에 전달하는 것을 단순화하는 좋은 방법입니다. 또한 실제 객체 지향 기능을 시뮬레이션하는 데 필요한 추가 노력을 고려할 때 JavaScript 클래스가 C ++ 클래스보다 C ++ 구조체와 비슷하다고 주장 합니다.

JavaScript를 다른 언어와 비슷하게 만들려는 시도가 빠르게 복잡하다는 것을 발견했지만 JavaScript 클래스를 함수없는 구조체로 사용하는 것을 완벽하게 지원합니다.


강력한 데이터의 수집을 입력 허용 뭔가 - - 컴파일 타임에 처리되며, 객체와 같은 HashMaps을의 오버 헤드가없는 나는 구조체, 튜플 같은 것을 가지고 싶어요
derekdreery

4

Markus의 답변에 따라 최신 버전의 JS (ES6 내 생각에)에서는 Arrow FunctionsRest Parameter 를 사용하여 더 간단하게 'struct'팩토리를 만들 수 있습니다 .

const Struct = (...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {}))
const Item = Struct('id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

이를 실행 한 결과는 다음과 같습니다.

[ { id: 1, speaker: 'john', country: 'au' },
  { id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

Python의 namedtuple과 비슷하게 만들 수 있습니다.

const NamedStruct = (name, ...keys) => ((...v) => keys.reduce((o, k, i) => {o[k] = v[i]; return o} , {_name: name}))
const Item = NamedStruct('Item', 'id', 'speaker', 'country')
var myItems = [
    Item(1, 'john', 'au'),
    Item(2, 'mary', 'us')
];

console.log(myItems);
console.log(myItems[0].id);
console.log(myItems[0].speaker);
console.log(myItems[0].country);

결과 :

[ { _name: 'Item', id: 1, speaker: 'john', country: 'au' },
  { _name: 'Item', id: 2, speaker: 'mary', country: 'us' } ]
1
john
au

C / C ++ 및 기타 언어의 구조체처럼 보이지만 실제로는 그렇지 않습니다. 객체의 속성은 다음과 같이 순서가 보장되지 않습니다. ECMAScript Third Edition의 객체 정의 (pdf) : 4.3.3 객체 개체는 개체 유형의 구성원입니다. 이는 각각 원시 값, 객체 또는 함수를 포함하는 순서없는 속성 모음입니다. 객체의 속성에 저장하는 함수는 메소드 호출
tibetty


1

ES6 호환성으로 작업하는 경우 구조체를 정의하기 위해 작은 라이브러리를 만들었습니다.

여기에서 프로젝트 저장소를 확인할 수있는 JKT 파서입니다. JKT 파서

예를 들어 다음과 같이 구조체를 만들 수 있습니다.

const Person = jkt`
    name: String
    age: Number
`

const someVar = Person({ name: "Aditya", age: "26" })

someVar.name // print "Aditya"
someVar.age // print 26 (integer)

someVar.toJSON() // produce json object with defined schema 

0

설정하는 데 더 많은 작업이 필요하지만 유지 관리가 한 번의 노력을 능가한다면 이것이 귀하의 경우가 될 수 있습니다.

/**
 * @class
 */
class Reference {

    /**
     * @constructs Reference
     * @param {Object} p The properties.
     * @param {String} p.class The class name.
     * @param {String} p.field The field name.
     */
    constructor(p={}) {
        this.class = p.class;
        this.field = p.field;
    }
}

장점 :

  • 인수 순서에 구속되지 않음
  • 쉽게 확장 가능
  • 유형 스크립트 지원 :

여기에 이미지 설명 입력

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.