简体   繁体   English

JavaScript中的defineProperty原型

[英]Prototype of defineProperty in JavaScript

In JavaScript you can define getters and setters by using Object.defineProperty() . 在JavaScript中,您可以使用Object.defineProperty()定义getter和setter。 I am wondering if it is possible to extend or use the prototype of this to extend its functionality. 我想知道是否可以扩展或使用它的原型来扩展其功能。 Here is an example: 这是一个例子:

I start off a variable called color: 我开始一个名为color的变量:

Object.defineProperty(window, 'color', {
    get: function() {
        return [_color.red,_color.green,_color.blue,_color.alpha];
    },
    set: function(val) {
        _color.red = val[0];
        _color.green = val[1];
        _color.blue = val[2];
        _color.alpha = val[3];
    }
});

This allows for me to both set and get the color by passing rgba arrays to and from the variables. 这允许我通过将rgba数组传入和传出变量来设置和获取颜色。 Here is how I would use this: 以下是我将如何使用它:

color = [0,127,255,255];
alert(color);
//alerts [0,127,255,255]

Now I also want to be able to edit these variables through accessing each variable individually. 现在我也想通过单独访问每个变量来编辑这些变量。

color.r = 255;
alert(color);
//alerts [255,127,255,255]

I am at an impasse at this moment because I don't know what I can do to create this. 我此刻陷入僵局,因为我不知道我能做些什么来创造这个。 I would think either using color.prototype.r or something similar would work, but I can't get it to. 我会认为使用color.prototype.r或类似的东西可以工作,但我不能得到它。 Is it possible to do something like this? 可以这样做吗?

You have to create an interim object extended from array to do it specifically. 您必须创建从数组扩展的临时对象才能专门执行此操作。

Here you go: 干得好:

var __color = {red:0,green:0,blue:0,alpha:1};
function createGetMethod(prop){
    return function(){return __color[prop]};
}
function createSetMethod(prop){
    return function(val){__color[prop]=val};
}
function createDescritorProperty(prop){
    return {
        get: createGetMethod(prop),
        set: createSetMethod(prop)
    }
}

var _color_descriptor = {
    red:createDescritorProperty('red'),
    green:createDescritorProperty('green'),
    blue:createDescritorProperty('blue'),
    alpha:createDescritorProperty('alpha'),
    length:{
        value:4,
        writable:false
    }
}
//setup numbered values
_color_descriptor[0]=createDescritorProperty('red');
_color_descriptor[1]=createDescritorProperty('green');
_color_descriptor[2]=createDescritorProperty('blue');
_color_descriptor[3]=createDescritorProperty('alpha');

var _color = Object.create(Array.prototype, _color_descriptor); //extends array


Object.defineProperty(window, 'color', {
    get: function() {
        return _color;
    },
    set: function(val) {
        _color.red = val[0];
        _color.green = val[1];
        _color.blue = val[2];
        _color.alpha = val[3];
    }
});

window.color = [255,255,255,0];
alert(window.color);
window.color.red=10;
alert(window.color);

Hope it works! 希望它有效! :D :d

The prototype is only for object instances, which you don't have unfortunately. prototype仅适用于对象实例,遗憾的是您没有。 If you had a constructor like this: 如果你有这样的构造函数:

function Color(r,g,b,a){
    for (var i=0; i<4; i++)
        this[i] = arguments[i];
}

it would work with 它会合作

Object.defineProperty(Color.prototype, "r", {
    get: function() { return this[0]; } // setter analogous
};

However, these Color instances are no arrays. 但是,这些Color实例不是数组。 You could give them a length property and let them inherit from Array.prototype , but they won't really be arrays. 你可以给它们一个length属性,让它们从Array.prototype继承,但它们实际上不是数组。 @Trouts solution is a bit like that, and I'd say it is okay because colors really are no arrays (you can't push a fifth value etc). @Trouts解决方案有点像这样,我说它没关系,因为颜色确实没有数组(你不能推第五个值等)。

The alternative were to extend the array which you return from the color getter with those properties. 另一种方法是使用这些属性扩展从color吸气剂返回的数组。 You could do that every time someone accesses the value (like you currently do, you create a new array in the getter) but I'd suggest that you should return the same instance, propagating any changes. 每次有人访问该值时你都可以这样做(就像你现在一样,你在getter中创建一个新数组)但是我建议你应该返回相同的实例,传播任何更改。 Your current property definition is like "setColor" and "getCurrentColor". 您当前的属性定义类似于“setColor”和“getCurrentColor”。

So, actually you want two separate things: Color objects that have more than one property per value (ie 0 == r ); 所以,实际上你需要两个独立的东西:每个值具有多个属性的Color对象(即0 == r ); and a setter for your global color variable which accepts arrays and sets the single values on the respective object. 和一个全局color变量的setter,它接受数组并在相应的对象上设置单个值。

// version with private values
function Color(r, g, b, a) {
    // r, g, b and a are private-scoped variables
    var desc = {
        "0": {
             get:function(){return r;},
             set:function(val){ if(+val<256&&val>=0) r=+val;}
        },
        …
    }
    // use those property descriptors multiple times
    desc.r = desc[0];
    …
    Object.defineProperties(this, desc);
}
// or version with public and unlimited read/write access to the properties:
function Color(r,g,b,a){
    for (var i=0; i<4; i++)
        this[i] = arguments[i];
}
Object.defineProperties(Color.prototype, {
    r: { get:function(){return this[0];}, set:function(r){this[0]=r;} },
    …
}

// and for both versions we can add array-like methods on the prototype
var cprot = Color.prototype, aprot = Array.prototype;
Object.defineProperty(cprot, "length", {value:4});
// we only need accessor functions here, nothing which changes the array [length]
cprot.map = aprot.map;
cprot.reduce = aprot.reduce;
cprot.slice = aprot.slice;
cprot.join = aprot.join;

// you might want to add other utilities like
cprot.toString = function() {
    return "rgba("+this.join(",")+")"; // using array method from above
};
cprot.getHex = function() {
    function hex(n) { return (n<16?"0":"") + n.toString(16); }
    return "#"+this.slice(0, 3).map(hex).join("");
};

And then, your color value setter: 然后,你的颜色值设定器:

function defineColorProperty(obj, prop, color) {
    // again, color is private-scoped
    if (!color || !(color instanceof Color)) color = new Color(0, 0, 0, 0);
    Object.defineProperty(obj, prop, {
        get: function(){ return color; }, // a cool Color instance!
        set: function(val) {
            if (Object(val)!==val) return; // accept objects (including arrays)
            for (var i=0; i<4 && i<val.length; i++)
                color[i] = val[i];
        },
        enumberable: true
    });
    return color;
}

// usage:
> defineColorProperty(window, "color");
Object[Color]: 0, 0, 0, 0
> color = [255, 0, 120, 1];
> color.r = 42;
> color[0]
42
> color = [0, 0];
> ""+color
"rgba(0,0,120,1)"
> var x = color;
> x.b = 255;
> x.getHex()
"#0000FF"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM