• [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,符合预期
    
    
  • 相关阅读:
    操作 Java 数组的 12 个最佳方法
    详解 JavaScript 中 splice() 方法
    Java 读取 .properties 配置文件的几种方式
    表单中单选、多选、选择框值的获取及表单的序列化
    一个调出上下文菜单的实例
    跨浏览器的事件侦听器和事件对象
    动态加载js和css
    php语言实现的7种基本的排序方法
    CORS(跨源资源共享)实战
    ubuntu中LAMP环境搭建及ubuntu语言和输入法设置
  • 原文地址:https://www.cnblogs.com/ForRickHuan/p/9441983.html
Copyright © 2020-2023  润新知