简体   繁体   English

在JavaScript对象中实现setter和getter

[英]Implementing setter and getter in JavaScript object

I want to implement setter and getter on local javascript variable. 我想在本地javascript变量上实现setter和getter。 Here is an example function: 这是一个示例函数:

function someThing() {
   var someLocalvariable = '';
}

// with this function I want to 
// return value of someLocalvariable
// also if it is possible to implement
// setter in this way. 
someThing.prototype.getLocalVar = function() {

}

I want variable to be 'realy' private. 我想变量'真的'私有。 I don't wont to use something like this: someThing.prototype.someLocalvariable = 我不会使用这样的东西:someThing.prototype.someLocalvariable =

or 要么

function someThing() {
   this.someLocalvariable = '';
}

or attaching function inside someThing() like this: 或者在someThing()中附加函数,如下所示:

function someThing() {
      var someLocalvariable = '';
   this.getLocalvariable = function() {
      return someLocalvariable;
   }
}

I would be very grateful for any guidance and assistance. 我将非常感谢任何指导和帮助。

Your last example of what you don't want to do won't work (it has syntax errors), (it's been fixed) but I think you may have meant the usual way of doing this, which is to make the getter and setter closures within the constructor function (below). 你不想做的最后一个例子是不行的(它有语法错误), (它已被修复)但我认为你可能意味着这样做的常用方法,即制作getter和setter构造函数中的闭包(如下)。

Unfortunately, if you want truly private variables, this is just about your only option. 不幸的是,如果你想要真正的私有变量,这只是你唯一的选择。 There is no other way to get truly private, instance-specific variables. 没有其他方法可以获得真正私有的, 特定于实例的变量。 However, see "hack" below. 但是,请参阅下面的“黑客”。

Here's the correct version of the usual way of doing this (which I think you said you don't want, but for completeness): 这是通常的做法的正确版本(我认为你说你不想要,但为了完整性):

function SomeThing() {
    var privateVar;

    this.setPrivateVar = function(val) {
        privateVar = val;
    };
    this.getPrivateVar = function() {
        return privateVar;
    };
}

// use:
var t = new Something();
t.setPrivateVar("foo");
console.log(t.getPrivateVar()); // "foo"

Like most, I first read of this pattern on Douglas Crockford's site . 像大多数人一样,我首先在Douglas Crockford的网站上阅读过这种模式。

This option does carry a downside: Every instance created via the SomeThing constructor function gets its own two functions. 这个选项确实有缺点:通过SomeThing构造函数创建的每个实例都有自己的两个函数。 They cannot be shared between instances. 它们不能在实例之间共享。 So if there are going to be hundreds or thousands of SomeThing instances in your app, that's something to be considered from a memory perspective. 因此,如果您的应用程序SomeThing有数百或数千个SomeThing实例,那么从内存角度考虑这一点。 If there are going to be a couple of hundred or fewer, it probably doesn't matter. 如果有几百个或更少,那可能无关紧要。 (Those numbers are pulled out of a hat and you should not trust them, you'll have to review your code's memory use when/if there's some kind of issue; but you get the idea.) (这些数字是从帽子中拉出来的,你不应该相信它们,当你出现某种问题时,你必须检查代码的内存使用情况;但是你明白了。)

The hack: If your instances will already have some kind of unique identifier on them as public data (or you're willing to add one, again it will be public), and if you're willing to add a fair bit of complication into the use of the instances, you can have a private cache that holds the data for all of your instances that only your code can access, and key into that cache via the unique identifier of the object. 黑客攻击:如果你的实例已经有一些独特的标识符作为公共数据(或者你愿意添加一个,那么它将是公开的),如果你愿意添加一些复杂的在使用实例时,您可以拥有一个私有缓存,用于保存只有您的代码可以访问的所有实例的数据,并通过对象的唯一标识符键入该缓存。 Like this (in this example, I'm allocating the id values, but you can use existing unique IDs if you have them): 像这样(在这个例子中,我正在分配id值,但是你可以使用现有的唯一ID):

var SomeThing = (function() {
    var cache = {}, idAllocator = 0;

    function SomeThing() {
        this.id = ++idAllocator; // The unique identifier, can be a string if desired
        cache[this.id] = {};
    }
    SomeThing.prototype.getPrivateVar = function() {
        var data = cache[this.id];
        return data && data.privateVar;
    };
    SomeThing.prototype.setPrivateVar = function(value) {
        cache[this.id].privateVar = value;
    };
    SomeThing.prototype.destroy = function() {
        delete cache[this.id];
    };

    return SomeThing;
})();

Here's how that works: All of the functions are closures over the cache local variable in the outer scoping function. 这是如何工作的:所有函数都是外部作用域函数中cache局部变量的闭包。 We index into that using the unique ID of the object, which gives us an object on which we put our private data members. 我们使用对象的唯一ID对其进行索引,这为我们提供了一个对象,我们将其放在私有数据成员上。 When the code using the instance is done using it, that code must call destroy (which is a major downside to this pattern) so we remove the private data object from cache by deleting the property for our id . 当使用实例的代码完成后,该代码必须调用destroy (这是此模式的主要缺点),因此我们通过删除id的属性从cache删除私有数据对象。

Caveats and costs: 警告和费用:

  • You still have a public piece of data that is the key to your private data ( id in the above) 您仍然拥有公共数据,这是您的私人数据的关键(上面的id
  • Users of the instances created by SomeThing must call destroy on those instances when they're done with them. SomeThing创建的实例的用户必须在完成这些实例后调用destroy This is anathema to the way JavaScript's garbage handling works, but it's a requirement of the pattern above because otherwise you end up with cruft building up in the cache object. 这是JavaScript的垃圾处理工作方式的诅咒,但它是上述模式的要求,否则你最终会在cache对象中建立起来。
  • (I wouldn't worry about this one) Eventually, if you're using the automatic id values above, you'll run out of them, if your app creates and destroys a lot of these instances. (我不担心这个)最终,如果你使用上面的自动id值,如果你的应用创建并销毁了很多这些实例,你将会用完它们。 But JavaScript numbers go very high up indeed, and if that's an issue just find a different way to allocate IDs rather than the simplistic always-increasing system above. 但是JavaScript的数字确实非常高,如果这是一个问题,只需找到一种不同的方式来分配ID,而不是上面简单的常设增长系统。

I haven't had to use the pattern above in my work yet, but I expect there are use-cases for it involving thousands of SomeThing instances and thus the desire not to have per-instance functions. 我还没有在我的工作中使用上面的模式,但我希望它有一些用例,涉及数千个SomeThing实例,因此不希望有每个实例的功能。


Side note: In the above, I changed someThing to SomeThing . 附注:在上面,我将someThing更改为SomeThing In JavaScript, the standard practice is for the names of normal functions to start with a lower-case letter, and for the names of constructor functions (ones you use with new ) to start with a capital letter. 在JavaScript中,标准做法是将普通函数的名称以小写字母开头,并将构造函数的名称(与new一起使用的名称)以大写字母开头。 Since SomeThing is meant to be used with new , I capped it. 由于SomeThing是用于new ,我限制了它。 This is only convention, but it's an overwhelmingly popular one and, of course, it's used within the language definition itself ( Date is a constructor, setHours is a function). 这只是惯例,但它是一个非常受欢迎的惯例,当然,它在语言定义本身中使用( Date是构造函数, setHours是函数)。

Use Object.defineProperty() in the function constructor in order to define your getter and setter more info here .. 在函数构造函数中使用Object.defineProperty(),以便在此处定义getter和setter 更多信息

To make truly private (not visible to the outside) some values use a Closure, more info can be found here . 要使真正的私有(对外部不可见),某些值使用Closure,可以在此处找到更多信息。

In the following example we define a getter and setter for property temperature , where the inner "private" value is stored in a variable var temperature . 在下面的示例中,我们为属性temperature定义了一个getter和setter,其中内部“private”值存储在变量var temperature

var temperature will never be visible/accessibly from the outside of Archiver() has it is a Closure. var temperature永远不会从Archiver()的外部可见/可访问它是一个闭包。

Please note that this pattern works on ES5 as Object.defineProperty() it is not supported on ES3. 请注意,此模式在ES5上作为Object.defineProperty()在ES3上不受支持。

function Archiver() {
    var temperature = null;
    var archive = [];

    Object.defineProperty(this, 'temperature', {
        get: function () {
            console.log('get!');
            return temperature;
        },
        set: function (value) {
            temperature = value;
            archive.push({ val: temperature });
        }
    });

    this.getArchive = function () {
        return archive;
    };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

Something like this: 像这样的东西:

function Field(val){
    var value = val;

    this.getValue = function(){
        return value;
    };

    this.setValue = function(val){
        value = val;
    };
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()

Check ref: http://ejohn.org/blog/javascript-getters-and-setters/ 检查参考: http//ejohn.org/blog/javascript-getters-and-setters/

道格拉斯Crockford的写了对在JavaScript中实现私有成员

That's not possible. 那是不可能的。 If you have a local variable in someThing(), the function you attach to the prototype can't read its value (it's private, remember?). 如果你在someThing()中有一个局部变量,你附加到原型的函数就无法读取它的值(它是私有的,还记得吗?)。 Your last example is the normal solution to this problem, why isn't this good enough for you? 你的最后一个例子是这个问题的正常解决方案,为什么这对你来说不够好?

Try these two ways to achieve setter and getter 尝试这两种方法来实现setter和getter

var address = {

            street : "No street",
            city : "No city",
            state : "No state",     

            get getAddress()
            {
                return (this.street+","+this.city+","+this.state);
            },

            set setAddress(theAddress)
            {
                var part = theAddress.toString().split(", ");
                this.street = part[0] || "";
                this.city = part[1] || "";
                this.state = part[2] || "";
            }
        };


        address.setAddress = "27 Sus Road, Pune, MH";
        console.log(address.getAddress);


        //Other setter and getter

        function Square(side)
        {
            this._side = side;


        };

        Square.prototype = {

            set setSide(side){ 
                this._side = side;
            },

            get getSide(){ 
                return this._side;
            },

            get getArea(){ 
                return (this._side * this._side);
            }               
        };


        var mySquare = new Square(10);

        mySquare.setSide = 15;

        console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);

First method 第一种方法

var address = {

            street : "No street",
            city : "No city",
            state : "No state",     

            get getAddress()
            {
                return (this.street+","+this.city+","+this.state);
            },

            set setAddress(theAddress)
            {
                var part = theAddress.toString().split(", ");
                this.street = part[0] || "";
                this.city = part[1] || "";
                this.state = part[2] || "";
            }
        };


        address.setAddress = "27 Sus Road, Pune, MH";
        console.log(address.getAddress);

Second method 第二种方法

function Square(side)
        {
            this._side = side;


        };

        Square.prototype = {

            set setSide(side){ 
                this._side = side;
            },

            get getSide(){ 
                return this._side;
            },

            get getArea(){ 
                return (this._side * this._side);
            }               
        };


        var mySquare = new Square(10);

        mySquare.setSide = 15;

        console.log("Area of square is "+mySquare.getArea+" with side "+mySquare.getSide);

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

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