[javascript] 자바 스크립트로 객체 확장

현재 Java에서 Javascript로 변환 중이며 원하는 방식으로 객체를 확장하는 방법을 알아내는 것이 약간 어렵습니다.

인터넷의 여러 사람들이 extend on object라는 방법을 사용하는 것을 보았습니다. 코드는 다음과 같습니다.

var Person = {
   name : 'Blank',
   age  : 22
}

var Robot = Person.extend({
   name : 'Robo',
   age  : 4
)}

var robot = new Robot();
alert(robot.name); //Should return 'Robo'

누구나이 작업을 수행하는 방법을 알고 있습니까? 나는 당신이 쓸 필요가 있다고 들었습니다

Object.prototype.extend = function(...);

그러나이 시스템을 작동시키는 방법을 모르겠습니다. 가능하지 않은 경우 객체를 확장하는 다른 대안을 제시하십시오.



답변

Person의 프로토 타입 객체에서 ‘상속’하려고합니다.

var Person = function (name) {
    this.name = name;
    this.type = 'human';
};

Person.prototype.info = function () {
    console.log("Name:", this.name, "Type:", this.type);
};

var Robot = function (name) {
    Person.apply(this, arguments);
    this.type = 'robot';
};

Robot.prototype = Person.prototype;  // Set prototype to Person's
Robot.prototype.constructor = Robot; // Set constructor back to Robot

person = new Person("Bob");
robot = new Robot("Boutros");

person.info();
// Name: Bob Type: human

robot.info();
// Name: Boutros Type: robot


답변

“새”키워드가없는 세계.

그리고 Object.create ()를 사용하여 더 간단한 “동일한”구문.

*이 예제는 ES6 클래스 용으로 업데이트되었습니다.

우선, 자바 스크립트는 프로토 타입 언어 입니다. 클래스 기반이 아닙니다. 따라서 프로토 타입 형태로 글을 쓰면 그 본질이 드러나고 매우 단순하고 산문적이며 강력 할 수 있습니다.

TLDR;

const Person = { name: 'Anonymous' } // person has a name

const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'

아니요, 생성자가 필요하지 않으며 new인스턴스화 가 필요하지 않습니다 ( 사용하지 않아야하는 이유를 읽으십시오new ). 아니요 . super재미가 없습니다 __construct. 단순히 객체를 만든 다음 확장하거나 모핑합니다.

( 당신이 getter 및 setter에 대해 알고있는 경우, 섹션이 패턴은 자바 스크립트가했던 방법으로 당신에게 무료 getter 및 setter를 제공하는 방법을보고 “추가 읽기”를 참조 원래 의도, 그리고 얼마나 강력한 그들이 .)

산문과 같은 구문 : Base protoype

const Person = {

   //attributes
   firstName : 'Anonymous',
   lastName: 'Anonymous',
   birthYear  : 0,
   type : 'human',

   //methods
   name() { return this.firstName + ' ' + this.lastName },
   greet() {
       console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' )
   },
   age() {
      // age is a function of birth time.
   }
}

const person = Object.create(Person). // that's it!

한눈에, 매우 읽기 쉽게 보입니다.

확장,의 자손 만들기 Person

* 올바른 용어는 prototypes, 그 descendants. 아무 없습니다 classes, 그리고 필요 instances.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'

const anakin = Object.create(Skywalker)
anakin.firstName = 'Anakin'
anakin.birthYear = '442 BBY'
anakin.gender = 'male' // you can attach new properties.
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'

Person.isPrototypeOf(Skywalker) // outputs true
Person.isPrototypeOf(anakin) // outputs true
Skywalker.isPrototypeOf(anakin) // outputs true

를 만드는 “기본”방법을 제공하는 한 가지 방법 descendant#create메소드 를 첨부하는 것입니다.

Skywalker.create = function(firstName, gender, birthYear) {

    let skywalker = Object.create(Skywalker)

    Object.assign(skywalker, {
        firstName,
        birthYear,
        gender,
        lastName: 'Skywalker',
        type: 'human'
    })

    return skywalker
}

const anakin = Skywalker.create('Anakin', 'male', '442 BBY')

아래 방법은 가독성이 떨어집니다.

“클래식”동등 항목과 비교하십시오.

function Person (firstName, lastName, birthYear, type) {
    this.firstName = firstName
    this.lastName = lastName
    this.birthYear = birthYear
    this.type = type
}

// attaching methods
Person.prototype.name = function() { return firstName + ' ' + lastName }
Person.prototype.greet = function() { ... }
Person.prototype.age = function() { ... }

function Skywalker(firstName, birthYear) {
    Person.apply(this, [firstName, 'Skywalker', birthYear, 'human'])
}

// confusing re-pointing...
Skywalker.prototype = Person.prototype
Skywalker.prototype.constructor = Skywalker

const anakin = new Skywalker('Anakin', '442 BBY')

Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns false!

“클래식”스타일을 사용한 코드 가독성은 그리 좋지 않습니다.

ES6 수업

분명히, 이러한 문제 중 일부는 ES6 클래스에 의해 제거되지만 여전히 :

class Person {
    constructor(firstName, lastName, birthYear, type) {
        this.firstName = firstName
        this.lastName = lastName
        this.birthYear = birthYear
        this.type = type
    }
    name() { return this.firstName + ' ' + this.lastName }
    greet() { console.log('Hi, my name is ' + this.name() + ' and I am a ' + this.type + '.' ) }
}

class Skywalker extends Person {
    constructor(firstName, birthYear) {
        super(firstName, 'Skywalker', birthYear, 'human')
    }
}

const anakin = new Skywalker('Anakin', '442 BBY')

// prototype chain inheritance checking is partially fixed.
Person.isPrototypeOf(anakin) // returns false!
Skywalker.isPrototypeOf(anakin) // returns true

기본 프로토 타입 분기

// create a `Robot` prototype by extending the `Person` prototype:
const Robot = Object.create(Person)
Robot.type = 'robot'
Robot.variant = '' // add properties for Robot prototype

고유 한 메소드 첨부 Robot

// Robots speak in binaries, so we need a different greet function:
Robot.machineGreet = function() { /*some function to convert strings to binary */ }

// morphing the `Robot` object doesn't affect `Person` prototypes
anakin.greet() // 'Hi, my name is Anakin Skywalker and I am a human.'
anakin.machineGreet() // error

상속 확인

Person.isPrototypeOf(Robot) // outputs true
Robot.isPrototypeOf(Skywalker) // outputs false

당신은 당신이 이미 필요한 모든 것을 가지고 있습니다! 생성자도없고 인스턴스도 없습니다. 깨끗하고 명확한 산문.

추가 자료

쓰기 가능성, 구성 가능성 및 무료 Getter 및 Setter!

무료 게터 및 세터 또는 추가 구성의 경우 Object.create ()의 두 번째 인수 인 propertiesObject를 사용할 수 있습니다. # Object.defineProperty# Object.defineProperties 에서도 사용할 수 있습니다 .

이것이 얼마나 강력한지를 설명하기 위해 모두 Robot가 엄격하게 금속으로 만들어지고 (비아를 통해 writable: false) powerConsumption값을 표준화 하기를 원한다고 가정하십시오 (게터 및 세터를 통해).

const Robot = Object.create(Person, {
    // define your property attributes
    madeOf: {
        value: "metal",
        writable: false,
        configurable: false,
        enumerable: true
    },
    // getters and setters, how javascript had (naturally) intended.
    powerConsumption: {
        get() { return this._powerConsumption },
        set(value) {
            if (value.indexOf('MWh')) return this._powerConsumption = value.replace('M', ',000k')
            this._powerConsumption = value
            throw new Error('Power consumption format not recognised.')
        }
    }
})

const newRobot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

그리고의 모든 프로토 타입은 다른 Robot것이 될 수 없습니다 .madeOfwritable: false

const polymerRobot = Object.create(Robot)

polymerRobot.madeOf = 'polymer'

console.log(polymerRobot.madeOf) // outputs 'metal'

믹스 인 (# Object.assign 사용)-Anakin Skywalker

어디로 가는지 알 수 있습니까?

const darthVader = Object.create(anakin)
// for brevity, property assignments are skipped because you get the point by now.

Object.assign(darthVader, Robot)

다스 베이더는 다음의 방법을 얻습니다 Robot.

darthVader.greet() // inherited from `Person`, outputs "Hi, my name is Darth Vader..."
darthVader.machineGreet() // inherited from `Robot`, outputs 001010011010...

다른 이상한 것들과 함께 :

console.log(darthVader.type) // outputs robot.
Robot.isPrototypeOf(darthVader) // returns false.
Person.isPrototypeOf(darthVader) // returns true.

다스 베이더가 사람인지 기계인지는 실제로 주관적입니다.

“그는 지금 사람보다 기계가 많고 뒤틀리고 사악합니다.” -오비완 케노비

“당신에게 좋은 것이 있다는 것을 알고 있습니다.” – 루크 스카이 워커

추가-# Object.assign을 사용하여 약간 더 짧은 구문

이 패턴은 구문을 단축시킵니다. 그러나 ES6 # Object.assign은 더 짧아 질 수 있습니다 (오래된 브라우저에서 폴리 필을 사용하려면 ES6의 MDN 참조 ).

//instead of this
const Robot = Object.create(Person)
Robot.name = "Robot"
Robot.madeOf = "metal"

//you can do this
const Robot = Object.create(Person)
Object.assign(Robot, {
    name: "Robot",
    madeOf: "metal"
    // for brevity, you can imagine a long list will save more code.
})


답변

아직 방법을 찾지 못한 경우 JavaScript 객체의 연관 속성을 사용하여 Object.prototype아래와 같이 확장 기능을 추가하십시오 .

Object.prototype.extend = function(obj) {
   for (var i in obj) {
      if (obj.hasOwnProperty(i)) {
         this[i] = obj[i];
      }
   }
};

그런 다음 아래와 같이이 기능을 사용할 수 있습니다.

var o = { member: "some member" };
var x = { extension: "some extension" };

o.extend(x);


답변

다른 접근 방식 : Object.create

@osahyoun 답변에 따라 Person의 프로토 타입 객체에서 ‘상속’하는 더 좋고 효율적인 방법으로 다음을 발견했습니다.

function Person(name){
    this.name = name;
    this.type = 'human';
}

Person.prototype.info = function(){
    console.log("Name:", this.name, "Type:", this.type);
}

function Robot(name){
    Person.call(this, name)
    this.type = 'robot';
}

// Set Robot's prototype to Person's prototype by
// creating a new object that inherits from Person.prototype,
// and assigning it to Robot.prototype
Robot.prototype = Object.create(Person.prototype);

// Set constructor back to Robot
Robot.prototype.constructor = Robot;

새 인스턴스를 작성하십시오.

var person = new Person("Bob");
var robot = new Robot("Boutros");

person.info(); // Name: Bob Type: human
robot.info();  // Name: Boutros Type: robot

이제 사용하여 Object.create를 :

Person.prototype.constructor !== Robot

MDN 설명서 도 확인하십시오 .


답변

ES6 에서는 다음과 같은 스프레드 연산자를 사용할 수 있습니다

var mergedObj = { ...Obj1, ...Obj2 };

Object.assign ()은 setter를 트리거하지만 스프레드 구문은 그렇지 않습니다.

자세한 내용은 link, MDN -Spread Syntax를 참조하십시오.


기존 답변 :

ES6 에는 Object.assign속성 값을 복사하는 것이 있습니다. {}대상 객체를 수정하지 않으려는 경우 첫 번째 매개 변수로 사용하십시오 (첫 번째 매개 변수가 전달됨).

var mergedObj = Object.assign({}, Obj1, Obj2);

자세한 내용은 MDN 링크 -Object.assign ()을 참조하십시오.

ES5 용 Polyfill 이 필요한 경우 링크에서도 제공합니다. 🙂


답변

그리고 1 년 후 또 다른 좋은 답변이 있다고 말할 수 있습니다.

객체 / 클래스를 확장하기 위해 프로토 타이핑이 작동하는 방식이 마음에 들지 않으면 https://github.com/haroldiedema/joii를 살펴보십시오.

가능성에 대한 간단한 예제 코드 (및 그 이상) :

var Person = Class({

    username: 'John',
    role: 'Employee',

    __construct: function(name, role) {
        this.username = name;
        this.role = role;
    },

    getNameAndRole: function() {
        return this.username + ' - ' + this.role;
    }

});

var Manager = Class({ extends: Person }, {

  __construct: function(name)
  {
      this.super('__construct', name, 'Manager');
  }

});

var m = new Manager('John');
console.log(m.getNameAndRole()); // Prints: "John - Manager"


답변

간단하고 최상의 접근 방식으로 여전히 어려움을 겪고있는 사람들은 Spread Syntax객체를 확장 하는 데 사용할 수 있습니다 .

var person1 = {
      name: "Blank",
      age: 22
    };

var person2 = {
      name: "Robo",
      age: 4,
      height: '6 feet'
    };
// spread syntax
let newObj = { ...person1, ...person2 };
console.log(newObj.height);

참고 : 호텔이 가장 오른쪽에있을수록 우선권이 있습니다. 이 예에서는 person2오른쪽에 있으므로 newObj이름이 Robo 입니다.