如你所知,getter和setter已經成為了JavaScript的一部分。它們廣泛支援所有的主流瀏覽器,甚至是IE8。
我不認為這個點子通常是錯的,但我認為它不是非常適合JavaScript。可能看起來getter和setter可以簡化程式碼和節省時間,但其實它們會帶來隱藏錯誤,而這些錯誤第一眼看並不明顯。
首先小小地總結一下這些是什麼東西:
有時候,我們希望能允許存取一個會返回動態計算值的屬性,或者你可能想要反映內部變數的狀態,而不使用顯式的方法呼叫。
為了說明它們是如何運作的,讓我們來看一個有著兩個屬性的person對象,這兩個屬性為:firstName和lastName,以及一個計算值:fullName。
var obj = { firstName: "Maks", lastName: "Nemisj" }
計算值fullName會傳回firstName和lastName兩者的串連。
Object.defineProperty(person, 'fullName', { get: function () { return this.firstName + ' ' + this.lastName; } });
為了得到fullName的計算值,不需要像person.fullName()帶可怕的括號,只需要使用簡單的var fullName = person.fullName。
這也適用於setter,你可以透過使用函數設定值:
Object.defineProperty(person, 'fullName', { set: function (value) { var names = value.split(' '); this.firstName = names[0]; this.lastName = names[1]; } });
使用就和getter一樣簡單:person.fullName = ‘Boris Gorbachev’。這將會呼叫上面定義的函數,並分離Boris Gorbachev成firstName和lastName。
你也許在想:「嘿,我喜歡getter和setter方法,它們感覺更自然,就像JSON一樣。」你說得對,它們的確是這樣的,但我們先退一步來看一看fullName在getter和setter之前是如何運作的。
為得到值,我們將使用類似getFullName()的某些東西,以及為了設定值,我們將使用person.setFullName(‘Maks Nemisj’)。
如果拼錯函數名,person.getFullName()寫成person.getFulName()會發生什麼事?
JavaScript會給出一個錯誤:
person.getFulName(); ^ TypeError: undefined is not a function
這個錯誤會在適當的時候適當的地方被觸發。訪問函數不存在的物件將觸發錯誤——這是好的。
現在,讓我們來看看當用錯誤的名稱來使用setter的時候會發生什麼事?
person.fulName = 'Boris Gorbachev';
什麼都沒有。物件是可擴展的,可以動態分配鍵和值,因此不會有錯誤在運行時被拋出。
這樣的行為意味著錯誤可能顯示在使用者介面上的某個地方,或者,當某些操作被執行在錯誤的值上時,而並非是打字錯誤的時刻。
追蹤應該發生在過去但卻顯示在將來的程式碼流上的錯誤是如此有趣。
這個問題可以透過sealAPI來部分解決。只要物件是密封的,它就不能突變,也就是意味著fulName會試圖分配一個新鍵到person對象,而且它會失敗。
出於某種原因,當我在Node.js V4.0測試這個的時候,它沒有按照我期待的那樣工作。所以,我不能確保這個解決方案。
而更令人沮喪的是,對於setter一點也沒有解決方法。正如我前面提到的,物件是可擴展和可故障保護的,這意味著存取一個不存在的鍵不會導致任何錯誤。
如果這種情況只適用於物件的文字的話,我不會多此一舉地寫這篇文章,但在ECMAScript 2015(ES6)和用類別定義getter和setter能力的興起之後,我決定寫下關於潛在陷阱的部落格。
我知道目前類別在某些JavaScript社群中不是非常受歡迎。人們對在函數式/基於原型的語言,例如JavaScript中是否需要它們,爭執不休。然而,事實是,類別就在ECMAScript 2015(ES6)規範說明中,並且將存在於此一段時間。
對我來說,類別是指定在類別的外部世界(消費者)和應用程式的內部世界之間的定義良好的API的一種方式。這就是白紙黑字放入規則的抽象,我們假定這些規則不會很快改變。
改進person對象,做一個它的real類別。 person定義了介面用於取得和設定fullName。
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } getFullName() { return this.firstName + ' ' + this.lastName; } setFullName(value) { var names = value.split(' '); this.firstName = names[0]; this.lastName = names[1]; } }
類別定義了一個嚴格的介面描述,但getter和setter方法使其變得不太嚴格。我們已經習慣了臃腫的錯誤,當工作於物件文字和JSON時的按鍵中出現拼字錯誤的時候。我希望至少類別能夠更嚴格,並且在這個意義上,提供更好的回饋給開發人員。
雖然這種情況在定義getter和setter在一個類別上的時候沒有任何不同。但它不會阻止任何人拼錯。
class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get fullName() { return this.firstName + ' ' + this.lastName; } set fullName(value) { var names = value.split(' '); this.firstName = names[0]; this.lastName = names[1]; } }
有拼字錯誤的執行不會給出任何錯誤:
var person = new Person('Maks', 'Nemisj'); console.log(person.fulName);
同樣不嚴格,不冗長,不可追蹤的行為導致可能會出錯。
在我发现这一点后,我有一个问题:在使用getter和setter的时候,有没有什么可以做的,以便于使得类更严格?我发现:有是肯定有,但是这值得吗?增加额外层次的复杂性到代码就只是为了使用数量更少的括号?对于API定义,也可以不使用getter和setter,而这样一来就能解决这个问题。除非你是一个铁杆开发人员,并愿意继续进行,不然还有另一种解决方案,如下所述。
除了getter和setter方法,ECMAScript 2015(ES6)还自带proxy对象。proxy可以帮助你确定委托方法,这些委托方法可以在实际访问键执行之前,用来执行各种操作。事实上,它看起来像动态getter / setter方法。
proxy对象可以用来捕捉任何到类的实例的访问,并且如果在类中没有找到预先定义的getter或setter就会抛出错误。
为了做到这一点,必须执行下面两个操作:
创建基于Person原型的getter和setter清单。
创建将测试这些清单的Proxy对象。
让我们来实现它。
首先,为了找出什么样的getter和setter方法可以用在类Person上,可以使用getOwnPropertyNames和getOwnPropertyDescriptor:
var names = Object.getOwnPropertyNames(Person.prototype); var getters = names.filter((name) => { var result = Object.getOwnPropertyDescriptor(Person.prototype, name); return !!result.get; }); var setters = names.filter((name) => { var result = Object.getOwnPropertyDescriptor(Person.prototype, name); return !!result.set; });
在此之后,创建一个Proxy对象:
var handler = { get(target, name) { if (getters.indexOf(name) != -1) { return target[name]; } throw new Error('Getter "' + name + '" not found in "Person"'); }, set(target, name) { if (setters.indexOf(name) != -1) { return target[name]; } throw new Error('Setter "' + name + '" not found in "Person"'); } }; person = new Proxy(person, handler);
现在,只要你尝试访问person.fulName,就会显示Error: Getter “fulName” not found in “Person”的消息。
以上是JavaScript中使用getter與setter為什麼不好呢的詳細內容。更多資訊請關注PHP中文網其他相關文章!