как использовать объект javascript.defineProperty

Я огляделся вокруг, как использовать Object.defineProperty метод, но не смог найти ничего приличного.

кто-то дал мне этот фрагмент кода:

Object.defineProperty(player, "health", {
    get: function () {
        return 10 + ( player.level * 15 );
    }
})

но я этого не понимаю. Главным образом,get это то, что я не могу сделать (каламбур). Как это работает?

7 ответов


так как вы спросили аналогичный вопрос, давайте сделаем это шаг за шагом. Это немного дольше, но это может сэкономить вам гораздо больше времени, чем я потратил на написание этого:

свойства - это функция ООП, предназначенная для чистого разделения клиентского кода. Например, в каком-то интернет-магазине у вас могут быть такие объекты:

function Product(name,price) {
  this.name = name;
  this.price = price;
  this.discount = 0;
}

var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10);  // {name:"T-shirt",price:10,discount:0}

затем в вашем клиентском коде (интернет-магазине) вы можете добавить скидки на свои товары:

function badProduct(obj) { obj.discount+= 20; ... }
function generalDiscount(obj) { obj.discount+= 10; ... }
function distributorDiscount(obj) { obj.discount+= 15; ... }
, владелец интернет-магазина может понять, что скидка не может быть больше, чем 80%. Теперь вам нужно найти каждый случай изменения скидки в коде клиента и добавить строку
if(obj.discount>80) obj.discount = 80;

тогда владелец интернет-магазина может дополнительно изменить свою стратегию, например " если клиент является реселлером, максимальная скидка может составлять 90%". И вам нужно сделать изменение на нескольких местах снова плюс вам нужно помнить, чтобы изменить эти линии в любое время стратегия изменяется. Это плохой дизайн. Вот почему инкапсуляция основной принцип ООП. Если конструктор был таким:

function Product(name,price) {
  var _name=name, _price=price, _discount=0;
  this.getName = function() { return _name; }
  this.setName = function(value) { _name = value; }
  this.getPrice = function() { return _price; }
  this.setPrice = function(value) { _price = value; }
  this.getDiscount = function() { return _discount; }
  this.setDiscount = function(value) { _discount = value; } 
}

затем вы можете просто изменить getDiscount (метод) и setDiscount (мутатор) методов. Проблема в том, что большинство членов ведут себя как общие переменные, просто скидка здесь нуждается в особом уходе. Но хороший дизайн требует инкапсуляции каждого члена данных, чтобы код был расширяемым. Так что тебе нужно чтобы добавить много кода, который ничего не делает. Это тоже плохой дизайн,шаблонный антиобразец. Иногда вы не можете просто изменить поля с методами позже (код интернет-магазин может вырасти большой или какой-то сторонний код может зависеть от старой версии), так что шаблон имеет здесь меньшее зло. Но все же это зло. Вот почему свойства были введены во многие языки. Вы можете сохранить исходный код, просто преобразуйте член скидки в свойство с помощью get и set блоки:

function Product(name,price) {
  this.name = name;
  this.price = price;
//this.discount = 0; // <- remove this line and refactor with the code below
  var _discount; // private member
  Object.defineProperty(this,"discount",{
    get: function() { return _discount; },
    set: function(value) { _discount = value; if(_discount>80) _discount = 80; }
  });
}

// the client code
var sneakers = new Product("Sneakers",20);
sneakers.discount = 50; // 50, setter is called
sneakers.discount+= 20; // 70, setter is called
sneakers.discount+= 20; // 80, not 90!
alert(sneakers.discount); // getter is called

обратите внимание на последнюю строку: ответственность за правильное значение скидки была перенесена из кода клиента (определение интернет-магазина) в определение продукта. Продукт отвечает за согласованность своих элементов данных. Хороший дизайн (грубо говоря), если код работает так же, как наши мысли.

так много о свойствах. Но javascript отличается от чистых объектно-ориентированных языков, таких как C#, и кодирует функции иначе:

В C#, превращая поля в свойства breaking change, так и открытые поля должны быть закодированы как Автоматически Реализуемые Свойства если ваш код может использоваться по отдельности компилируется клиента.

В Javascript, стандартные свойства (элемент данных с геттером и сеттером, описанным выше) определяются доступа дескриптора (в ссылке, которую вы имеете в своем вопросе). Исключительно, вы можете использовать дескриптор данных (поэтому вы не можете использовать, т. е. стоимостью и set на этой же территории):

  • доступа дескриптора = get + set (см. пример выше)
    • get должна быть функцией; ее возвращаемое значение используется при чтении свойства; если не указано, значение по умолчанию неопределено, который ведет себя как функция, которая возвращает неопределено
    • set должна быть функцией; ее параметр заполняется RHS при присвоении значения свойству; если не указано, значение по умолчанию неопределено, который ведет себя как пустая функция
  • дескриптор данных = value + writable (см. пример ниже)
    • стоимостью по умолчанию неопределено; если записи, настраиваемые!--31--> и перечисли (см. ниже) имеет значение true, свойство ведет себя как обычное поле данных
    • записи по умолчанию false, если не правда свойство доступно только для чтения; попытка записи игнорируется без ошибок*!

оба дескриптора могут иметь эти членов комиссии:

  • настраиваемые!--31--> по умолчанию false; если не true, свойство не может быть удалено; попытка удаления игнорируется без ошибок*!
  • перечисли по умолчанию false; если true, он будет повторен в for(var i in theObject); если false, он не будет повторяться, но он по-прежнему доступен как public

* если строгий режим - в этом случае JS останавливает выполнение с TypeError, если он не пойман в try-catch block

чтобы прочитать эти настройки, используйте Object.getOwnPropertyDescriptor().

учатся на примере:

var o = {};
Object.defineProperty(o,"test",{
  value: "a",
  configurable: true
});
console.log(Object.getOwnPropertyDescriptor(o,"test")); // check the settings    

for(var i in o) console.log(o[i]); // nothing, o.test is not enumerable
console.log(o.test); // "a"
o.test = "b"; // o.test is still "a", (is not writable, no error)
delete(o.test); // bye bye, o.test (was configurable)
o.test = "b"; // o.test is "b"
for(var i in o) console.log(o[i]); // "b", default fields are enumerable

если вы не хотите, чтобы код клиента такие Читы, вы можете ограничить объект тремя уровнями ограничения:


get - это функция, которая вызывается при попытке чтения значения player.health, как:

console.log(player.health);

это эффективно, не сильно отличается от:

player.getHealth = function(){
  return 10 + this.level*15;
}
console.log(player.getHealth());

установлена противоположность get, которая будет использоваться при назначении значения. Поскольку сеттера нет, кажется, что присвоение здоровью игрока не предназначено:

player.health = 5; // Doesn't do anything, since there is no set function defined

простой пример:

var player = {
  level: 5
};

Object.defineProperty(player, "health", {
  get: function() {
    return 10 + (player.level * 15);
  }
});

console.log(player.health); // 85
player.level++;
console.log(player.health); // 100

player.health = 5; // Does nothing
console.log(player.health); // 100

defineProperty - это метод на объекте, который позволяет настроить свойства для удовлетворения некоторых критериев. Вот простой пример с объектом employee с двумя свойствами firstName & lastName и добавьте два свойства, переопределив toString метод на объекте.

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
employee.toString=function () {
    return this.firstName + " " + this.lastName;
};
console.log(employee.toString());

вы получите выход как: Jameel Moideen

Я собираюсь изменить тот же код, используя defineProperty на объект

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
    value: function () {
        return this.firstName + " " + this.lastName;
    },
    writable: true,
    enumerable: true,
    configurable: true
});
console.log(employee.toString());

первый параметр-это имя объекта, а затем второй параметр-это имя свойства, которое мы добавляем,в нашем случае это toString, а затем последний параметр-объект json, который имеет значение, которое будет функцией и тремя параметрами, записываемыми, перечисляемыми и настраиваемыми.Прямо сейчас я просто заявил, что все это правда.

если вы запустите пример, вы получите вывод как:Джамиль Трейлер

давайте поймем, почему мы нужны три свойства, такие как запись,перечислить и настроить. записи Одной из очень раздражающих частей javascript является, если вы измените свойство toString на что - то другое, например enter image description here

если запустить это снова, все ломается Давайте изменим writable на false. Если запустить то же самое снова, вы получите правильный вывод как "Jameel Moideen". Это свойство предотвратит перезапись этого свойства позже. перечисли при печати всех ключей внутри объекта можно просмотреть все свойства, включая toString.

console.log(Object.keys(employee));

enter image description here

если вы установите enumerable в false, вы можете скрыть свойство toString от всех остальных. Если запустить это снова, вы получите firstName, lastName настраиваемые!--6-->

если кто-то позже переопределил объект позже, например, перечислил true и запустил его. Вы можете увидеть toString собственность пришла снова.

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
    value: function () {
        return this.firstName + " " + this.lastName;
    },
    writable: false,
    enumerable: false,
    configurable: true
});

//change enumerable to false
Object.defineProperty(employee, 'toString', {

    enumerable: true
});
employee.toString="changed";
console.log(Object.keys(employee));

enter image description here

вы можете ограничить это поведение, установив настраиваемое значение false.

исходная ссылка на эту информацию из моего личного блога


по сути, defineProperty - Это метод, который принимает 3 параметра - объект, свойства и описание. То, что происходит в этом конкретном вызове, - это "health" свойства player объекту присваивается 10 плюс 15 раз уровень объекта игрока.


да нет больше функции расширения для setter & getter установки это мой пример


резюме:

Object.defineProperty(player, "health", {
    get: function () {
        return 10 + ( player.level * 15 );
    }
});

Object.defineProperty используется для создания нового свойства на объекте игрока. Object.defineProperty - это функция, которая изначально присутствует в среде выполнения JS и принимает следующие аргументы:

Object.defineProperty(obj, prop, descriptor)

  1. на объект на котором мы хотим определить новое свойство
  2. на название нового свойства мы хотим определить
  3. дескриптор объект

объект дескриптора является интересной частью. Здесь мы можем определить следующие вещи:

  1. настраиваемые!--29--> <boolean>: If true дескриптор свойства может быть изменен и может быть удален от объекта. Если настраиваемый false свойства дескриптора, которые передаются в Object.defineProperty невозможно изменить.
  2. записи <boolean>: If true свойство может быть перезаписывается с помощью оператора присваивания.
  3. перечисли <boolean>: If true свойство может быть повторено в for...in петли. Также при использовании