从原型定义的函数访问私有成员变量
有没有办法让“私有”变量(在构造函数中定义的),可用于原型定义的方法?
TestClass = function(){ var privateField = "hello"; this.nonProtoHello = function(){alert(privateField)}; }; TestClass.prototype.prototypeHello = function(){alert(privateField)};
这工作:
t.nonProtoHello()
但是这不是:
t.prototypeHello()
我习惯于在构造函数中定义我的方法,但由于几个原因,我正在远离它。
不,没有办法做到这一点。 这基本上是相反的范围。
在构造函数中定义的方法可以访问私有变量,因为所有的函数都可以访问它们被定义的范围。
定义在原型上的方法没有在构造函数的范围内定义,并且不能访问构造函数的局部变量。
您仍然可以拥有私有变量,但是如果您希望在原型上定义的方法有权访问它们,则应该在this
对象上定义getter和setter,这些原型方法(以及其他所有方法) 将有权访问this
getter和setter。 例如:
function Person(name, secret) { // public this.name = name; // private var secret = secret; // public methods have access to private members this.setSecret = function(s) { secret = s; } this.getSecret = function() { return secret; } } // Must use getters/setters Person.prototype.spillSecret = function() { alert(this.getSecret()); };
更新:有了ES6,还有更好的方法:
长话短说,你可以使用新的Symbol
来创建私人领域。
这里有一个很好的描述: https : //curiosity-driven.org/private-properties-in-javascript
例:
var Person = (function() { // Only Person can access nameSymbol var nameSymbol = Symbol('name'); function Person(name) { this[nameSymbol] = name; } Person.prototype.getName = function() { return this[nameSymbol]; }; return Person; }());
对于所有使用ES5的现代浏览器:
你只能使用闭包
构建对象最简单的方法是完全避免原型继承。 只需在闭包中定义私有变量和公共函数,所有公共方法都可以私有访问变量。
或者你可以使用原型
在JavaScript中,原型继承主要是一种优化 。 它允许多个实例共享原型方法,而不是每个实例都有自己的方法。
缺点是this
是每次调用原型函数时唯一不同的东西。
因此,任何私人领域都必须通过this
来获得,这意味着他们将会被公开。 所以我们只是坚持为_private
字段命名约定。
不要打扰与原型混合关闭
我想你不应该把闭包变量和原型方法混合在一起。 你应该使用一个或另一个。
当您使用闭包访问私有变量时,原型方法不能访问该变量。 所以,你必须把闭包暴露在this
,这意味着你公开地以这种或那种方式公开它。 这种方法几乎没有什么收获。
我该选择哪一个?
对于非常简单的对象,只需使用带有闭包的普通对象即可。
如果你需要原型继承 – 继承,性能等 – 然后坚持“_private”命名约定,不要打扰关闭。
我不明白为什么JS开发人员试图让这个领域变得真正的私人化。
当我读到这些,听起来像是一个艰难的挑战,所以我决定找出一个办法。 我想到的是CRAAAAZY,但它完全有效。
首先,我尝试在直接函数中定义这个类,这样你就可以访问该函数的一些私有属性。 这个工作,并允许您获得一些私人数据,但是,如果您尝试设置私人数据,你很快就会发现,所有的对象将共享相同的价值。
var SharedPrivateClass = (function(){ // use immediate function // our private data var private = "Default"; // create the constructor function SharedPrivateClass () {} // add to the prototype SharedPrivateClass.prototype.getPrivate = function () { // It has access to private vars from the immediate function! return private; } SharedPrivateClass.prototype.setPrivate = function (value) { private = value; } return SharedPrivateClass; })(); var a = new SharedPrivateClass(); console.log("a:", a.getPrivate()); // "a: Default" var b = new SharedPrivateClass(); console.log("b:", b.getPrivate()); // "b: Default" a.setPrivate("foo"); // a Sets private to 'foo' console.log("a:", a.getPrivate()); // "a: foo" console.log("b:", b.getPrivate()); // oh no, b.getPrivate() is 'foo'! console.log(a.hasOwnProperty("getPrivate")); // false. belongs to the prototype console.log(a.private); // undefined
有很多情况下,这将是足够的,如果你想有像事件名称的常量值,实例之间共享。 但实质上,它们就像私有静态变量一样。
如果您绝对需要从原型中定义的方法中访问私有名称空间中的变量,则可以尝试此模式。
var PrivateNamespaceClass = (function(){ // immediate function var instance = 0, // counts the number of instances defaultName = "Default Name", p = []; // an array of private objects // careate the constructor function PrivateNamespaceClass () { // Increment the instance count and save it to the instance. // This will become your key to your private space. this.i = instance++; // Create a new object in the private space. p[this.i] = {}; // Define properties or methods in the private space. p[this.i].name = defaultName; console.log("New instance " + this.i); } PrivateNamespaceClass.prototype.getPrivateName = function () { // It has access to the private space and it's children! return p[this.i].name; } PrivateNamespaceClass.prototype.setPrivateName = function (value) { // Because you use the instance number assigned to the object (this.i) // as a key, the values set will not change in other instances. p[this.i].name = value; return "Set " + p[this.i].name; } return PrivateNamespaceClass; })(); var a = new PrivateNamespaceClass(); console.log(a.getPrivateName()); // Default Name var b = new PrivateNamespaceClass(); console.log(b.getPrivateName()); // Default Name console.log(a.setPrivateName("A")); console.log(b.setPrivateName("B")); console.log(a.getPrivateName()); // A console.log(b.getPrivateName()); // B console.log(a.privateNamespace); // undefined
我喜欢从这种方式看到错误的人的一些反馈。
请参阅Doug Crockford关于此的页面 。 你必须间接地用可以访问私有变量范围的东西来做。
另一个例子:
Incrementer = function(init) { var counter = init || 0; // "counter" is a private variable this._increment = function() { return counter++; } this._set = function(x) { counter = x; } } Incrementer.prototype.increment = function() { return this._increment(); } Incrementer.prototype.set = function(x) { return this._set(x); }
用例:
js>i = new Incrementer(100); [object Object] js>i.increment() 100 js>i.increment() 101 js>i.increment() 102 js>i.increment() 103 js>i.set(-44) js>i.increment() -44 js>i.increment() -43 js>i.increment() -42
我建议将“构造函数中的原型赋值”描述为Javascript反模式可能是个好主意。 想想看。 这太危险了。
在创建第二个对象(即b)时实际上正在做的是为所有使用该原型的对象重新定义原型函数。 这将有效地重置您的示例中的对象a的值。 如果你想要一个共享变量,并且如果你碰巧在前面创建了所有的对象实例,它就会工作,但感觉风险太大。
我发现了一些最近正在使用的Javascript中的一个错误,这是由于这种反模式。 它试图在正在创建的特定对象上设置一个拖放处理程序,而是对所有实例执行该操作。 不好。
Doug Crockford的解决方案是最好的。
@Kai
这是行不通的。 如果你这样做
var t2 = new TestClass();
那么t2.prototypeHello
将访问t的私人部分。
@AnglesCrimes
示例代码工作正常,但实际上创建了一个由所有实例共享的“静态”私有成员。 这可能不是摩根代码寻找的解决方案。
到目前为止,我还没有找到一个简单而干净的方法来做到这一点,而不引入私人散列和额外的清理功能。 私人成员函数可以在一定程度上被模拟:
(function() { function Foo() { ... } Foo.prototype.bar = function() { privateFoo.call(this, blah); }; function privateFoo(blah) { // scoped to the instance by passing this to call } window.Foo = Foo; }());
是的,这是可能的。 PPF的设计模式正好解决了这个问题。
PPF代表私人原型功能。 基本的PPF解决了这些问题:
- 原型函数可以访问私有实例数据。
- 原型函数可以是私有的。
首先,只是:
- 将所有可以从原型函数访问的私有实例变量放在一个单独的数据容器中
- 将对数据容器的引用作为参数传递给所有原型函数。
就这么简单。 例如:
// Helper class to store private data. function Data() {}; // Object constructor function Point(x, y) { // container for private vars: all private vars go here // we want x, y be changeable via methods only var data = new Data; data.x = x; data.y = y; ... } // Prototype functions now have access to private instance data Point.prototype.getX = function(data) { return data.x; } Point.prototype.getY = function(data) { return data.y; }
…
在这里阅读完整的故事:
PPF设计模式
你可以使用Accessor Verification来实现这个功能:
(function(key, global) { // Creates a private data accessor function. function _(pData) { return function(aKey) { return aKey === key && pData; }; } // Private data accessor verifier. Verifies by making sure that the string // version of the function looks normal and that the toString function hasn't // been modified. NOTE: Verification can be duped if the rogue code replaces // Function.prototype.toString before this closure executes. function $(me) { if(me._ + '' == _asString && me._.toString === _toString) { return me._(key); } } var _asString = _({}) + '', _toString = _.toString; // Creates a Person class. var PersonPrototype = (global.Person = function(firstName, lastName) { this._ = _({ firstName : firstName, lastName : lastName }); }).prototype; PersonPrototype.getName = function() { var pData = $(this); return pData.firstName + ' ' + pData.lastName; }; PersonPrototype.setFirstName = function(firstName) { var pData = $(this); pData.firstName = firstName; return this; }; PersonPrototype.setLastName = function(lastName) { var pData = $(this); pData.lastName = lastName; return this; }; })({}, this); var chris = new Person('Chris', 'West'); alert(chris.setFirstName('Christopher').setLastName('Webber').getName());
这个例子来自我关于Prototypal Functions&Private Data的文章 ,在这里有更详细的解释。
在当前的JavaScript中,我相当确定只有一种方法可以通过原型函数访问私有状态 ,而不需要添加任何公有的东西。 答案是使用“弱映射”模式。
综上所述: Person
类具有单个弱映射,其中键是Person的实例,并且这些值是用于私有存储的纯对象。
这里是一个功能完整的例子:(玩在http://jsfiddle.net/ScottRippey/BLNVr/ )
var Person = (function() { var _ = weakMap(); // Now, _(this) returns an object, used for private storage. var Person = function(first, last) { // Assign private storage: _(this).firstName = first; _(this).lastName = last; } Person.prototype = { fullName: function() { // Retrieve private storage: return _(this).firstName + _(this).lastName; }, firstName: function() { return _(this).firstName; }, destroy: function() { // Free up the private storage: _(this, true); } }; return Person; })(); function weakMap() { var instances=[], values=[]; return function(instance, destroy) { var index = instances.indexOf(instance); if (destroy) { // Delete the private state: instances.splice(index, 1); return values.splice(index, 1)[0]; } else if (index === -1) { // Create the private state: instances.push(instance); values.push({}); return values[values.length - 1]; } else { // Return the private state: return values[index]; } }; }
就像我说的,这是真正实现所有3个部分的唯一方法。
有两个警告,但是。 首先,这会降低性能 – 每次访问私有数据时,都是O(n)
操作,其中n
是实例的数量。 所以如果你有大量的实例,你不会希望这样做。 其次,当你完成一个实例时,你必须调用destroy
; 否则,实例和数据将不会被垃圾收集,并最终导致内存泄漏。
这就是为什么我原来的回答是“你不应该” ,这是我想坚持的。
利用bind
和call
方法有一个更简单的方法。
通过将私有变量设置为对象,可以利用该对象的作用域。
例
function TestClass (value) { // The private value(s) var _private = { value: value }; // `bind` creates a copy of `getValue` when the object is instantiated this.getValue = TestClass.prototype.getValue.bind(_private); // Use `call` in another function if the prototype method will possibly change this.getValueDynamic = function() { return TestClass.prototype.getValue.call(_private); }; }; TestClass.prototype.getValue = function() { return this.value; };
这种方法不是没有缺点。 由于范围上下文被有效地覆盖,所以您不能访问_private
对象之外的内容。 但是,虽然仍然可以访问实例对象的作用域,但并不是不可能的。 您可以传入对象的上下文( this
)作为bind
或call
的第二个参数,以便仍然可以访问原型函数中的公共值。
访问公共价值
function TestClass (value) { var _private = { value: value }; this.message = "Hello, "; this.getMessage = TestClass.prototype.getMessage.bind(_private, this); } TestClass.prototype.getMessage = function(_public) { // Can still access passed in arguments // eg – test.getValues('foo'), 'foo' is the 2nd argument to the method console.log([].slice.call(arguments, 1)); return _public.message + this.value; }; var test = new TestClass("World"); test.getMessage(1, 2, 3); // [1, 2, 3] (console.log) // => "Hello, World" (return value) test.message = "Greetings, "; test.getMessage(); // [] (console.log) // => "Greetings, World" (return value)
尝试一下!
function Potatoe(size) { var _image = new Image(); _image.src = 'potatoe_'+size+'.png'; function getImage() { if (getImage.caller == null || getImage.caller.owner != Potatoe.prototype) throw new Error('This is a private property.'); return _image; } Object.defineProperty(this,'image',{ configurable: false, enumerable: false, get : getImage }); Object.defineProperty(this,'size',{ writable: false, configurable: false, enumerable: true, value : size }); } Potatoe.prototype.draw = function(ctx,x,y) { //ctx.drawImage(this.image,x,y); console.log(this.image); } Potatoe.prototype.draw.owner = Potatoe.prototype; var pot = new Potatoe(32); console.log('Potatoe size: '+pot.size); try { console.log('Potatoe image: '+pot.image); } catch(e) { console.log('Oops: '+e); } pot.draw();
这是我想出来的。
(function () { var staticVar = 0; var yrObj = function () { var private = {"a":1,"b":2}; var MyObj = function () { private.a += staticVar; staticVar++; }; MyObj.prototype = { "test" : function () { console.log(private.a); } }; return new MyObj; }; window.YrObj = yrObj; }()); var obj1 = new YrObj; var obj2 = new YrObj; obj1.test(); // 1 obj2.test(); // 2
这个实现的主要问题是它重新定义了每个实例的原型。
有一个非常简单的方法来做到这一点
function SharedPrivate(){ var private = "secret"; this.constructor.prototype.getP = function(){return private} this.constructor.prototype.setP = function(v){ private = v;} } var o1 = new SharedPrivate(); var o2 = new SharedPrivate(); console.log(o1.getP()); // secret console.log(o2.getP()); // secret o1.setP("Pentax Full Frame K1 is on sale..!"); console.log(o1.getP()); // Pentax Full Frame K1 is on sale..! console.log(o2.getP()); // Pentax Full Frame K1 is on sale..! o2.setP("And it's only for $1,795._"); console.log(o1.getP()); // And it's only for $1,795._
JavaScript原型是黄金。
我迟到了,但我想我可以贡献。 在这里检查一下:
// 1. Create closure var SomeClass = function() { // 2. Create `key` inside a closure var key = {}; // Function to create private storage var private = function() { var obj = {}; // return Function to access private storage using `key` return function(testkey) { if(key === testkey) return obj; // If `key` is wrong, then storage cannot be accessed console.error('Cannot access private properties'); return undefined; }; }; var SomeClass = function() { // 3. Create private storage this._ = private(); // 4. Access private storage using the `key` this._(key).priv_prop = 200; }; SomeClass.prototype.test = function() { console.log(this._(key).priv_prop); // Using property from prototype }; return SomeClass; }(); // Can access private property from within prototype var instance = new SomeClass(); instance.test(); // `200` logged // Cannot access private property from outside of the closure var wrong_key = {}; instance._(wrong_key); // undefined; error logged
我试图找到这个问题的最简单的解决方案,这是我想出的东西,也许这可能是有用的人。 我是新来的JavaScript,所以可能会有一些代码的问题。
// pseudo-class definition scope (function () { // this is used to identify 'friend' functions defined within this scope, // while not being able to forge valid parameter for GetContext() // to gain 'private' access from outside var _scope = new (function () { })(); // ----------------------------------------------------------------- // pseudo-class definition this.Something = function (x) { // 'private' members are wrapped into context object, // it can be also created with a function var _ctx = Object.seal({ // actual private members Name: null, Number: null, Somefunc: function () { console.log('Something(' + this.Name + ').Somefunc(): number = ' + this.Number); } }); // ----------------------------------------------------------------- // function below needs to be defined in every class // to allow limited access from prototype this.GetContext = function (scope) { if (scope !== _scope) throw 'access'; return _ctx; } // ----------------------------------------------------------------- { // initialization code, if any _ctx.Name = (x !== 'undefined') ? x : 'default'; _ctx.Number = 0; Object.freeze(this); } } // ----------------------------------------------------------------- // prototype is defined only once this.Something.prototype = Object.freeze({ // public accessors for 'private' field get Number() { return this.GetContext(_scope).Number; }, set Number(v) { this.GetContext(_scope).Number = v; }, // public function making use of some private fields Test: function () { var _ctx = this.GetContext(_scope); // access 'private' field console.log('Something(' + _ctx.Name + ').Test(): ' + _ctx.Number); // call 'private' func _ctx.Somefunc(); } }); // ----------------------------------------------------------------- // wrap is used to hide _scope value and group definitions }).call(this); function _A(cond) { if (cond !== true) throw new Error('assert failed'); } // ----------------------------------------------------------------- function test_smth() { console.clear(); var smth1 = new Something('first'), smth2 = new Something('second'); //_A(false); _A(smth1.Test === smth2.Test); smth1.Number = 3; smth2.Number = 5; console.log('smth1.Number: ' + smth1.Number + ', smth2.Number: ' + smth2.Number); smth1.Number = 2; smth2.Number = 6; smth1.Test(); smth2.Test(); try { var ctx = smth1.GetContext(); } catch (err) { console.log('error: ' + err); } } test_smth();
我今天面对完全相同的问题,并在阐述Scott Rippey一流的回应之后,提出了一个非常简单的解决方案(恕我直言),它既兼容ES5又高效,它也是名称冲突安全(使用_private似乎不安全) 。
/*jslint white: true, plusplus: true */ /*global console */ var a, TestClass = (function(){ "use strict"; function PrefixedCounter (prefix) { var counter = 0; this.count = function () { return prefix + (++counter); }; } var TestClass = (function(){ var cls, pc = new PrefixedCounter("_TestClass_priv_") , privateField = pc.count() ; cls = function(){ this[privateField] = "hello"; this.nonProtoHello = function(){ console.log(this[privateField]); }; }; cls.prototype.prototypeHello = function(){ console.log(this[privateField]); }; return cls; }()); return TestClass; }()); a = new TestClass(); a.nonProtoHello(); a.prototypeHello();
Tested with ringojs and nodejs. I'm eager to read your opinion.
var getParams = function(_func) { res = _func.toString().split('function (')[1].split(')')[0].split(',') return res } function TestClass(){ var private = {hidden: 'secret'} //clever magic accessor thing goes here if ( !(this instanceof arguments.callee) ) { for (var key in arguments) { if (typeof arguments[key] == 'function') { var keys = getParams(arguments[key]) var params = [] for (var i = 0; i <= keys.length; i++) { if (private[keys[i]] != undefined) { params.push(private[keys[i]]) } } arguments[key].apply(null,params) } } } } TestClass.prototype.test = function(){ var _hidden; //variable I want to get TestClass(function(hidden) {_hidden = hidden}) //invoke magic to get }; new TestClass().test()
How's this? Using an private accessor. Only allows you to get the variables though not to set them, depends on the use case.
I have one solution, but I am not sure it is without flaws.
For it to work, you have to use the following structure:
- Use 1 private object that contains all private variables.
- Use 1 instance function.
- Apply a closure to the constructor and all prototype functions.
- Any instance created is done outside the closure defined.
这里是代码:
var TestClass = (function () { // difficult to be guessed. var hash = Math.round(Math.random() * Math.pow(10, 13) + + new Date()); var TestClass = function () { var privateFields = { field1: 1, field2: 2 }; this.getPrivateFields = function (hashed) { if(hashed !== hash) { throw "Cannot access private fields outside of object."; // or return null; } return privateFields; }; }; TestClass.prototype.prototypeHello = function () { var privateFields = this.getPrivateFields(hash); privateFields.field1 = Math.round(Math.random() * 100); privateFields.field2 = Math.round(Math.random() * 100); }; TestClass.prototype.logField1 = function () { var privateFields = this.getPrivateFields(hash); console.log(privateFields.field1); }; TestClass.prototype.logField2 = function () { var privateFields = this.getPrivateFields(hash); console.log(privateFields.field2); }; return TestClass; })();
How this works is that it provides an instance function "this.getPrivateFields" to access the "privateFields" private variables object, but this function will only return the "privateFields" object inside the main closure defined (also prototype functions using "this.getPrivateFields" need to be defined inside this closure).
A hash produced during runtime and difficult to be guessed is used as parameters to make sure that even if "getPrivateFields" is called outside the scope of closure will not return the "privateFields" object.
The drawback is that we can not extend TestClass with more prototype functions outside the closure.
Here is some test code:
var t1 = new TestClass(); console.log('Initial t1 field1 is: '); t1.logField1(); console.log('Initial t1 field2 is: '); t1.logField2(); t1.prototypeHello(); console.log('t1 field1 is now: '); t1.logField1(); console.log('t1 field2 is now: '); t1.logField2(); var t2 = new TestClass(); console.log('Initial t2 field1 is: '); t2.logField1(); console.log('Initial t2 field2 is: '); t2.logField2(); t2.prototypeHello(); console.log('t2 field1 is now: '); t2.logField1(); console.log('t2 field2 is now: '); t2.logField2(); console.log('t1 field1 stays: '); t1.logField1(); console.log('t1 field2 stays: '); t1.logField2(); t1.getPrivateFields(11233);
EDIT: Using this method, it is also possible to "define" private functions.
TestClass.prototype.privateFunction = function (hashed) { if(hashed !== hash) { throw "Cannot access private function."; } }; TestClass.prototype.prototypeHello = function () { this.privateFunction(hash); };
Was playing around with this today and this was the only solution I could find without using Symbols. Best thing about this is it can actually all be completely private.
The solution is based around a homegrown module loader which basically becomes the mediator for a private storage cache (using a weak map).
const loader = (function() { function ModuleLoader() {} //Static, accessible only if truly needed through obj.constructor.modules //Can also be made completely private by removing the ModuleLoader prefix. ModuleLoader.modulesLoaded = 0; ModuleLoader.modules = {} ModuleLoader.prototype.define = function(moduleName, dModule) { if (moduleName in ModuleLoader.modules) throw new Error('Error, duplicate module'); const module = ModuleLoader.modules[moduleName] = {} module.context = { __moduleName: moduleName, exports: {} } //Weak map with instance as the key, when the created instance is garbage collected or goes out of scope this will be cleaned up. module._private = { private_sections: new WeakMap(), instances: [] }; function private(action, instance) { switch (action) { case "create": if (module._private.private_sections.has(instance)) throw new Error('Cannot create private store twice on the same instance! check calls to create.') module._private.instances.push(instance); module._private.private_sections.set(instance, {}); break; case "delete": const index = module._private.instances.indexOf(instance); if (index == -1) throw new Error('Invalid state'); module._private.instances.slice(index, 1); return module._private.private_sections.delete(instance); break; case "get": return module._private.private_sections.get(instance); break; default: throw new Error('Invalid action'); break; } } dModule.call(module.context, private); ModuleLoader.modulesLoaded++; } ModuleLoader.prototype.remove = function(moduleName) { if (!moduleName in (ModuleLoader.modules)) return; /* Clean up as best we can. */ const module = ModuleLoader.modules[moduleName]; module.context.__moduleName = null; module.context.exports = null; module.cotext = null; module._private.instances.forEach(function(instance) { module._private.private_sections.delete(instance) }); for (let i = 0; i < module._private.instances.length; i++) { module._private.instances[i] = undefined; } module._private.instances = undefined; module._private = null; delete ModuleLoader.modules[moduleName]; ModuleLoader.modulesLoaded -= 1; } ModuleLoader.prototype.require = function(moduleName) { if (!(moduleName in ModuleLoader.modules)) throw new Error('Module does not exist'); return ModuleLoader.modules[moduleName].context.exports; } return new ModuleLoader(); })(); loader.define('MyModule', function(private_store) { function MyClass() { //Creates the private storage facility. Called once in constructor. private_store("create", this); //Retrieve the private storage object from the storage facility. private_store("get", this).no = 1; } MyClass.prototype.incrementPrivateVar = function() { private_store("get", this).no += 1; } MyClass.prototype.getPrivateVar = function() { return private_store("get", this).no; } this.exports = MyClass; }) //Get whatever is exported from MyModule const MyClass = loader.require('MyModule'); //Create a new instance of `MyClass` const myClass = new MyClass(); //Create another instance of `MyClass` const myClass2 = new MyClass(); //print out current private vars console.log('pVar = ' + myClass.getPrivateVar()) console.log('pVar2 = ' + myClass2.getPrivateVar()) //Increment it myClass.incrementPrivateVar() //Print out to see if one affected the other or shared console.log('pVar after increment = ' + myClass.getPrivateVar()) console.log('pVar after increment on other class = ' + myClass2.getPrivateVar()) //Clean up. loader.remove('MyModule')
I'm just new to javascripting (I need to get acquainted with it) . I stumbled on the same question. For now I would go for a small lightweight wrapper function. This way each new instance will only reimplement the wrapper.
I think it should be something like this:
// your class function TestClass() { // your field this.privateField = "hello"; // create a local reference to this, // because 'this' in the wrapper function will not be a TestClass var self = this; // implement the wrapper function and pass the 'self' to the static version this.showHello = () => TestClass.showHello(self); } // implement the 'big/complex' functionallity static. The wrapper will pass the instance TestClass.showHello = function(self) { alert(self.privateField); }
用法:
var t = new TestClass(); t.showHello();
You could even call the static method:
TestClass.showHello(t);
Can't you put the variables in a higher scope?
(function () { var privateVariable = true; var MyClass = function () { if (privateVariable) console.log('readable from private scope!'); }; MyClass.prototype.publicMethod = function () { if (privateVariable) console.log('readable from public scope!'); }; }))();
You can also try to add method not directly on prototype, but on constructor function like this:
var MyArray = function() { var array = []; this.add = MyArray.add.bind(null, array); this.getAll = MyArray.getAll.bind(null, array); } MyArray.add = function(array, item) { array.push(item); } MyArray.getAll = function(array) { return array; } var myArray1 = new MyArray(); myArray1.add("some item 1"); console.log(myArray1.getAll()); // ['some item 1'] var myArray2 = new MyArray(); myArray2.add("some item 2"); console.log(myArray2.getAll()); // ['some item 2'] console.log(myArray1.getAll()); // ['some item 2'] - FINE!
You can use a prototype assignment within the constructor definition.
The variable will be visible to the prototype added method but all the instances of the functions will access the same SHARED variable.
function A() { var sharedVar = 0; this.local = ""; A.prototype.increment = function(lval) { if (lval) this.local = lval; alert((++sharedVar) + " while this.p is still " + this.local); } } var a = new A(); var b = new A(); a.increment("I belong to a"); b.increment("I belong to b"); a.increment(); b.increment();
I hope this can be usefull.