簡體   English   中英

可以從函數原型訪問私有構造函數范圍的變量嗎?

[英]Possible to access private constructor-scoped variables from a functions prototype?

根據我對javascript的理解,原型方法無法訪問構造函數范圍內的私有變量,

 var Foo = function() {
      var myprivate = 'I am private';    
      this.mypublic = 'I am public';
 }

 Foo.prototype = {
     alertPublic: function() { alert(this.mypublic); } // will work
     alertPrivate: function() { alert(myprivate); } // won't work
 }

這很有道理,但有什么方法可以安全和良好的做法嗎? 由於使用原型提供了性能優勢,因為成員函數只分配了一次,我想實現類似的功能,同時仍然可以訪問我的私有變量。 我不認為它會使用原型,但是有另一種模式,例如工廠方法或閉包方法嗎? 就像是,

var fooFactory = function() {
    var _alertPrivate = function(p) { alert(p); } // bulk of the logic goes here
    return function(args) {
         var foo = {}; 
         var myprivate = args.someVar; 
         foo.mypublic = args.someOtherVar; 
         foo.alertPrivate = function() { _alertPrivate(myprivate); };
         return foo; 
    }; 
}

var makeFoo = new fooFactory();
var foo = makeFoo(args); 

我不確定每次創建新的Foo時是否創建了_alertPrivate的新副本,或者是否有任何潛在的性能優勢。 目的是獲得類似於原型的功能(因為它節省了內存),同時仍然能夠訪問私有變量。

謝謝。

我提出了以下模式來解決這個問題,至少目前。 我需要的是一個特權設置器,以便私有變量可以從某些原型函數內部更改,但不能從其他任何地方更改:

 var Foo = (function() {

    // the bulk of the objects behavior goes here and is created once 
    var functions = {
        update: function(a) {
             a['privateVar'] = "Private variable set from the prototype";
        }
    }; 

    // the objects prototype, also created once
    var proto = {
        Update: function() {
             this.caller('update'); 
        }
    };

    // special function to get private vars into scope
    var hoist = function(accessor) {
        return function(key) {
             return functions[key](accessor()); 
        }
    }

    // the constructor itself
    var foo = function foo() {
        var state = {
            privateVar: "Private variable set in constructor",
            // put more private vars here
        }
        this.caller = hoist(function(){
            return state;
        }); 
    }

    // assign the prototype
    foo.prototype = proto;

    // return the constructor
    return foo; 

 })(); 

基本上,一個指向對象內部狀態的指針通過一個簡單的訪問函數()返回狀態被提升到它的原型(返回狀態; }。 在任何給定實例上使用“調用者”函數允許您調用僅創建一次但仍可引用該實例中保存的私有狀態的函數。 同樣重要的是要注意原型之外的任何函數都不能訪問特權訪問器,因為“調用者”只接受一個引用范圍內預定義函數的鍵。

以下是此方法的一些基准,以了解它與純原型的比較。 這些圖表示在循環中創建對象的80,000個實例(請注意,用於基准測試的對象比上面的對象更復雜,這僅用於簡化目的):

鉻:

僅關閉 - 2172ms

原型設計(以上方式) - 822ms

原型設計(標准方式) - 751ms

FIREFOX:

僅關閉 - 1528ms

原型設計(以上方式) - 971ms

原型設計(標准方式) - 752ms

正如您所看到的,該方法幾乎與正常原型一樣快,並且肯定比僅使用將函數與實例一起復制的常規閉包更快。

我發現Sean Thoman的回答非常有用(雖然起初很難理解)。

它看起來不像公共setter可以接受privateVar的值,所以我做了一些調整:

更改functions update

update: function(st, newVal) {
     st['privateVar'] = newVal;
}

更改proto Update

Update: function(newVal) {
     this.caller('update', newVal); 
}

更換hoist

var hoist = function(accessor) {
    return function(key) {
        // we can't slice arguments directly because it's not a real array
        var args_tail = Array.prototype.slice.call(arguments, 1);
        return functions[key].apply(functions[key], [accessor()].concat(args_tail)); 
    }
}

您要求的是可能的,盡管在性能(速度或內存)和功能之間總會存在權衡。

在JavaScript中, 可以使用普通的原型方法(並且沒有集中的,泄漏的,字段存儲)來實現私有的每個實例狀態。

查看我寫的關於該技術的文章: http//www.codeproject.com/KB/ajax/SafeFactoryPattern.aspx

或者直接訪問源代碼: https//github.com/dcleao/private-state

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM