자바스크립트로 객체 확장하기
저는 현재 에서 변신 중입니다.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에서 속성을 확장할 때 실제 개체에서 이러한 속성을 상속합니다.다음과 같은 방식으로 작동합니다.
- 객체 속성이 요청된 경우(예:
myObj.foo
아니면myObj['foo']
) JS 엔진이 먼저 개체 자체에서 해당 속성을 찾습니다. - 이 속성이 개체 자체에서 발견되지 않으면 프로토타입 체인에 올라 프로토타입 개체를 살펴봅니다.여기서도 이 속성을 찾을 수 없는 경우 속성을 찾을 때까지 프로토타입 체인을 계속해서 이동합니다.속성을 찾지 못하면 참조 오류가 발생합니다.
자바스크립트의 객체에서 확장하고자 할 때 프로토타입 체인에서 이 객체를 간단히 연결할 수 있습니다.이를 달성하기 위한 다양한 방법이 있는데, 일반적으로 사용되는 두 가지 방법을 설명하겠습니다.
예:
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
'programing' 카테고리의 다른 글
jQuery를 사용하여 선택 필드를 비활성화/활성화하는 방법? (0) | 2023.10.28 |
---|---|
GROUP BY, ORDER BY 및 HAVING을 결합하는 방법 (0) | 2023.10.28 |
워드 프레스 로그인 후 참조 페이지로 리디렉션 (0) | 2023.10.28 |
ng반복에서 애니메이트를 지연시키는 방법 (0) | 2023.10.28 |
JNI를 사용하여 Java에서 C로 데이터 유형 전달(또는 그 반대) (0) | 2023.10.28 |