Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/412.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 可以从函数原型访问私有构造函数范围的变量吗?_Javascript_Constructor_Closures_Private_Prototype Programming - Fatal编程技术网

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

Javascript 可以从函数原型访问私有构造函数范围的变量吗?,javascript,constructor,closures,private,prototype-programming,Javascript,Constructor,Closures,Private,Prototype Programming,根据我对javascript的理解,原型方法无法访问构造函数作用域私有的变量 var Foo = function() { var myprivate = 'I am private'; this.mypublic = 'I am public'; } Foo.prototype = { alertPublic: function() { alert(this.mypublic); } // will work alertPrivate

根据我对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; 

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

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

铬:

仅限关闭-2172ms

原型制作(上方)-822ms

原型制作(标准方式)-751ms

火狐:

仅限闭合-1528ms

原型制作(上方)-971ms

原型制作(标准方式)-752ms


正如您所看到的,该方法几乎和普通的原型设计一样快,而且肯定比只使用普通的闭包来复制实例中的函数要快

我发现肖恩·托曼的回答很有帮助(虽然一开始很难理解)

看起来公共setter不能接受
privateVar
的值,所以我做了一些调整:

功能中更改
更新

update: function(st, newVal) {
     st['privateVar'] = newVal;
}
proto
中更改
Update

Update: function(newVal) {
     this.caller('update', newVal); 
}
更改提升机构

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中,可以使用正常的原型方法(并且没有集中的、泄漏的、字段存储)实现每个实例的私有状态

查看我写的关于该技术的文章:


或者直接转到中的源代码:。

您确定性能差异确实是个问题吗?@Qerub,可能是。通常的规则是,如果需要创建大量实例,最好使用原型,因为每个实例都会引用原型中只创建一次的函数。我已经对它进行了基准测试,使用原型有显著的性能优势。想要启用继承还有一个明显的原因。在下面文章的末尾,有一个链接指向创建受保护的成员,而无需在每次创建实例时创建大量闭包: