2015-09-28 172 views
3

在我們的應用程序的NodeJS,我們通過默認的Error對象擴展定義自定義錯誤類:Object.defineProperty覆蓋只讀屬性

"use strict"; 
const util = require("util"); 

function CustomError(message) { 
    Error.call(this); 
    Error.captureStackTrace(this, CustomError); 
    this.message = message; 
} 

util.inherits(CustomError, Error); 

這使我們與堆棧跟蹤throw CustomError("Something");顯示正確了, instanceof Errorinstanceof CustomError都正常工作。

然而,對於我們的API在返回錯誤(通過HTTP),我們希望將錯誤轉換成JSON。調用JSON.stringify()上的錯誤導致"{}",這顯然不是真正的消費者描述。

爲了解決這個問題,我想重寫CustomError.prototype.toJSON(),返回一個對象常量錯誤的姓名和消息。然後JSON.stringify()只想字符串化該對象和所有將工作偉大:

// after util.inherits call 

CustomError.prototype.toJSON =() => ({ 
    name : "CustomError", 
    message : this.message 
}); 

不過,我很快發現,這將引發TypeError: Cannot assign to read only property 'toJSON' of Error。當我試圖寫入原型時,這可能是有意義的。所以我改變了構造來代替:

function CustomError(message) { 
    Error.call(this); 
    Error.captureStackTrace(this, CustomError); 
    this.message = message; 
    this.toJSON =() => ({ 
     name : "CustomError", 
     message : this.message 
    }); 
} 

這樣(我的預期),則CustomError.toJSON功能將被使用,並且CustomError.prototype.toJSON(從錯誤)將被忽略。

不幸的是,這只是拋出在對象的構造錯誤:Cannot assign to read only property 'toJSON' of CustomError

下一個我試圖從文件,其中排序在正在拋出了沒有錯誤的問題解決了去除"use strict";,雖然toJSON()功能不使用JSON.stringify()可言。

在這一點上,我只是絕望,只是嘗試隨機的東西。最後,我結束了使用Object.defineProperty(),而不是直接分配給this.toJSON

function CustomError(message) { 
    Error.call(this); 
    Error.captureStackTrace(this, CustomError); 
    this.message = message; 
    Object.defineProperty(this, "toJSON", { 
     value:() => ({ 
      name : "CustomError", 
      message : this.message 
     }) 
    }); 

這完美的作品。在嚴格模式下,沒有錯誤被調用,JSON.stringify()返回{"name:" CustomError", "message": "Something"}就像我想要的那樣。

所以,雖然它的工作原理,因爲我希望它到現在爲止,我還是想知道:

  1. 爲什麼這項工作到底是什麼?我期望它是相當於this.toJSON = ...,但顯然它不是。
  2. 它應該這樣工作嗎?即依靠這種行爲是否安全?
  3. 如果不是,我應該如何正確覆蓋toJSON方法? (如果可能的話)
+1

看看[我的答案在這裏](http://stackoverflow.com/questions/22960493/i-dont-understand-writable-and-configurable-property-attributes-of-objects/22960738#22960738)和看看這是你問的問題。謝謝! –

+0

@ Qantas94Heavy這的確很奇怪,但至少可以解釋爲什麼我無法正常分配給屬性。我仍然沒有從你的評論中的[鏈接文章](https://esdiscuss.org/topic/set-and-inherited-readonly-data-properties)中獲得:Object.defineProperty是否工作(即覆蓋無論如何,只讀原型屬性)通過設計還是我不應該依賴的這種意外行爲? – Lapixx

回答

1

因爲我注意到你使用箭頭函數,我假設你可以訪問ES6,也就是說你也可以訪問類。

你可以只是簡單的擴展Error類。例如:

class CustomError extends Error { 
    toJSON() { 
     return { 
      name: 'CustomError', 
      message: this.message 
     }; 
    } 
} 
+0

好點,看起來更清潔!但是,爲什麼這個(並使用'Object.defineProperty')工作並試圖設置'this.toJSON'不? – Lapixx

+0

實際上我不太確定,不能在節點4.x上重現。 –

1

爲什麼這項工作到底是什麼?

Object.defineProperty只是定義了一個屬性(或者如果它的屬性已經存在並且是可配置的,它就會改變它的屬性)。與轉讓this.toJSON = …不同,它不關心任何繼承,也不檢查是否存在可能是setter或non-writable的繼承屬性。

它應該這樣工作嗎?即依靠這種行爲是否安全?

是的,是的。可能你甚至可以在原型上使用它。


爲了您的實際使用情況,鑑於最近的node.js版本,使用ES6類extends Error最好的結果。