programing

자바스크립트로 객체 확장하기

muds 2023. 10. 28. 08:20
반응형

자바스크립트로 객체 확장하기

저는 현재 에서 변신 중입니다.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(...);

하지만 저는 이 시스템을 어떻게 작동시키는지 모릅니다.만약 불가능하다면, 객체를 확장하는 다른 대안을 보여주시기 바랍니다.

사용자의 프로토타입 개체에서 '상속'하려는 경우:

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()를 사용하여 보다 간단한 "prose-like" 구문을 만들 수 있습니다.

그리고 자바스크립트의 실제 원형적인 특성

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

첫째, 자바스크립트는 클래스 기반이 아닌 프로토타입 언어입니다.그 진면목은 아래 프로토타입 형태로 표현되어 있으며, 매우 단순하고 산문적이면서도 강력한 것을 볼 수 있습니다.

TLDR;

자바스크립트

const Person = { 
    name: 'Anonymous', // person has a name
    greet: function() { console.log(`Hi, I am ${this.name}.`) } 
} 
    
const jack = Object.create(Person)   // jack is a person
jack.name = 'Jack'                   // and has a name 'Jack'
jack.greet()                         // outputs "Hi, I am Jack."

타이프스크립트

TypeScript에서는 인터페이스를 설정해야 합니다. 이 인터페이스는 하위 파일을 생성할 때 확장됩니다.Person원형의돌연변이politeGreet하위 메서드에 새 메서드를 연결하는 예를 보여 줍니다.jack.

interface IPerson extends Object {
    name: string
    greet(): void
}

const Person: IPerson =  {
    name:  'Anonymous',  
    greet() {
        console.log(`Hi, I am ${this.name}.`)
    }
}

interface IPolitePerson extends IPerson {
    politeGreet: (title: 'Sir' | 'Mdm') => void
}

const PolitePerson: IPolitePerson = Object.create(Person)
PolitePerson.politeGreet = function(title: string) {
    console.log(`Dear ${title}! I am ${this.name}.`)
}

const jack: IPolitePerson = Object.create(Person)
jack.name = 'Jack'
jack.politeGreet = function(title): void {
    console.log(`Dear ${title}! I am ${this.name}.`)
}

jack.greet()  // "Hi, I am Jack."
jack.politeGreet('Sir') // "Dear Sir, I am Jack."

이를 통해 때때로 복잡해지는 컨스트럭터 패턴을 제거할 수 있습니다.새 개체는 이전 개체에서 상속되지만 고유한 속성을 가질 수 있습니다.새 객체에서 멤버를 구하려고 할 경우 (#greet()) 새로운 개체를 선택합니다.jack부족하다, 오래된 물건.Person멤버들에게 공급할 것입니다.

Douglas Crockford의 말에 따르면, "객체는 사물로부터 물려받습니다. 그것보다 더 객체 지향적인 것이 어디 있겠습니까?"

건설업자는 필요 없고,new예를 들면, 예를 들면, 예를 들면, 예를 들면, 예를 들면개체를 만든 다음 확장하거나 형태를 지정하면 됩니다.

또한 이 패턴은 불변성(부분 또는 전체)과 게터/세터를 제공합니다.

깨끗하고 맑음.단순하기 때문에 기능이 손상되지 않습니다.읽어보세요.

사용자의 하위/복사본 만들기prototype(보다 techn적으로 더 정확함)class).

*참고: 아래 예제는 JS에 있습니다.타이프스크립트로 쓰려면 위의 예에 따라 타이프를 위한 인터페이스를 설정하면 됩니다.

const Skywalker = Object.create(Person)
Skywalker.lastName = 'Skywalker'
Skywalker.firstName = ''
Skywalker.type = 'human'
Skywalker.greet = function() { console.log(`Hi, my name is ${this.firstName} ${this.lastName} and I am a ${this.type}.`

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

직접적인 과제 대신 시공자를 버리는 것이 안전성이 떨어진다면 일반적인 방법 중 하나는#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')

가지치기Person견본으로 삼다Robot

분기할 때Robot손의 Person프로토타입, 당신은 당신에게 영향을 주지 않을 겁니다.Skywalker그리고.anakin:

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

고유한 메서드 연결Robot

Robot.machineGreet = function() { 
    /*some function to convert strings to binary */ 
}

// Mutating the `Robot` object doesn't affect `Person` prototype and its descendants
anakin.machineGreet() // error

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

TypeScript에서 당신은 또한 확장할 필요가 있을 것입니다.Person인터페이스:

interface Robot extends Person {
    machineGreet(): void
}
const Robot: Robot = Object.create(Person)
Robot.machineGreet = function() { console.log(101010) }

믹신도 먹을 수 있습니다. 왜냐하면..다스 베이더는 인간입니까 로봇입니까?

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.

여기에는 "실생활"의 주관성이 우아하게 반영되어 있습니다.

"그는 이제 인간보다 더 기계적이고, 뒤틀리고 사악합니다." - 오비완 케노비

"당신 안에 좋은 점이 있다는 걸 알아요." - 루크 스카이워커

ES6 이전의 "클래식" 동급 제품과 비교해 보십시오.

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')

// #isPrototypeOf won't work
Person.isPrototypeOf(anakin) // returns false
Skywalker.isPrototypeOf(anakin) // returns false

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

추가열람

쓰기성, 구성성, 무료 게터 및 세터!

자유 getter 및 setter 또는 추가 구성의 경우 Object.create()의 두 번째 인수 a.k.a propertiesObject를 사용할 수 있습니다.또한 #Object.definProperty#Object.definProperties에서도 사용할 수 있습니다.

그것의 유용성을 설명하기 위해, 우리가 모든 것을 원한다고 가정하자.Robot엄밀하게 금속으로 만들어지다 ( 경유)writable: false), 및 표준화powerConsumption값(게터 및 세터를 통해).


// Add interface for Typescript, omit for Javascript
interface Robot extends Person {
    madeOf: 'metal'
    powerConsumption: string
}

// add `: Robot` for TypeScript, omit for Javascript.
const Robot: Robot = Object.create(Person, {
    // define your property attributes
    madeOf: { 
        value: "metal",
        writable: false,  // defaults to false. this assignment is redundant, and for verbosity only.
        configurable: false, // defaults to false. this assignment is redundant, and for verbosity only.
        enumerable: true  // defaults to false
    },
    // getters and setters
    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.')
        }  
    }
})

// add `: Robot` for TypeScript, omit for Javascript.
const newRobot: Robot = Object.create(Robot)
newRobot.powerConsumption = '5MWh'
console.log(newRobot.powerConsumption) // outputs 5,000kWh

그리고 모든 프로토타입은Robot있을 수 없는madeOf 내용것:

const polymerRobot = Object.create(Robot)
polymerRobot.madeOf = 'polymer'
console.log(polymerRobot.madeOf) // outputs 'metal'

아직 방법을 찾지 못했다면 자바스크립트 객체의 연관 속성을 사용하여 확장 함수를 에 추가합니다.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);

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

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

Object.assign()은 설정자를 트리거하지만 확산 구문은 트리거하지 않습니다.

자세한 내용은 MDN - 구문 확산 링크를 참조하십시오.


이전 답변:

ES6에는.Object.assign속성 값을 복사하기 위해 사용합니다.{}대상 개체를 수정하지 않으려면 첫 번째 매개 변수로 지정합니다(첫 번째 매개 변수가 전달됨).

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

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

ES5용 Polyfill이 필요한 경우 링크에서도 제공됩니다.:)

다른 접근 방식: Object.create

@osahyun 답변에 따르면, 저는 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 설명서도 확인합니다.

그리고 1년 후에 또 하나의 좋은 답이 있습니다.

프로토타이핑이 객체/classes에서 확장되는 방식이 마음에 들지 않는다면, 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"

아직도 단순하고 최선의 접근 방식을 위해 고군분투하는 사람들은 오브젝트를 확장하는 데 사용할 수 있습니다.

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로보라는 이름이 들어갈 겁니다.

undercore.js와 같은 헬퍼 라이브러리를 사용하는 것을 고려해 볼 수 있습니다. 이 라이브러리는 자체적으로 구현되어 있습니다.

그리고 소스코드를 보고 배우는 것도 좋은 방법입니다.주석이 달린 소스 코드 페이지는 꽤 유용합니다.

Mozilla가 ECMAscript 6.0에서 확장하는 개체를 '공지'합니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends

참고: 이것은 ECMA스크립트 6(Harmony) 제안서의 일부인 실험적 기술입니다.

class Square extends Polygon {
  constructor(length) {
    // Here, it calls the parent class' constructor with lengths
    // provided for the Polygon's width and height
    super(length, length);
    // Note: In derived classes, super() must be called before you
    // can use 'this'. Leaving this out will cause a reference error.
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.area = value;     } 
}

이 기술은 Gecko(Google Chrome / Firefox) - 2015년 03월 야간 빌드에서 사용할 수 있습니다.

대부분의 프로젝트에서는 개체 확장(밑줄, jquery, lodash: extend)의 일부 구현이 있습니다.

ECMAscript 6: Object.assign: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 의 일부인 순수한 자바스크립트 구현도 있습니다.

Function.prototype.extends=function(ParentClass) {
    this.prototype = new ParentClass();
    this.prototype.constructor = this;
}

그러면:

function Person() {
    this.name = "anonym"
    this.skills = ["abc"];
}
Person.prototype.profile = function() {
    return this.skills.length // 1
};

function Student() {} //well extends fom Person Class
Student.extends(Person)

var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

업데이트 01/2017:

자바스크립트가 지원하므로 2015년 내 답변은 무시해주세요.extends 이후의드(Ecmasctipt6)

- ES6:

class Person {
   constructor() {
     this.name = "anonym"
     this.skills = ["abc"];
   }

   profile() {
    return this.skills.length // 1
   }

}

Person.MAX_SKILLS = 10;
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

- ES7:

class Person {
    static MAX_SKILLS = 10;
    name = "anonym"
    skills = ["abc"];

    profile() {
      return this.skills.length // 1
    }

}
class Student extends Person {


} //well extends from Person Class

//-----------------
var s1 = new Student();
s1.skills.push("")
s1.profile() // 2

요약:.

자바스크립트는 프로토타입 상속이라는 메커니즘을 사용합니다.프로토타입 상속은 개체에서 속성을 조회할 때 사용됩니다.javascript에서 속성을 확장할 때 실제 개체에서 이러한 속성을 상속합니다.다음과 같은 방식으로 작동합니다.

  1. 객체 속성이 요청된 경우(예:myObj.foo아니면myObj['foo']) JS 엔진이 먼저 개체 자체에서 해당 속성을 찾습니다.
  2. 이 속성이 개체 자체에서 발견되지 않으면 프로토타입 체인에 올라 프로토타입 개체를 살펴봅니다.여기서도 이 속성을 찾을 수 없는 경우 속성을 찾을 때까지 프로토타입 체인을 계속해서 이동합니다.속성을 찾지 못하면 참조 오류가 발생합니다.

자바스크립트의 객체에서 확장하고자 할 때 프로토타입 체인에서 이 객체를 간단히 연결할 수 있습니다.이를 달성하기 위한 다양한 방법이 있는데, 일반적으로 사용되는 두 가지 방법을 설명하겠습니다.

예:

1. Object.create()

Object.create()는 객체를 인수로 삼고 새로운 객체를 생성하는 함수입니다.인수로 전달된 개체는 새로 생성된 개체의 프로토타입이 됩니다.예를 들어,

// prototype of the dog
const dogPrototype = {
  woof: function () { console.log('woof'); }
}

// create 2 dog objects, pass prototype as an argument
const fluffy = Object.create(dogPrototype);
const notFluffy = Object.create(dogPrototype);

// both newly created object inherit the woof 
// function from the dogPrototype
fluffy.woof();
notFluffy.woof();

2. 프로토타입 속성 명시적으로 설정

생성자 함수를 사용하여 객체를 생성할 때 프로토타입 객체 속성에 추가 속성을 설정할 수 있습니다.를 사용할 때 생성된 객체는 생성자 함수를 형성합니다.new키워드, 프로토타입을 컨스트럭터 함수의 프로토타입으로 설정합니다.예를 들어,

// Constructor function object
function Dog (name) {
   name = this.name;
}

// Functions are just objects
// All functions have a prototype property
// When a function is used as a constructor (with the new keyword)
// The newly created object will have the consturctor function's
// prototype as its prototype property
Dog.prototype.woof = function () {
  console.log('woof');
}

// create a new dog instance
const fluffy = new Dog('fluffyGoodBoyyyyy');
// fluffy inherits the woof method
fluffy.woof();

// can check the prototype in the following manner
console.log(Object.getPrototypeOf(fluffy));

간단하고 읽을 수 있는 해결책은 스프레드 연산자를 사용하는 것입니다.

...

예를 들어 다음과 같습니다.

const obj1 = {a: "a"} const obj2 = {b: "b"} const result = {...obj1, ..obj2,} console.log("result", result) // must be {a: "a", b: "b"}
  • 외부 라이브러리를 사용하여 확장할 필요 없음

  • 자바스크립트에서는 모든 것이 객체입니다(세 가지 원시 데이터 유형을 제외하고는 필요할 때 자동으로 객체로 래핑됩니다).게다가 모든 물체는 변형 가능합니다.

자바스크립트의 클래스 사용자

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype = {
    getName: function() {
        return this.name;
    },
    getAge: function() {
        return this.age;
    }
}

/* Instantiate the class. */
var alice = new Person('Alice', 93);
var bill = new Person('Bill', 30);

특정 인스턴스/개체를 수정합니다.

alice.displayGreeting = function() 
{
    alert(this.getGreeting());
}

클래스수정

Person.prototype.getGreeting = function() 
{
    return 'Hi ' + this.getName() + '!';
};

또는 간단히 말하면: 확장 JSON과 OBESTAL은 둘 다 동일합니다.

var k = {
    name : 'jack',
    age : 30
}
 
k.gender = 'male'; /*object or json k got extended with new property gender*/

로스해, 더스틴 디아즈 덕분에

다음을 사용하여 간단히 수행할 수 있습니다.

Object.prototype.extend = function(object) {
  // loop through object 
  for (var i in object) {
    // check if the extended object has that property
    if (object.hasOwnProperty(i)) {
      // mow check if the child is also and object so we go through it recursively
      if (typeof this[i] == "object" && this.hasOwnProperty(i) && this[i] != null) {
        this[i].extend(object[i]);
      } else {
        this[i] = object[i];
      }
    }
  }
  return this;
};

업데이트: 확인했습니다this[i] != null부터null물건입니다.

그러면 다음과 같이 사용합니다.

var options = {
      foo: 'bar',
      baz: 'dar'
    }

    var defaults = {
      foo: false,
      baz: 'car',
      nat: 0
    }

defaults.extend(options);

이 우물은 다음과 같은 결과를 가져옵니다.

// defaults will now be
{
  foo: 'bar',
  baz: 'dar',
  nat: 0
}

이렇게 하면 속성 확장을 통해 전달된 개체를 변경하지 않고도 개체 매개 변수 프로토타입으로 새 개체를 생성할 수 있습니다.

function extend(object) {
    if (object === null)
        throw TypeError;
    if (typeof object !== "object" && typeof object !== "function")
        throw TypeError;
    if (Object.create)
        return Object.create(object);
    function f() {}
    ;
    f.prototype = p;
    return new f();
}

그러나 매개 변수를 수정하지 않고 개체를 확장하려면 extendProperty를 개체에 추가할 수 있습니다.

var Person{
//some code
extend: extendProperty
}

//Enforce type checking an Error report as you wish
    function extendProperty(object) {
        if ((object !== null && (typeof object === "object" || typeof object === "function"))){
            for (var prop in object) {
                if (object.hasOwnProperty(prop))
                    this[prop] = object[prop];
            }
        }else{
            throw TypeError; //Not an object
        }
    }

이 작업 중에는 100% 정확하지 않습니다.

// Parent
var Parent = function (name) {
  this.name = name;
  this.test = function () {
    console.log("parent test");
  }
  this.testOverride = function () {
    console.log("parent testOverride");
  }
}
// define a function extend
Parent.prototype.extend = function () {
  // parent properties to override or add
  var override = arguments[0];
  return function () {
    Parent.apply(this, arguments);
    // add and override properties
    Object.keys(override).forEach(el =>{
      this[el] = override[el];
    })
   }
}
// create a Child from the Parent and override
// the function "testOverride" and keep "test" unchanged
var Child = Parent.prototype.extend({
  y: 10,
  testOverride: function () { 
    console.log("child testOverride"); 
  }
});
// Create an object of type Parent
var p = new Parent("Parent");
// Create an object of type Child
var c = new Child("Child");
console.log(p.name);
// Parent
console.log(c.name);
// Child
p.test();
//parent test
p.testOverride();
//parent testOverride
c.test();
//parent test
c.testOverride();
//child testOverride

언급URL : https://stackoverflow.com/questions/10430279/extending-an-object-in-javascript

반응형