【问题标题】:Defining read-only properties within a factory-function, using getters使用 getter 在工厂函数中定义只读属性
【发布时间】:2018-12-12 13:38:34
【问题描述】:

看来,在 JS 中定义只读属性有两种可行的方法 - 使用 Object.definePropertygetter

就我而言,我必须坚持使用 getter 方法,但考虑到上下文,它似乎并不合适,因为我正在 LoyaltyCard 工厂函数中实现 getter .

必须将属性“id”、“balance”和“discount”定义为只读。从'id'开始,出现语法错误,返回:“Unexpected token, expected ;”。

有没有办法巧妙地实现 getter,如 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get 中所建议的那样,或者我可能遗漏了什么?

function rand(min, max) {
  return Math.ceil((max - min + 1) * Math.random()) + min - 1;
}

function generateId() {
  return Array(4).fill(1).map(value => rand(1000, 9999)).join('-');
}  


let LoyaltyCard = function(name, sum) {
  this.owner = name;
  this.id; //unfinished
  this.balance = sum; 
  this.discount = 0; 
  this.orders = Array.of(sum);
}

LoyaltyCard.prototype.getFinalSum = function(sum) {
  let calculatedDiscount;

  if (this.balance >= 3000 && this.balance < 5000) {
    calculatedDiscount = 3;
  } else if (this.balance >= 5000 && this.balance < 10000){
    calculatedDiscount = 5;
  } else if (this.balance >= 10000) {
    calculatedDiscount = 7; 
  }

  Object.defineProperty(this, 'discount', {
    value: calculatedDiscount
  });

  finalSum = sum * (1 - this.discount / 100);
  this.orders.push(sum);
  return finalSum;
}

LoyaltyCard.prototype.append = function(sum) {
  this.orders.push(sum);
  return Object.defineProperty(this, 'balance', {
    value: this.balance += sum
  });
}

LoyaltyCard.prototype.show = function() {
  console.log(`Card ${this.id}:\nOwner: ${this.owner}\nBalance: ${this.balance} Q\nCurrent discount: ${this.discount} %\nOrders:\n  #1 on ${this.orders[0]} Q\n  #2 on ${this.orders[1]} Q`);
}

//Call sample:

const card = new LoyaltyCard('John Doe', 6300);

let newOrderSum = 7000;
let finalSum = card.getFinalSum(newOrderSum);
console.log(`The final order amount for the order on ${newOrderSum} Q using the loyalty card will be 
${finalSum} Q. ${card.discount} %. discount applied`);

card.append(newOrderSum);
console.log(`Loyalty card balance after the purchase ${card.balance} Q.`);
card.show();

【问题讨论】:

  • 无论如何你都不希望 getter 被这样定义,因为每次访问属性时你都会得到一个新的随机 id。
  • 你为什么不想使用defineProperty
  • 不是我反对 difineProperty,而是使用 getter 将某些属性定义为只读的给定任务(大概是因为它是一种更现代的方法)
  • 只使用 getter 不会使属性只读。如果您直接分配该属性,它将优先于 getter
  • 如果它正是我需要的,但只是在某个执行点上呢?二传手进入游戏?

标签: javascript ecmascript-6 ecmascript-5


【解决方案1】:

请考虑使用“模块模式”将您要存储的数据封装为“私有”。这里是演示

function LoyaltyCard(name, sum) {
  let owner = name;
  let id; // get id from your generateId()
  let balance = sum;
  let discount = 0;
  let orders = Array.of(sum);

  function getFinalSum(sum) {
    /* implementation */
    balance += sum; // DEMO ONLY
    return sum; //  DEMO ONLY
  }

  function append(sum) { /* implementation */ }

  function show() { /* implementation */ }

  return {
    get name() {
      return owner;
    },
    set name(name) {
      owner = name;
    },
    get balance() {
      return balance;
    },
    getFinalSum,
    append,
  };
}

const card = LoyaltyCard('peter', 100);
console.log(card.balance); // 100
console.log(card.getFinalSum(200)); // 200
console.log(card.balance); // 300
card.balance = 50; // silently fail
console.log(card.balance); // 300

有关“模块模式”的更多信息,请阅读 YDKJS https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch5.md

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 2012-09-28
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多