[JavaScript] Uncaught TypeError: Method get Set.prototype.size called on incompatible receiver
阿新 • • 發佈:2018-08-08
fun 例子 .proto alt .get ret rabl singleton png
在對Set進行方法擴展的時候,無法覆蓋size屬性
情景:定義一個SingletonSet,繼承自Set,size只能為1,並且不能add和remove
//首先是extend函數 var extend = (function () { //檢查是否存在bug for (var p in { toString: null }) { //如果進來了,那說明沒有bug return function extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) { // var desc = Object.getOwnPropertyDescriptor(source, prop); // Object.defineProperty(o, prop, desc); o[prop] = source[prop]; //書上的例子, } } return o; } } //如果存在bug的話 return function patched_extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; //復制可以枚舉的屬性 for (var prop in source) { // var desc = Object.getOwnPropertyDescriptor(source, prop); // Object.defineProperty(o, prop, desc); o[prop] = source[prop]; } //檢查特殊屬性並進行復制 for (var j = 0; j < protoprops.length; j++) { prop = protoprops[j]; if (source.hasOwnProperty(prop)) { // var desc = Object.getOwnPropertyDescriptor(source, prop); // Object.defineProperty(o, prop, desc); o[prop] = source[prop]; } } } return o; } var protoprops = ["toString", "valueOf", "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocalString" ]; }()); //調用 function SingletonSet(member) { this.member = member; this.size =2; } SingletonSet.prototype = inherit(Set.prototype); extend(SingletonSet.prototype, { constructor: SingletonSet, add: function () { throw "read-only set" }, remove: function () { throw "read-only set" }, get size(){ return 1; }, foreach:function(f,context){ f.call(context,this.member); }, contains:function(x){ return x===this.member; } }); var newSet = new SingletonSet(1); console.log(newSet.size); //打印
打印出來發現newSet的size屬性報錯如下:
之後通過排查,在extend函數中 該位置進行打印測試:
for (var prop in source) { // var desc = Object.getOwnPropertyDescriptor(source, prop); // Object.defineProperty(o, prop, desc); o[prop] = source[prop]; console.log(prop); console.log(o[prop]); }
打印如下:
也就是說,是在執行o[prop] = source[prop];
時,當prop===‘size‘
時,因拋出錯誤,並未將自定義的方法賦值給目標對象。
所以,我的解決辦法,也就是註釋掉的那兩句,通過Object.defineProperty
來進行方法的復制,從而避免使用o[‘size‘]
而拋出錯誤。
修改後的extend函數如下
var extend = (function () { //檢查是否存在bug for (var p in { toString: null }) { //如果進來了,那說明沒有bug return function extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) { var desc = Object.getOwnPropertyDescriptor(source, prop); Object.defineProperty(o, prop, desc); // o[prop] = source[prop]; //書上的例子, } } return o; } } //如果存在bug的話 return function patched_extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; //復制可以枚舉的屬性 for (var prop in source) { var desc = Object.getOwnPropertyDescriptor(source, prop); Object.defineProperty(o, prop, desc); //o[prop] = source[prop]; } //檢查特殊屬性並進行復制 for (var j = 0; j < protoprops.length; j++) { prop = protoprops[j]; if (source.hasOwnProperty(prop)) { var desc = Object.getOwnPropertyDescriptor(source, prop); Object.defineProperty(o, prop, desc); //o[prop] = source[prop]; } } } return o; } var protoprops = ["toString", "valueOf", "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocalString" ]; }());
此時
var newSet = new SingletonSet(1);
console.log(newSet.size); //打印
//結果 為 1,符合預期
[JavaScript] Uncaught TypeError: Method get Set.prototype.size called on incompatible receiver