zoukankan      html  css  js  c++  java
  • [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,符合预期
    
    
  • 相关阅读:
    算法·进阶石
    How can I determine whether a 2D Point is within a Polygon?
    直线射线线段的相交判断
    关于时间的感想
    企业级自定义表单引擎解决方案(七)--视图模型管理
    GB28181安防Web无插件流媒体平台LiveGBS如何配置集群部署增加并发播放和录像
    接口测试之object []如何类型传参
    Excel2010工作簿被锁定,无法复制或者新增加sheet表格。
    drawio下载
    alsa-amixer-api
  • 原文地址:https://www.cnblogs.com/ForRickHuan/p/9441983.html
Copyright © 2011-2022 走看看