Development Tip

언제 Object.defineProperty ()를 사용합니까?

yourdevel 2020. 12. 12. 12:34
반응형

언제 Object.defineProperty ()를 사용합니까?


언제 사용해야하는지 궁금합니다

Object.defineProperty

개체에 대한 새 속성을 만듭니다. 나는 다음과 같은 것을 설정할 수 있다는 것을 알고 있습니다.

enumerable: false

하지만이게 언제 정말 필요한가요? 다음과 같은 속성을 설정하면

myObject.myprop = 5;

설명자는 모두 true로 설정되어 있습니다. 저는 여러분이 .defineProperty ()에 대한 다소 장황한 호출을 사용할 때와 그 이유가 무엇인지 실제로 더 궁금합니다.


Object.defineProperty주로 특정 속성 설명자를 사용하여 속성을 설정하는 데 사용됩니다 (예 : 읽기 전용 (상수), 열거 가능성 ( for (.. in ..)루프, getter, setter에 속성을 표시하지 않음 ).

"use strict";
var myObj = {}; // Create object
// Set property (+descriptor)
Object.defineProperty(myObj, 'myprop', {
    value: 5,
    writable: false
});
console.log(myObj.myprop);// 5
myObj.myprop = 1;         // In strict mode: TypeError: myObj.myprop is read-only

이 메서드 Object는 속성을 사용 하여 프로토 타입을 확장합니다 . getter 만 정의되고 열거 가능성은로 설정됩니다 false.

Object.defineProperty(Object.prototype, '__CLASS__', {
    get: function() {
        return Object.prototype.toString.call(this);
    },
    enumerable: false // = Default
});
Object.keys({});           // []
console.log([].__CLASS__); // "[object Array]"

'열거 형'과 같은 기능은 내 경험에서 거의 사용되지 않습니다. 주요 사용 사례는 계산 된 속성입니다.

var myObj = {};

myObj.width = 20;
myObj.height = 20;

Object.defineProperty(myObj, 'area', {
    get: function() {
        return this.width*this.height;
    }
});
console.log(myObj.area);

Object.defineProperty를 사용하는 정말 좋은 이유는 함수의 본문을 반환하는 대신 함수를 실행하는 계산 된 속성으로 객체의 함수를 반복 할 수 있기 때문입니다.

예를 들면 :

var myObj = {};

myObj.width = 20;
myObj.height = 20;

Object.defineProperty(myObj, 'area', {
    get: function() {
        return this.width*this.height;
    },
    enumerable: true
});

for (var key in myObj) {
  if (myObj.hasOwnProperty(key)) {
    console.log(key + " -> " + myObj[key]);
  }
}
//width -> 20, height -> 20, area -> 400

객체 리터럴에 속성으로 함수를 추가하는 것과 비교 :

var myObj = {};

myObj.width = 20;
myObj.height = 20;

myObj.area = function() {
       return this.width*this.height;
    };

for (var key in myObj) {
  if (myObj.hasOwnProperty(key)) {
    console.log(key + " -> " + myObj[key]);
  }
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}

반복하려면 열거 가능 속성을 true로 설정해야합니다.


내가 본 한 가지 깔끔한 사용 사례 defineProperty는 라이브러리가 사용자에게 오류 속성을 제공하는 것인데, 특정 간격 내에 액세스하지 않으면 스스로 던질 것입니다. 예를 들면 :

let logErrorTimeoutId = setTimeout(() => {
  if (error) {
    console.error('Unhandled (in <your library>)', error.stack || error);
  }
}, 10);

Object.defineProperty(data, 'error', {
    configurable: true,
    enumerable: true,
    get: () => {
      clearTimeout(logErrorTimeoutId);
      return error;
    },
  });

이 코드의 소스 : https://github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510


예를 들어, Vue.js는 data객체 의 변경 사항을 추적 합니다 .

당신이 그와 같은 뷰 인스턴스에 일반 자바 스크립트 객체를 전달하면 data옵션, 뷰는 모든 속성을 걸을 것이며, 그들로 변환 getter/setters사용 Object.defineProperty. 이것은 ES5 전용이며 시밍 할 수없는 기능이므로 Vue는 IE8 이하를 지원하지 않습니다.

getter / setter는 사용자에게 보이지 않지만 속성에 액세스하거나 수정할 때 Vue가 종속성 추적 및 변경 알림을 수행 할 수 있도록합니다.

[...]

Vue.js의 초슬림 및 기본 버전조차도 .js 이상의 것을 사용 Object.defineProperty하지만 주요 기능은 다음과 같습니다.

Vue.js's Reactivity Cycle

여기에서 작성자가 Vue.js와 같은 최소 버전의 PoC 버전을 구현하는 기사를 볼 수 있습니다. https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c

그리고 Vue.js에서 반응을 설명하면서 비슷한 것을 만드는 강연 (스페인어) : https://www.youtube.com/watch?v=axXwWU-L7RM


인터 셉션을 수행하거나 고전적인 Observer / Observable 패턴을 우아한 방식으로 적용해야 할 때 유용합니다.

https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects


요약:

자바 스크립트에서 객체는 키-값 쌍의 모음입니다. Object.defineProperty()객체에 대한 새 속성을 정의 할 수있는 함수이며 다음과 같은 속성 속성을 설정할 수 있습니다.

  • value <any>: 키와 관련된 값
  • writable <boolean>: if writable is set to true The property can be updated by assigning a new value to it. If set to false you can't change the value.
  • enumerable <boolean>: if enumerable is set to true Property can be accessed via a for..in loop. Furthermore are the only the enumerable property keys returned with Object.keys()
  • configurable <boolean>: If configurable is set to false you cannot change change the property attributes (value/writable/enumerable/configurable), also since you cannot change the value you cannot delete it using the delete operator.

Example:

let obj = {};


Object.defineProperty(obj, 'prop1', {
      value: 1,
      writable: false,
      enumerable: false,
      configurable: false
});   // create a new property (key=prop1, value=1)


Object.defineProperty(obj, 'prop2', {
      value: 2,
      writable: true,
      enumerable: true,
      configurable: true
});  // create a new property (key=prop2, value=2)


console.log(obj.prop1, obj.prop2); // both props exists

for(const props in obj) {
  console.log(props);
  // only logs prop2 because writable is true in prop2 and false in prop1
}


obj.prop1 = 100;
obj.prop2 = 100;
console.log(obj.prop1, obj.prop2);
// only prop2 is changed because prop2 is writable, prop1 is not


delete obj.prop1;
delete obj.prop2;

console.log(obj.prop1, obj.prop2);
// only prop2 is deleted because prop2 is configurable and prop1 is not


Object.defineProperty prevents you from accidentally assigning values to some key in its prototype chain. With this method you assign only to that particular object level(not to any key in prototype chain).

For example: There is an object like {key1: value1, key2: value2} and you don't know exactly its prototype chain or by mistake you miss it and there is some property 'color' somewhere in prototype chain then-

using dot(.) assignment-

this operation will assign value to key 'color' in prototype chain(if key exist somewhere) and you will find the object with no change as . obj.color= 'blue'; // obj remain same as {key1: value1, key2: value2}

using Object.defineProperty method-

Object.defineProperty(obj, 'color', {
  value: 'blue'
});

// now obj looks like {key1: value1, key2: value2, color: 'blue'}. it adds property to the same level.Then you can iterate safely with method Object.hasOwnProperty().


A very useful case is to monitor changes to something and act on them. It's easy because you can have callback functions fire whenever the value gets set. Here's a basic example.

You have an object Player that can be playing or not playing. You want something to happen right when it starts playing, and right when it stops playing.

function Player(){}
Object.defineProperty(Player.prototype, 'is_playing', {
  get(){
    return this.stored_is_playing;  // note: this.is_playing would result in an endless loop
  },
  set(newVal){
    this.stored_is_playing = newVal;
    if (newVal === true) {
      showPauseButton();
    } else {
      showPlayButton();
    }
  }
});
const cdplayer = new Player();
cdplayer.is_playing = true; // showPauseButton fires 

This answer is related to a couple other answers here, which are good stepping points for more information, but with no need to follow external links to read about libraries or programming paradigms.


@Gerard Simpson

If 'area' should be enumerable it can be written without Object.defineProperty, too.

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

myObj.width = 20;
myObj.height = 20;

for (var key in myObj) {
  if (myObj.hasOwnProperty(key)) {
    console.log(key + " -> " + myObj[key]);
  }
}

//area -> 400, width -> 20, height -> 20

참고URL : https://stackoverflow.com/questions/10105824/when-do-you-use-object-defineproperty

반응형