🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
![](https://box.kancloud.cn/e75c21d8ec4b017a6d58256f42508fea_255x322.jpeg) ``` const basePrice = this._quantity * this._itemPrice; if (basePrice > 1000) return basePrice * 0.95; else return basePrice * 0.98; ``` ![](https://box.kancloud.cn/a3bed334e2e1f6d1a46c5039deb25af9_91x152.jpeg) ``` get basePrice() {this._quantity * this._itemPrice;} ... if (this.basePrice > 1000) return this.basePrice * 0.95; else return this.basePrice * 0.98; ``` ### 动机 临时变量的一个作用是保存某段代码的返回值,以便在函数的后面部分使用它。临时变量允许我引用之前的值,既能解释它的含义,还能避免对代码进行重复计算。但尽管使用变量很方便,很多时候还是值得更进一步,将它们抽取成函数。 如果我正在分解一个冗长的函数,那么将变量抽取到函数里能使函数的分解过程更简单,因为我就不再需要将变量作为参数传递给提炼出来的小函数。将变量的计算逻辑放到函数中,也有助于在提炼得到的函数与原函数之间设立清晰的边界,这能帮我发现并避免难缠的依赖及副作用。 改用函数还让我避免了在多个函数中重复编写计算逻辑。每当我在不同的地方看见同一段变量的计算逻辑,我就会想方设法将它们挪到同一个函数里。 这项重构手法在类中施展效果最好,因为类为待提炼函数提供了一个共同的上下文。如果不是在类中,我很可能会在顶层函数中拥有过多参数,这将冲淡提炼函数所能带来的诸多好处。使用嵌套的小函数可以避免这个问题,但又限制了我在相关函数间分享逻辑的能力。 以查询取代临时变量(178)手法只适用于处理某些类型的临时变量:那些只被计算一次且之后不再被修改的变量。最简单的情况是,这个临时变量只被赋值一次,但在更复杂的代码片段里,变量也可能被多次赋值——此时应该将这些计算代码一并提炼到查询函数中。并且,待提炼的逻辑多次计算同样的变量时,应该能得到相同的结果。因此,对于那些做快照用途的临时变量(从变量名往往可见端倪,比如`oldAddress`这样的名字),就不能使用本手法。 ### 做法 - 检查变量在使用前是否已经完全计算完毕,检查计算它的那段代码是否每次都能得到一样的值。 - 如果变量目前不是只读的,但是可以改造成只读变量,那就先改造它。 - 测试。 - 将为变量赋值的代码段提炼成函数。 > 如果变量和函数不能使用同样的名字,那么先为函数取个临时的名字。 > > 确保待提炼函数没有副作用。若有,先应用将查询函数和修改函数分离(306)手法隔离副作用。 - 测试。 - 应用内联变量(123)手法移除临时变量。 ### 范例 这里有一个简单的订单类。 ##### class Order... ``` constructor(quantity, item) { this._quantity = quantity; this._item = item; } get price() { var basePrice = this._quantity * this._item.price; var discountFactor = 0.98; if (basePrice > 1000) discountFactor -= 0.03; return basePrice * discountFactor; } } ``` 我希望把`basePrice`和`discountFactor`两个临时变量变成函数。 先从`basePrice`开始,我先把它声明成`const`并运行测试。这可以很好地防止我遗漏了对变量的其他赋值点——对于这么个小函数是不太可能的,但当我处理更大的函数时就不一定了。 ##### class Order... ```  constructor(quantity, item) {   this._quantity = quantity;   this._item = item;  }  get price() {   const basePrice = this._quantity * this._item.price;   var discountFactor = 0.98;   if (basePrice > 1000) discountFactor -= 0.03;   return basePrice * discountFactor;  } } ``` 然后我把赋值操作的右边提炼成一个取值函数。 ##### class Order... ``` get price() {  const basePrice = this.basePrice;  var discountFactor = 0.98;  if (basePrice > 1000) discountFactor -= 0.03;  return basePrice * discountFactor; }  get basePrice() {   return this._quantity * this._item.price;  } ``` 测试,然后应用内联变量(123)。 ##### class Order... ``` get price() {  const basePrice = this.basePrice;  var discountFactor = 0.98;  if (this.basePrice > 1000) discountFactor -= 0.03;  return this.basePrice * discountFactor; } ``` 接下来我对`discountFactor`重复同样的步骤,先是应用提炼函数(106)。 ##### class Order... ``` get price() {  const discountFactor = this.discountFactor;  return this.basePrice * discountFactor; }  get discountFactor() {   var discountFactor = 0.98;   if (this.basePrice > 1000) discountFactor -= 0.03;   return discountFactor; } ``` 这里我需要将对`discountFactor`的两处赋值一起搬移到新提炼的函数中,之后就可以将原变量一起声明为`const`。 然后,内联变量: ``` get price() { return this.basePrice * this.discountFactor; } ```