Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 扩展基本体而不进行原型化_Javascript - Fatal编程技术网

Javascript 扩展基本体而不进行原型化

Javascript 扩展基本体而不进行原型化,javascript,Javascript,我正在开发一个非常丑陋的库,它可以让你做一些奇怪的事情。 拥有一个图形,您可以以链式样式映射一组集合,并且在更改 要在整个系统中更改的值 当结束类型是JS原语时,问题就出现了 在我的例子中,在使用值和对象绘制图形后,我可以执行以下操作: CHAIN.components[0].value = 20; components是使用setter和getter对图的节点进行过滤的函数。 如果组件中只筛选了一个节点,则用户设置的默认值将可用,而无需执行以下操作: CHAIN.components.va

我正在开发一个非常丑陋的库,它可以让你做一些奇怪的事情。 拥有一个图形,您可以以链式样式映射一组集合,并且在更改 要在整个系统中更改的值

当结束类型是JS原语时,问题就出现了

在我的例子中,在使用值和对象绘制图形后,我可以执行以下操作:

CHAIN.components[0].value = 20; 
components
是使用setter和getter对图的节点进行过滤的函数。 如果组件中只筛选了一个节点,则用户设置的默认值将可用,而无需执行以下操作: CHAIN.components.value=20; 而是: 链组件=20

现在的问题是,除了默认值(在我的例子中,默认值设置为
value
)之外,节点还可能有其他方法或属性

我如何在不破坏Number.prototype的情况下使用Number对象上的setter和getter,因为
CHAIN.components
现在是一个数字(如果它不是一个原语,我已经以一种不引人注目的方式使它工作),但是当我想调用
CHAIN.components.func()时
出现了一个问题,因为我必须在编号后追加。每次我设置一个集合或进入
组件时,都要创建
函数的原型,然后将其删除

你有没有其他办法来完成这种行为

您需要的代码如下:

/*jslint nomen: true, sloppy: true*/
GRID.modules.OHM || Object.extend(GRID.modules, ( function() {
    var Node, Nodes, Ohm, num_proto = Number.prototype.__clone(), str_proto = String.prototype.__clone();
    Node = function(uid) {
        var UID = uid;
        this.getUID = function() {
            return UID;
        };
    };
    Nodes = function() {
        var stack = [];
        this.add = function(id, val) {
            var n = new Node(stack.length);
            val.id = id;
            Object.extend(n, val);
            stack.push(n);
            return n.getUID();
        };
        this.getById = function(id) {
            return stack.filter(function(v) {
                var a = id || v.id;
                return (v.id === a);
            });
        };
        this.getByUID = function(UID) {
            return stack[UID];
        };
        this.get = function(callback) {
            !Object.isString(callback) || ( callback = [callback]);
            var f = Object.isFunction(callback) ? callback : (Object.isArray(callback) ? function(k) {
                return (callback.indexOf(k.id) >= 0);
            } : function(k) {
                return true;
            });
            return stack.filter(f);
        };
    };
    Ohm = function(n) {
        var graph = n || (new Nodes()), filters = {}, __nodes = {}, addGS = function(obj, name, conf, binder) {
            var alfa = {};
            Object.extend(alfa, conf);
            if (!alfa.get) {
                alfa.get = function() {
                    var a = this.g.getById(this.p);
                    return a.length === 1 ? a[0] : a;
                }.bind(binder);
            } else {
                alfa.get = alfa.get.bind(binder);
            }
            if (!alfa.set) {
                alfa.set = function(value) {
                    this.g.getById(this.p).forEach(function(k) {
                        Object.extend(k, value);
                        return true;
                    });
                }.bind(binder);
            } else {
                alfa.set = alfa.set.bind(binder);
            }
            Object.defineProperty(obj, name, alfa);
        }, add = function(id, node) {
            if (__nodes.hasOwnProperty(id)) {
                addGS(__nodes, id, {
                    enumerable : true
                }, {
                    t : this,
                    p : id,
                    g : graph
                });
            }
            return graph.add(id, node || {});
        };
        Object.extend(this, {
            add : function() {
                add.apply(this, arguments);
            },
            map : function(name, f, that) {
                var n = name, filterer = ['add', 'map', '__all'];
                n = Object.isFunction(n) ? name.apply(that, arguments.slice(3)) : n;
                if (filterer.indexOf(n.toLowerCase()) >= 0) {
                    console.log("You can't map over a basic property of object !!! Please read the freakin' manual.");
                    return null;
                }
                if (!filters.hasOwnProperty(n)) {
                    filters[n] = new Ohm(graph);
                    addGS(this, n, {
                        get : function() {
                            this.g.get(this.f).forEach(function(v, key, arr) {
                                var temp, binder;
                                if (arr.length !== 1) {
                                    if (!this.filt.hasOwnProperty(v.id)) {
                                        addGS(this.filt, v.id, {
                                            set : function(value) {
                                                this.t.g.getById(this.p).filter(this.t.f).forEach(function(k) {
                                                    Object.extend(k, value);
                                                });
                                            },
                                            get : function() {
                                                var a = this.t.g.getById(this.p).filter(this.t.f);
                                                return a.length === 1 ? a[0] : a;
                                            }
                                        }, {
                                            t : this,
                                            p : v.id
                                        });
                                        (key !== arr.length - 1) || Object.extend(this.filt, this.g.get(this.f));
                                    }
                                } else {
                                    if (Object.isFunction(v.__new__)) {
                                        v.__default = function() {
                                            return Object.extend((new this.__new__(arguments)), this);
                                        };
                                    }
                                    if (!Object.isUndefined(v.__default)) {
                                        temp = this.filt;
                                        this.filt = Object.isFunction(v.__default) ? v.__default.bind(v) : v.__default;
                                        if (Object.isNumber(this.filt) || Object.isString(this.filt)) {
                                            var prot = Object.isNumber(this.filt) ? Number : String;
                                            for (var i in temp) {
                                                if (temp.hasOwnProperty(i) && !prot.prototype.hasOwnProperty(i)) {
                                                    var bin = {
                                                        t : temp,
                                                        m : i,
                                                        p : prot,

                                                    };
                                                    Object.defineProperty(prot.prototype, i, {
                                                        set : function(value) {
                                                            Object.defineProperty(this.p.prototype, this.m, {
                                                                configurable : true, // defaults to false
                                                                writable : false,
                                                                value : 1
                                                            });
                                                            delete this.p.prototype[this.m];
                                                            this.t[this.m] = value;
                                                        }.bind(bin),
                                                        get : function() {
                                                            Object.defineProperty(this.p.prototype, this.m, {
                                                                configurable : true, // defaults to false
                                                                writable : false,
                                                                value : 1
                                                            });
                                                            delete this.p.prototype[this.m];
                                                            return this.t[this.m];
                                                        }.bind(bin),
                                                        enumerable : true,
                                                        configurable : true
                                                    });
                                                }
                                            }
                                        } else {
                                            Object.extend(this.filt, temp);
                                        }
                                    }
                                    if (Object.isNumber(this.filt) || Object.isString(this.filt)) {
                                        var prot = Object.isNumber(this.filt) ? Number : String;
                                        for (var i in v) {
                                            if (v.hasOwnProperty(i) && !prot.prototype.hasOwnProperty(i)) {
                                                var bin = {
                                                    t : v,
                                                    m : i,
                                                    p : prot,

                                                };
                                                Object.defineProperty(prot.prototype, i, {
                                                    set : function(value) {
                                                        Object.defineProperty(this.p.prototype, this.m, {
                                                            configurable : true, // defaults to false
                                                            writable : false,
                                                            value : 1
                                                        });
                                                        delete this.p.prototype[this.m];
                                                        this.t[this.m] = value;
                                                    }.bind(bin),
                                                    get : function() {
                                                        Object.defineProperty(this.p.prototype, this.m, {
                                                            configurable : true, // defaults to false
                                                            writable : false,
                                                            value : 1
                                                        });
                                                        delete this.p.prototype[this.m];
                                                        return this.t[this.m];
                                                    }.bind(bin),
                                                    enumerable : true,
                                                    configurable : true
                                                });
                                            }
                                        }
                                    } else {
                                        Object.extend(this.filt, v);
                                    }
                                }
                            }, this);
                            return this.filt;
                        },
                        set : function(value) {
                            this.g.get(this.f).forEach(function(k) {
                                Object.extend(k, value);
                            });
                        }
                    }, {
                        t : this,
                        f : f,
                        g : graph,
                        filt : filters[n]
                    });
                }
            }
        }, true, true);
        addGS(this, '__all', {
            get : function() {
                var a = this.g.getById();
                Object.extend(__nodes, a.length === 1 ? a[0] : a);
                return __nodes;
            },
            enumerable : true
        }, {
            t : this,
            p : null,
            g : graph
        });
    };
    window['Ω'] = Ohm;
    return {
        OHM : Ohm,
    };
}()));
现在是演示:

var c = new Ω();
c.add('ann', {
__default : 58,
blah : 98,
ceva : function()
{
    console.log('asd');
}
});
c.add('ann2',{
    __default: function(){
       console.log('hello');
    },
    abc: 78,
    dce: function(){
       console.log(' world');
    }
};
c.add('b2', {
__new__ : function() {
    this.init = function() {
        this.id = 86;
    };
    this.mer = function() {
        console.log(this);
    };
},
els : 'asadar'
});
c.map('b2', function(k) {
return k.id === 'b2';
});
c.map('ann', function(k) {
return k.id === 'ann';
});
c.map('ann2', function(k) {
return k.id === 'ann2';
});
console.log(c.ann); // returns 58 ( the __default value )
console.log(c.ann.blah); // returns 98
console.log(c.ann.blah.blah); // undefined
console.log(c.ann2);  // function()
c.ann2(); // prints out 'hello'
c.ann2.cde(); // prints out 'world'
c.ann2 = 60;
console.log(c.ann2); // 60
console.log(c.ann2.cde()); // prints out 'world'
这段代码很有效,但我必须使用数字或字符串原型的部分让我很困扰。你有其他方法吗


原因是要做一些有人说可以用PHP而不是JS来完成的事情,这个家伙最近和我一起在WebGL着色器上工作,他讨厌他必须写700行代码才能使用多重效果与FBO相结合,而不是100行,这需要他使用类似的工具,比如用PHP编写的工具。所以是的,我知道原语原型上的e访问器是一种黑客行为,但是如果链末端对象是原语,我如何在不使用valueOf的情况下使其不同呢?

不要将其设置为原语数字,将其设置为行为类似于数字的对象。您可以使用
数字
对象,并使用自定义属性扩展它(请参阅),但通常为什么不子类
Number
呢?它只需要保留一个返回数字的:

function MyNumber(n) {
    this.value = Number(n);
}
MyNumber.prototype = Object.create(Number.prototype, {constructor:{value:MyNumber}});
MyNumber.prototype.valueOf = function() {
    return this.value;
};
// OK, we have to overwrite those methods as they don't work on subclasses of Number
["toExponential", "toFixed", "toLocaleString", "toPrecision", "toString"].forEach(function(name) {
    MyNumber.prototype[name] = function() {
        return Number.prototype[name].apply(new Number(this.value), arguments);
    };
});

// now extend the prototype with other properties, e.g. chaining methods
当然,您可能需要将
组件
设置为将给定数字(或数字)转换为MyNumber的setter:

var actualNumber = new MyNumber;
Object.defineProperty(MyFabulousChainingThing, "components", {
    get: function() { return actualNumber; },
    set: function(x) { actualNumber.value = Number(x); }
});

好的,现在我已经阅读了附带的代码(但不能完全理解)。缺少一些注释,但我不会抱怨,我自己的代码并不好,因为我不希望任何人阅读或理解它们:-)

你是对的,你扩展原生原型的部分很可怕。据我所知,在返回数字/字符串之前,需要在数字或字符串原型上定义访问器属性。在获取和设置时,访问器属性被数据属性(??)覆盖,然后在存储/返回值之前删除整个属性。这似乎是一个聪明的技巧,允许在原语值上使用自定义属性,但是:

  • 碰撞的风险很高。通过使用
    this
    值作为查找表中的键(以区分
    (5).x
    (3).x
    ),可以降低该值,但仍然无法完全避免
  • 在访问/设置时删除自身的属性非常不直观。避免这样
  • 在原语原型上任意更改访问器属性代价高昂。这是4个性能对比的总和。没有一台发动机能够对此进行优化。而且你似乎经常使用它们
如果您真的需要这个(我仍然不明白您的原因),我会使用一个带有查找表的变体。它应该减少冲突(不确定您的代码如何处理冲突),不会更改它们定义的访问器属性,因此更持久(尽管可能会泄漏):

然而,有一件事你永远无法解决:

与对象不同,基本值不是唯一的;他们没有身份

您将永远无法区分
c.ann
58
,或
循环“
循环“.x
,因此两者都有属性或没有属性。这不是构建API的好前提

因此,我仍然建议使用
Number
String
对象。您不需要对它们进行子类化(如我前面的回答所示),因为您似乎没有(m)个方法,所以您可以轻松地构建它们:

c.ann = new Number(58);
c.ann.blah = 98;
return c;
除了
操作符的
typeof之外,应该没有什么区别。您是否可以添加更多使用默认值的示例

但是,如果chain end对象是一个基本体,我如何在不使用valueOf的情况下使其不同呢


回答这个简单的问题:这家伙是对的,如果不攻击本机原型,就无法在JavaScript中完成。你是对的,黑客很难看:-)

如果没有看到访问器的代码就很难说,但是
get
方法不应该返回一个对象引用(比如
this
)而不是它们的
属性吗?@bfavaretto我添加了一些代码(玩得开心)。问题是,我还想在不调用valueOf的情况下使用该对象。我自己也试过。所以如果我做一个
console.log(g)其中
g=新的MyNumber(10)
它应该返回10,但是如果我执行
g.myFunction()
也可以工作,而不必使用原型编号(在我的例子中,这是一种非常丑陋的方法)。有什么想法吗?
valueOf
的好处是您不需要调用它-它还将用于隐式类型转换:
newmynumber(9)+1==10
问题是如果
组件
MyNumber
的实例
c.ann = new Number(58);
c.ann.blah = 98;
return c;