[JavaScript] Uncaught TypeError: Method get Set.prototype.size called on incompatible receiver
在对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,符合预期