簡體   English   中英

在JavaScript對象中實現setter和getter

[英]Implementing setter and getter in JavaScript object

我想在本地javascript變量上實現setter和getter。 這是一個示例函數:

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() {

}

我想變量'真的'私有。 我不會使用這樣的東西:someThing.prototype.someLocalvariable =

要么

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

或者在someThing()中附加函數,如下所示:

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

我將非常感謝任何指導和幫助。

你不想做的最后一個例子是不行的(它有語法錯誤), (它已被修復)但我認為你可能意味着這樣做的常用方法,即制作getter和setter構造函數中的閉包(如下)。

不幸的是,如果你想要真正的私有變量,這只是你唯一的選擇。 沒有其他方法可以獲得真正私有的, 特定於實例的變量。 但是,請參閱下面的“黑客”。

這是通常的做法的正確版本(我認為你說你不想要,但為了完整性):

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"

像大多數人一樣,我首先在Douglas Crockford的網站上閱讀過這種模式。

這個選項確實有缺點:通過SomeThing構造函數創建的每個實例都有自己的兩個函數。 它們不能在實例之間共享。 因此,如果您的應用程序SomeThing有數百或數千個SomeThing實例,那么從內存角度考慮這一點。 如果有幾百個或更少,那可能無關緊要。 (這些數字是從帽子中拉出來的,你不應該相信它們,當你出現某種問題時,你必須檢查代碼的內存使用情況;但是你明白了。)

黑客攻擊:如果你的實例已經有一些獨特的標識符作為公共數據(或者你願意添加一個,那么它將是公開的),如果你願意添加一些復雜的在使用實例時,您可以擁有一個私有緩存,用於保存只有您的代碼可以訪問的所有實例的數據,並通過對象的唯一標識符鍵入該緩存。 像這樣(在這個例子中,我正在分配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;
})();

這是如何工作的:所有函數都是外部作用域函數中cache局部變量的閉包。 我們使用對象的唯一ID對其進行索引,這為我們提供了一個對象,我們將其放在私有數據成員上。 當使用實例的代碼完成后,該代碼必須調用destroy (這是此模式的主要缺點),因此我們通過刪除id的屬性從cache刪除私有數據對象。

警告和費用:

  • 您仍然擁有公共數據,這是您的私人數據的關鍵(上面的id
  • SomeThing創建的實例的用戶必須在完成這些實例后調用destroy 這是JavaScript的垃圾處理工作方式的詛咒,但它是上述模式的要求,否則你最終會在cache對象中建立起來。
  • (我不擔心這個)最終,如果你使用上面的自動id值,如果你的應用創建並銷毀了很多這些實例,你將會用完它們。 但是JavaScript的數字確實非常高,如果這是一個問題,只需找到一種不同的方式來分配ID,而不是上面簡單的常設增長系統。

我還沒有在我的工作中使用上面的模式,但我希望它有一些用例,涉及數千個SomeThing實例,因此不希望有每個實例的功能。


附注:在上面,我將someThing更改為SomeThing 在JavaScript中,標准做法是將普通函數的名稱以小寫字母開頭,並將構造函數的名稱(與new一起使用的名稱)以大寫字母開頭。 由於SomeThing是用於new ,我限制了它。 這只是慣例,但它是一個非常受歡迎的慣例,當然,它在語言定義本身中使用( Date是構造函數, setHours是函數)。

在函數構造函數中使用Object.defineProperty(),以便在此處定義getter和setter 更多信息

要使真正的私有(對外部不可見),某些值使用Closure,可以在此處找到更多信息。

在下面的示例中,我們為屬性temperature定義了一個getter和setter,其中內部“private”值存儲在變量var temperature

var temperature永遠不會從Archiver()的外部可見/可訪問它是一個閉包。

請注意,此模式在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 }]

像這樣的東西:

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()

檢查參考: http//ejohn.org/blog/javascript-getters-and-setters/

道格拉斯Crockford的寫了對在JavaScript中實現私有成員

那是不可能的。 如果你在someThing()中有一個局部變量,你附加到原型的函數就無法讀取它的值(它是私有的,還記得嗎?)。 你的最后一個例子是這個問題的正常解決方案,為什么這對你來說不夠好?

嘗試這兩種方法來實現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);

第一種方法

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);

第二種方法

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