Страницы

Поиск по вопросам

среда, 29 января 2020 г.

Приватные свойства в js

#javascript


Я не знаю как правильно сказать, но как сделать свойство, которое было бы не видно
внешне, но было бы видно методам установленных через прототип? Вот типа -

var Class = function(){
    var _array = []; // приватное или протектед свойство
};

Class.prototype.method = function(){
    // как обратиться здесь к _array?
};

Возможно такое сделать из коробки?    


Ответы

Ответ 1



Средства языка такого, насколько я знаю, не предоставляют. Поэтому javascript-еры договорились, что все свойства которые начинаются со знака нижнего подчеркивания '_' являются приватными. В вашем случае: var Class = function(){ this._array = []; // приватное или протектед свойство }; Class.prototype.method = function(){ // как обратиться здесь к _array? this._array }; var instance = new Class(); instance._array.push('string') // но мы то знаем, что так делать нельзя Update Появилась идея. Шифровать имя свойства и делать его enumerable. Костыль: var prive = function (that, propName, newValue) { var decodeStr = function (str) { return Array.prototype.map.call( str, function (char, i) { return String.fromCharCode(str.charCodeAt(i)-5) }).join(''); }, decodedPropName = decodeStr(propName); if (arguments.length >= 3) { // set private property Object.defineProperty(that, decodedPropName, { enumerable: false, writable: true, value: newValue, }); } else { //get private property return that[decodedPropName]; } } Демонстрация

Ответ 2



Оберните класс в анонимную функцию, воспользовавшись ограниченной областью видимости для приватных свойств. (function(){ var private_method = function(){}; // приватный метод не будет виден снаружи var private_property = 'ololo'; // приватное свойство var Class = function(){}; Class.prototype.public_method = function(){ // паблик метод var x = private_method(private_property); // приватные свойства и методы можно использовать здесь }; window.Class = Class; // выносим класс в общую область видимости })(); jsfiddle

Ответ 3



Я этот вопрос решал вот так: (function (exports) { /* * sample prototype, * * inherit @boolean if true - return privates object, * */ function A(inherit) { var privates = { //setup private vars, they could be also changed, added in method or children a: 1, b: 2, c: 3 }; //setup public methods which uses privates this.aPlus = bindPlus("aPlus", this, privates); //pass method name as string! this.aGet = bindPlus("aGet", this, privates); if (inherit) { return privates; } } A.prototype.aPlus = function () { var args = getArgs(arguments), //self is "this" here (applied/called too), object reference is still this privates = args.shift(), self = args.shift(), //function real arguments n = args.shift(); return privates.a += n; }; A.prototype.aGet = function (n) { var args = getArgs(arguments), privates = args.shift(), self = args.shift(); console.error(this, self,privates); return privates.a; }; exports.A = A; exports.getArgs = getArgs; //should be hidden somehow, but this is out of the story exports.bindPlus = bindPlus; //utilites function getArgs(arg) { return Array.prototype.slice.call(arg); } //вот здесь в общем-то ядро идеи function bindPlus(funct, self, privates) { /** * if uncomment here and comment same line later, * it will be run faster, but it would be impossible * to change prototype after constructor run (tests after ----- could be incorrect) */ //var func=Object.getPrototypeOf(self)[funct].bind(self, privates); return function () { var func=Object.getPrototypeOf(self)[funct].bind(self, privates); var args=getArgs(arguments); //this could be changed to speedup, but need to change method itself args.unshift(this); //called/applied this return func.apply(null, args); }; } })(this); //inherited function B(inherit) { var privates = Object.getPrototypeOf(this).constructor.call(this, true); privates.d = 4; this.dGet = bindPlus("dGet", this, privates); if (inherit) { return privates; } } B.prototype = Object.create(A.prototype); B.constructor = B; B.prototype.aGet = function () { var args = getArgs(arguments); var privates = args.shift(), self = args.shift(); console.warn("B.aGet",self, privates); return privates.a; }; B.prototype.dGet = function () { var args = getArgs(arguments), privates = args.shift(); self = args.shift(), console.warn("B.dGet", self, privates); return privates.d; }; но это немного тормозно и неудобно, лучшего способа не нашел, чтобы работало. http://jsfiddle.net/oceog/TJH9Q/

Ответ 4



Ну раз тут уже толпа, внесу лепту, так сказать. Вкратце - из глобальной области видимости исключается один объект _this, который и содержит все приватные поля-методы. Плюсы - прозрачность и вроде даже удобство. var MyClass = function() { var _this = {}; // private container _this.private1 = 0; // private var 1 _this.private2 = 1; // private var 2 _this.incPrivate = function() { // private function _this.private1++; _this.private2++; }; this.public1 = 2; // public var 1 this.public2 = 3; // public var 2 this.logPrivate = function() { // public function console.log(_this); return this; }; this.incPublic = function() { // public function this.public1++; this.public2++; return this; }; this.proxyIncPrivate = function() { // public function / proxy _this.incPrivate(); return this; }; this.logPublic = function() { // public function console.log(this); return this; }; } var MyInstance = new MyClass(); jsfiddle UPDADE Заморочился я тут и сделал реализацию для основных типов свойств в JS. не в курсе, что там с памятью, но по работе оно стало похоже на нормальные языки :) (function() { var _class = { // доступно в объекте и прототипе, // один экземпляр (изменяется отовсюду) // недоступно из глобальной области видимости privateStatic1: 0, privateStatic2: 1, privateStaticMethod: function() { console.log('called private static method'); } } var MyClass = function() { var _this = { // доступно только из методов объекта, // изменяется только объект // недоступно из глобала и класса private1: 2, private2: 3, privateMethod: function() { console.log('called private method'); } }; // доступно отовсюду после создания объекта, // изменяется только объект // недоступно из глобала и класса this.public1 = 4; this.public2 = 5; this.publicMethod = function() { console.log('called public method'); }; }; // доступно отовсюду, // один экземпляр // дублирование для возможности вызова через MyClass без создания объекта MyClass.prototype.publicStatic1 = 6; MyClass.publicStatic1 = MyClass.prototype.publicStatic1; MyClass.prototype.publicStatic2 = 7; MyClass.prototype.publicStatic2 = MyClass.prototype.publicStatic2; MyClass.prototype.publicStaticMethod = function() { console.log('called public static method'); } MyClass.publicStaticMethod = MyClass.prototype.publicStaticMethod; window.MyClass = MyClass; })(); http://jsfiddle.net/ux95ub87/1/ + консольный вывод результатов всех вызовов.

Комментариев нет:

Отправить комментарий