[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,符合预期

posted @ 2018-08-08 12:04  琐碎之人  阅读(547)  评论(0编辑  收藏  举报