자바 스크립트로 객체 확장


164

현재 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(...);

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


true를 반환; 그러나 그것이 내가 묻는 이유입니다 :)
Wituz

2
내가 MDN에이 아름다운 tuutorial를 통해 갈 제안 : - developer.mozilla.org/en/...
PRANAV

이 멋진 문서를 읽은 후에도 여전히 extend함수 에 대해 궁금 하다면 jsfiddle.net/k9LRd
Codrin Eugeniu

2
또한 '자바에서 자바 스크립트로 변환하는 것'과 '자바와 비슷한 문법을 ​​가진 새로운 언어 인 자바 스크립트를 배우는 것'으로 엄격하게 생각하지 말 것을 제안합니다.
Toni Leigh

답변:


195

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

4
한 가지 질문이 있습니다. Person()할 때 생성자가 어떻게 호출 new Robot()됩니까? 당신이 대신 수행의 기본 클래스 생성자를 호출해야한다고 날 것으로 보인다 this.name = name;Robot()... 생성자
알렉시스 WILKE에게

21
@AlexisWilke : 그렇습니다 Person.apply(this, arguments);. 또한 Robot.prototype = Object.create(Person.prototype);대신에 사용 하는 것이 좋습니다 new Person();.
Felix Kling

18
Felix가 말한 것처럼 'Robot.prototype = Person.prototype;' 누군가가 '로봇'유형에 자체 프로토 타입 인스턴스를 갖기를 원한다면 나쁜 생각입니다. 새로운 로봇 특정 기능을 추가하면 사람에게 추가됩니다.
James Wilkins

20
이 예는 완전히 틀 렸습니다. 이를 통해 Person의 프로토 타입을 변경합니다. 그것은 상속이 아니며 Person 클래스에 큰 혼란을 줄 위험이 있습니다. Object.create () 사용을 권장하는 답변을 참조하십시오. 그것이 올바른 일을하는 방법입니다.
nicolas-van

6
@osahyoun이 답변은 Google 검색에서 높은 순위를 차지합니다. 다른 의견에서 제안한대로 코드를 수정하고 프로토 타입 체인을 수정하는 것이 좋습니다.
raphaëλ

101

"새"키워드가없는 세계.

그리고 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.
})

7
생성자 함수를 사용하지 않는다는 공감대가 있습니다.
nsmarks

1
"클래식 교육을받은"프로그래머라면 무엇을 의미합니까?
Petra

1
나는 고전적인 OOP 사고 방식에서 왔으며이 답변은 많은 도움이되었습니다. 코드에 대한 두 가지 질문 : 1) 오늘날 ES2015 Object.assign(Robot, {a:1}는 귀하의 extend()방법에 대한 좋은 대안 입니까? 2) greet()메소드 를 재정 의하여 동일한 텍스트를 반환하지만 "Greet override"가 추가 된 방법은 무엇입니까?
Barry Staes

2
1) #Object.assign좋은 대안처럼 보입니다. 그러나 브라우저 지원은 atm이 낮습니다. 2) __proto__객체 의 속성을 사용하여 프로토 타입의 인사 기능에 액세스합니다. 그런 다음 수신자의 범위가 전달 된 프로토 타입 greet 함수를 호출합니다.이 경우 함수는 콘솔 로그이므로 "추가"할 수 없습니다. 그러나이 예에서는 드리프트를 얻는다고 생각합니다. skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Calvintwr

1
ECMAScript 언어 사양 관리자와 관련하여 논의해야 할 내용입니다. 나는 일반적으로 동의하지만, 내가 가진 것과 함께 일해야합니다.

51

아직 방법을 찾지 못한 경우 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);

18
'parent'클래스에서 객체 / 배열을 사용할 때 'child'클래스의 원래 객체에 대한 포인터를 생성한다는 점에 유의하십시오. 자세히 설명 : 부모 클래스에 객체 또는 배열이있는 경우 해당 기본에서 확장되는 자식 클래스에서 수정하면 동일한 기본 클래스에서 확장되는 모든 자식 클래스에 대해 실제로 수정됩니다.
Harold

해롤드, 그 사실을 강조해 주셔서 감사합니다. 이 기능을 사용하는 사람은 객체 / 배열을 확인하고 복사하는 조건을 통합하는 것이 중요합니다.
tomilay 2009 년

30

다른 접근 방식 : 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 설명서 도 확인하십시오 .


2
@GaretClaborn이 올바르게 작동한다고 말하고 싶지만 다음 name과 같이 부모 생성자에게 매개 변수를 전달하지 않습니다 . jsfiddle.net/3brm0a7a/3 (차이는 # 8 행)
xPheRe

1
@xPheRe 아, 감사합니다. 그 변화를 반영하기 위해 답변을 편집했습니다
Garet Claborn

1
@ xPheRe,이 솔루션을 추가했을 때 요점을 증명하는 데 더 집중 한 것 같습니다. 감사.
Lior Elrom

1
멋진 대답 +1, 당신은 ECMAScript를 6 키워드 클래스를 살펴보고 확장하실 수 있습니다 : developer.mozilla.org/en-US/docs/Web/JavaScript/...
벤자민 신랄한

26

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 이 필요한 경우 링크에서도 제공합니다. :)


18

그리고 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"

2 년 최대 때까지 글쎄, 난 여전히 2개월이 : P 어느 쪽이든, JOII 3.0에 대한 :) 릴리스입니다
해롤드

1
3 년 후를 확인하십시오.

흥미로운 개념이지만 구문은보기 흉하게 보입니다. ES6 수업이 안정 될 때까지 기다리는 것이 좋습니다.
sleepycal

@sleepycal에 전적으로 동의합니다. 그러나 불행히도 모든 주요 / 공통 브라우저가이를 구현하기까지는 적어도 5 년이 더 걸릴 것입니다. 그래서 그 때까지, 이렇게해야합니다 ...
Harold

12

간단하고 최상의 접근 방식으로 여전히 어려움을 겪고있는 사람들은 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 입니다.



6

모질라, ECMAScript 6.0에서 확장 된 객체 발표

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

참고 : 이것은 ECMAScript 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;     } 
}

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


4

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

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


"순수한 자바 스크립트 구현"은 기본적으로 구현 될 수있는 환경 제공 함수가 아니라 JavaScript만으로 구현 된 것을 의미하지 않습니까?
binki

1
@binki, 나는 기본 자바 스크립트 구현을 의미 - ECMA 스크립트 2015 년 (ES6)의 일부를 표준
의 Cezary 다니엘 노박

2
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 업데이트 :

Javascript가 현재 지원되므로 2015 년의 대답을 무시하십시오. extends ES6부터 키워드를 (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

1
new ParentClass()생성자를 덮어 쓰기 전에 호출 하여 이미 부모 생성자를 실행했습니다. 당신이 저에게 물어 보면 그것이 올바른 행동이라고 생각하지 않습니다 ...
Harold

1

요약:

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


0

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

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
}

0

DOWNVOTE에 대한 이유를 추가하십시오

  • 확장하기 위해 외부 라이브러리를 사용할 필요가 없습니다.

  • JavaScript에서 모든 것은 객체입니다 (세 가지 기본 데이터 유형을 제외하고 필요할 때 자동으로 객체로 래핑 됨). 또한 모든 객체는 변경 가능합니다.

JavaScript의 클래스 사람

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과 OBJECT는 동일합니다.

var k = {
    name : 'jack',
    age : 30
}

k.gender = 'male'; /*object or json k got extended with new property gender*/

총체적인 피해, 더스틴 디아즈


-1

이렇게하면 전달 된 객체를 변경하지 않고도 객체 매개 변수 프로토 타입을 사용하여 속성을 확장하여 새 객체를 만들 수 있습니다.

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
        }
    }

-2

프로토 타이핑은 좋은 방법이지만 프로토 타입은 때때로 매우 위험하며 버그로 이어질 수 있습니다. Ember.js가 Ember.Object.extend 및 Ember.Object.reopen과 같이 기본 객체로 캡슐화하는 것을 선호합니다. 사용하기 훨씬 안전합니다.

Ember.Object가 사용하는 것과 비슷한 것을 설정하는 방법으로 요점을 만들었습니다 .

링크는 다음과 같습니다. https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd


9
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.그게 무슨 뜻 이니? JavaScript에서 프로토 타입 체인을 사용하면 버그가 발생할 수 있습니까? Java에서 클래스를 사용하면 버그가 발생할 수 있으며 전혀 의미가 없다고 말하는 것과 같습니다.
HMR

@HMR은 환경 제공 객체 프로토 타입을 확장하면 깨지기 쉬운 코드가 생겨 향후 핵심 JavaScript 언어 기능과 충돌 할 수 있다고 말합니다. Object의 프로토 타입 을 확장하여 유용한 유틸리티 함수를 모든 것에 추가하면 함수가 미래의 JavaScript 함수와 이름이 같고 나중에 실행될 때 코드가 폭발 할 수 있습니다. 예를 들어, 인스턴스 에 repeat()함수를 추가 Object하고 호출 String한 다음 JavaScript 런타임을 ES6으로 업데이트했다고 가정 해보십시오.
binki

@binki 입력 해 주셔서 감사합니다. 당신은 클래스의 프로토 타입을 변경 얘기하면 할 "자신의"하여 파괴 incapsulation 참조하지 : developer.mozilla.org/en/docs/Web/JavaScript/... 당신의 API 노출하는 구현 회원 있도록 JS 개인 변수가 없습니다 이는 일반적으로 관례 (밑줄로 시작 멤버 이름)로 해결됩니다. 이것이 op가 가진 주요 문제인지 또는 구문이 혼란스럽고 많은 사람들이 이해하지 못하는지 확실하지 않습니다.
HMR

@HMR, 틀릴 수도 있지만“하지만 프로토 타입은 매우 위험합니다”는 언어 기능을 남용 있는 악명 높은 프로토 타입 프레임 워크 를 말합니다 . prototype
binki

생성하지 않은 객체를 사용하는 경우 부작용으로 인해 프로토 타입으로 어떤 부작용이 발생하는지 항상 알 수 없기 때문에 프로토 타이핑은 위험합니다. 예를 들면 다음과 같습니다. jsfiddle.net/fo6r20rg
Arkain
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.