可以从函数原型访问私有构造函数范围的变量吗?

发布于 2024-12-10 02:36:12 字数 1016 浏览 0 评论 0原文

根据我对 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 的新副本,或者是否有任何潜在的性能优势。目的是获得类似于原型设计的功能(因为它节省内存),同时仍然能够访问私有变量。

谢谢。

Based on my understanding of javascript, prototype methods cannot access variables that are private to the scope of the constructor,

 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
 }

It makes perfect sense, but is there any way around this that is safe and good practice? Since using prototypes provides a performance benefit in that the member functions are allocated only once, I'd like to achieve a similar functionality while still being able to get to my private variables. I don't think it will work by using a prototype, but is there another pattern, such as a factory method or a closure approach? Something like,

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

I'm not sure whether a new copy of _alertPrivate is created each time I create a new Foo or if there is any potential performance benefit. The intention is to get a functionality similar to prototyping (inasmuch as it saves memory) while still being able to access private variables.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

著墨染雨君画夕 2024-12-17 02:36:12

我想出了以下模式来解决这个问题,至少现在是这样。我需要的是一个特权设置器,以便可以从某些原型函数内部更改私有变量,但不能从其他任何地方更改:

 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; 

 })(); 

基本上,指向对象内部状态的指针通过简单访问器 function() 上的闭包提升到其原型返回状态; }。在任何给定实例上使用“调用者”函数允许您调用仅创建一次但仍然可以引用该实例中保存的私有状态的函数。同样重要的是要注意,原型之外的任何函数都无法访问特权访问器,因为“调用者”只接受引用回范围内的预定义函数的键。

以下是此方法的一些基准,以了解它与纯原型制作的比较。这些数字表示在循环中创建 80,000 个对象实例(请注意,用于基准测试的对象比上面的对象更复杂,这只是为了简化目的):

CHROME:

仅闭包 - 2172ms

原型设计(上述方式) - 822ms

原型设计(标准方式) - 751ms

FIREFOX:

仅关闭 - 1528ms

原型设计(上述方式) - 971ms

原型设计(标准方式)- 752ms

如您所见,该方法几乎与正常原型设计一样快,并且绝对比仅使用复制函数和实例的正常闭包更快。

I have come up with the following pattern to address this issue, atleast for now. What I needed was a privileged setter so that a private variable could be changed from inside certain prototype functions but not from anywhere else:

 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; 

 })(); 

Basically a pointer to the objects internal state is hoisted to its prototype via a closure over a simple accessor function() { return state; }. Using the 'caller' function on any given instance allows you to call functions which are created only once but can still refer to the private state held in that instance. Its also important to note that no functions outside of the prototype could ever access the privileged accessor, since the 'caller' only accepts a key that refers back to the predefined functions which are in scope.

Here are some benchmarks of this method to see how it compares to pure prototyping. These figures represent creating 80,000 instances of the object in a loop (note the object used for benchmarking is more complex than the one above, which was just for simplification purposes):

CHROME:

Closure Only - 2172ms

Prototyping (above way) - 822ms

Prototyping (std way) - 751ms

FIREFOX:

Closure Only - 1528ms

Prototyping (above way) - 971ms

Prototyping (std way) - 752ms

As you can see the method is almost as fast as normal prototyping, and definitely faster than just using a normal closure that copies functions along with the instance.

不再让梦枯萎 2024-12-17 02:36:12

我发现 Sean Thoman 的回答非常有帮助(尽管一开始很难理解)。

看起来公共 setter 无法接受 privateVar 的值,因此我做了一些调整:

更改 functions 中的 update

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

Change < proto 中的 code>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)); 
    }
}

I found Sean Thoman's answer very helpful (though hard to understand at first).

It didn't look like the public setter could accept a value for privateVar so I made a few tweaks:

Change update in functions:

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

Change Update in the proto:

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

Change 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)); 
    }
}
祁梦 2024-12-17 02:36:12

您所要求的是可能的,尽管性能(速度或内存)和功能之间总是存在权衡。

在 JavaScript 中,可以使用普通的原型方法(并且没有集中的、泄漏的、字段存储)来实现私有的每个实例状态。

查看我写的有关该技术的文章: http://www.codeproject.com/KB/ ajax/SafeFactoryPattern.aspx

或者直接进入源代码:https://github.com/dcleao/private-state

What you are asking for is possible, although there will always be a tradeoff between performance (in speed or memory) and functionality.

In JavaScript, it is possible to achieve private per-instance state, with normal prototype methods (and with no centralized, leaking, field storage).

Check the article I wrote about the technique: http://www.codeproject.com/KB/ajax/SafeFactoryPattern.aspx

Or go directly to the source code in: https://github.com/dcleao/private-state.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文