Частные методы JavaScript
Чтобы создать класс JavaScript с открытым методом, я бы сделал что-то вроде:
function Restaurant() {}
Restaurant.prototype.buy_food = function(){
// something here
}
Restaurant.prototype.use_restroom = function(){
// something here
}
Таким образом, пользователи моего класса могут:
var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();
Как создать приватный метод, который может быть вызван buy_food
а также use_restroom
методы, но не внешне пользователями класса?
Другими словами, я хочу, чтобы моя реализация метода была в состоянии сделать:
Restaurant.prototype.use_restroom = function() {
this.private_stuff();
}
Но это не должно работать:
var r = new Restaurant();
r.private_stuff();
Как мне определить private_stuff
как частный метод, так что оба они верны?
Я несколько раз читал рецензию Дуга Крокфорда, но не похоже, что "частные" методы могут быть вызваны публичными методами, а "привилегированные" методы могут быть вызваны извне.
36 ответов
Вы можете сделать это, но недостатком является то, что он не может быть частью прототипа:
function Restaurant()
{
var myPrivateVar;
var private_stuff = function() // Only visible inside Restaurant()
{
myPrivateVar = "I can set this here!";
}
this.use_restroom = function() // use_restroom is visible to all
{
private_stuff();
}
this.buy_food = function() // buy_food is visible to all
{
private_stuff();
}
}
Использование самовозвратной функции и вызова
JavaScript использует прототипы и не имеет классов (или методов в этом отношении), таких как объектно-ориентированные языки. Разработчик JavaScript должен думать на JavaScript.
Цитата из Википедии:
В отличие от многих объектно-ориентированных языков, нет различия между определением функции и определением метода. Скорее различие происходит во время вызова функции; когда функция вызывается как метод объекта, локальное ключевое слово this этой функции привязывается к этому объекту для этого вызова.
Решение, использующее функцию самозапуска и функцию вызова для вызова частного "метода":
var MyObject = (function () {
// Constructor
function MyObject (foo) {
this._foo = foo;
}
function privateFun (prefix) {
return prefix + this._foo;
}
MyObject.prototype.publicFun = function () {
return privateFun.call(this, '>>');
}
return MyObject;
})();
var myObject = new MyObject('bar');
myObject.publicFun(); // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined
Функция вызова позволяет нам вызывать приватную функцию с соответствующим контекстом (this
).
Проще с Node.js
Если вы используете node.js, вам не нужен IIFE, потому что вы можете воспользоваться системой загрузки модулей:
function MyObject (foo) {
this._foo = foo;
}
function privateFun (prefix) {
return prefix + this._foo;
}
MyObject.prototype.publicFun = function () {
return privateFun.call(this, '>>');
}
exports.MyObject = MyObject;
Загрузите файл:
var MyObject = require('./MyObject').MyObject;
var myObject = new MyObject('bar');
myObject.publicFun(); // Returns '>>bar'
myObject.privateFun('>>'); // ReferenceError: private is not defined
(экспериментальный) ES7 с оператором Bind
Оператор связывания ::
является предложением ECMAScript и реализовано в Babel ( этап 0).
export default class MyObject {
constructor (foo) {
this._foo = foo;
}
publicFun () {
return this::privateFun('>>');
}
}
function privateFun (prefix) {
return prefix + this._foo;
}
Загрузите файл:
import MyObject from './MyObject';
let myObject = new MyObject('bar');
myObject.publicFun(); // Returns '>>bar'
myObject.privateFun('>>'); // TypeError: myObject.privateFun is not a function
Вы можете смоделировать частные методы, как это:
function Restaurant() {
}
Restaurant.prototype = (function() {
var private_stuff = function() {
// Private code here
};
return {
constructor:Restaurant,
use_restroom:function() {
private_stuff();
}
};
})();
var r = new Restaurant();
// This will work:
r.use_restroom();
// This will cause an error:
r.private_stuff();
Больше информации об этой технике здесь: http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html
В этих ситуациях, когда у вас есть общедоступный API, и вам нужны частные и общедоступные методы / свойства, я всегда использую Шаблон модуля. Этот шаблон стал популярным в библиотеке YUI, а подробности можно найти здесь:
http://yuiblog.com/blog/2007/06/12/module-pattern/
Это действительно просто и легко для других разработчиков. Для простого примера:
var MYLIB = function() {
var aPrivateProperty = true;
var aPrivateMethod = function() {
// some code here...
};
return {
aPublicMethod : function() {
aPrivateMethod(); // okay
// some code here...
},
aPublicProperty : true
};
}();
MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay
Теперь вы можете сделать это с помощью частных методов es10. Вам просто нужно добавить#
перед названием метода.
class ClassWithPrivateMethod {
#privateMethod() {
return 'hello world';
}
getPrivateMessage() {
return #privateMethod();
}
}
Вот класс, который я создал, чтобы понять, что Дуглас Крокфорд предложил на своем сайте.
function Employee(id, name) { //Constructor
//Public member variables
this.id = id;
this.name = name;
//Private member variables
var fName;
var lName;
var that = this;
//By convention, we create a private variable 'that'. This is used to
//make the object available to the private methods.
//Private function
function setFName(pfname) {
fName = pfname;
alert('setFName called');
}
//Privileged function
this.setLName = function (plName, pfname) {
lName = plName; //Has access to private variables
setFName(pfname); //Has access to private function
alert('setLName called ' + this.id); //Has access to member variables
}
//Another privileged member has access to both member variables and private variables
//Note access of this.dataOfBirth created by public member setDateOfBirth
this.toString = function () {
return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth;
}
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
alert('setDateOfBirth called ' + this.id);
this.dataOfBirth = dob; //Creates new public member note this is accessed by toString
//alert(fName); //Does not have access to private member
}
$(document).ready()
{
var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
employee.setLName('Bhaskar', 'Ram'); //Call privileged function
employee.setDateOfBirth('1/1/2000'); //Call public function
employee.id = 9; //Set up member value
//employee.setFName('Ram'); //can not call Private Privileged method
alert(employee.toString()); //See the changed object
}
ES2021 / ES12 - Частные методы
Имена частных методов начинаются с хеша
#
префикс и доступен только внутри класса, в котором он определен.
class Restaurant {
// private method
#private_stuff() {
console.log("private stuff");
}
// public method
buy_food() {
this.#private_stuff();
}
};
const restaurant = new Restaurant();
restaurant.buy_food(); // "private stuff";
restaurant.private_stuff(); // Uncaught TypeError: restaurant.private_stuff is not a function
Это экспериментальное предложение. Ожидается, что версия ECMAScript 2021 будет выпущена в июне 2021 года.
Я придумал это: РЕДАКТИРОВАТЬ: На самом деле, кто-то связал с тем же решением. Duh!
var Car = function() {
}
Car.prototype = (function() {
var hotWire = function() {
// Private code *with* access to public properties through 'this'
alert( this.drive() ); // Alerts 'Vroom!'
}
return {
steal: function() {
hotWire.call( this ); // Call a private method
},
drive: function() {
return 'Vroom!';
}
};
})();
var getAwayVechile = new Car();
hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'
Я думаю, что такие вопросы возникают снова и снова из-за непонимания замыканий. Закрытие - самая важная вещь в JS. Каждый программист JS должен чувствовать суть этого.
1. Прежде всего нам нужно сделать отдельную область (закрытие).
function () {
}
2. В этой области мы можем делать все, что захотим. И никто не узнает об этом.
function () {
var name,
secretSkills = {
pizza: function () { return new Pizza() },
sushi: function () { return new Sushi() }
}
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return name in secretSkills ? secretSkills[name]() : null
}
}
3. Чтобы мир узнал о нашем ресторанном классе, мы должны вернуть его из закрытия.
var Restaurant = (function () {
// Restaurant definition
return Restaurant
})()
4. В итоге имеем:
var Restaurant = (function () {
var name,
secretSkills = {
pizza: function () { return new Pizza() },
sushi: function () { return new Sushi() }
}
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return name in secretSkills ? secretSkills[name]() : null
}
return Restaurant
})()
5. Кроме того, этот подход имеет потенциал для наследования и шаблонирования
// Abstract class
function AbstractRestaurant(skills) {
var name
function Restaurant(_name) {
name = _name
}
Restaurant.prototype.getFood = function (name) {
return skills && name in skills ? skills[name]() : null
}
return Restaurant
}
// Concrete classes
SushiRestaurant = AbstractRestaurant({
sushi: function() { return new Sushi() }
})
PizzaRestaurant = AbstractRestaurant({
pizza: function() { return new Pizza() }
})
var r1 = new SushiRestaurant('Yo! Sushi'),
r2 = new PizzaRestaurant('Dominos Pizza')
r1.getFood('sushi')
r2.getFood('pizza')
Я надеюсь, что это помогает кому-то лучше понять эту тему
Лично я предпочитаю следующий шаблон для создания классов в JavaScript:
var myClass = (function() {
// Private class properties go here
var blueprint = function() {
// Private instance properties go here
...
};
blueprint.prototype = {
// Public class properties go here
...
};
return {
// Public class properties go here
create : function() { return new blueprint(); }
...
};
})();
Как видите, он позволяет вам определять как свойства класса, так и свойства экземпляра, каждое из которых может быть открытым и закрытым.
демонстрация
var Restaurant = function() {
var totalfoodcount = 0; // Private class property
var totalrestroomcount = 0; // Private class property
var Restaurant = function(name){
var foodcount = 0; // Private instance property
var restroomcount = 0; // Private instance property
this.name = name
this.incrementFoodCount = function() {
foodcount++;
totalfoodcount++;
this.printStatus();
};
this.incrementRestroomCount = function() {
restroomcount++;
totalrestroomcount++;
this.printStatus();
};
this.getRestroomCount = function() {
return restroomcount;
},
this.getFoodCount = function() {
return foodcount;
}
};
Restaurant.prototype = {
name : '',
buy_food : function(){
this.incrementFoodCount();
},
use_restroom : function(){
this.incrementRestroomCount();
},
getTotalRestroomCount : function() {
return totalrestroomcount;
},
getTotalFoodCount : function() {
return totalfoodcount;
},
printStatus : function() {
document.body.innerHTML
+= '<h3>Buying food at '+this.name+'</h3>'
+ '<ul>'
+ '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>'
+ '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>'
+ '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>'
+ '<li>Total food count : '+ this.getTotalFoodCount() + '</li>'
+ '</ul>';
}
};
return { // Singleton public properties
create : function(name) {
return new Restaurant(name);
},
printStatus : function() {
document.body.innerHTML
+= '<hr />'
+ '<h3>Overview</h3>'
+ '<ul>'
+ '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>'
+ '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>'
+ '</ul>'
+ '<hr />';
}
};
}();
var Wendys = Restaurant.create("Wendy's");
var McDonalds = Restaurant.create("McDonald's");
var KFC = Restaurant.create("KFC");
var BurgerKing = Restaurant.create("Burger King");
Restaurant.printStatus();
Wendys.buy_food();
Wendys.use_restroom();
KFC.use_restroom();
KFC.use_restroom();
Wendys.use_restroom();
McDonalds.buy_food();
BurgerKing.buy_food();
Restaurant.printStatus();
BurgerKing.buy_food();
Wendys.use_restroom();
McDonalds.buy_food();
KFC.buy_food();
Wendys.buy_food();
BurgerKing.buy_food();
McDonalds.buy_food();
Restaurant.printStatus();
Смотрите также эту скрипку.
Все это закрытие обойдется вам. Убедитесь, что вы протестировали значения скорости, особенно в IE. Вы найдете, что вам лучше с соглашением об именах. Все еще есть много корпоративных веб-пользователей, которые вынуждены использовать IE6...
Не будь таким многословным. Это Javascript. Используйте соглашение об именах.
После нескольких лет работы в классах es6, я недавно начал работать над проектом es5 (используя requireJS, который уже очень многословен). Я перебрал все стратегии, упомянутые здесь, и все сводится к использованию соглашения об именах:
- Javascript не имеет ключевых слов области видимости, таких как
private
, Другие разработчики, входящие в Javascript, будут знать об этом заранее. Поэтому простого соглашения об именах более чем достаточно. Простое соглашение о присвоении имен с префиксом подчеркивания решает проблему как частных свойств, так и частных методов. - Давайте воспользуемся Prototype по соображениям скорости, но не будем более многословны. Давайте попробуем, чтобы "класс" es5 выглядел так же близко к тому, что мы могли бы ожидать в других языках бэкэнда (и рассматривал каждый файл как класс, даже если нам не нужно возвращать экземпляр).
- Продемонстрируем ситуацию с более реалистичным модулем (мы будем использовать старые es5 и старые requireJs).
мой-tooltip.js
define([
'tooltip'
],
function(
tooltip
){
function MyTooltip() {
// Later, if needed, we can remove the underscore on some
// of these (make public) and allow clients of our class
// to set them.
this._selector = "#my-tooltip"
this._template = 'Hello from inside my tooltip!';
this._initTooltip();
}
MyTooltip.prototype = {
constructor: MyTooltip,
_initTooltip: function () {
new tooltip.tooltip(this._selector, {
content: this._template,
closeOnClick: true,
closeButton: true
});
}
}
return {
init: function init() {
new MyTooltip(); // <-- Our constructor adds our tooltip to the DOM so not much we need to do after instantiation.
}
// You could instead return a new instantiation,
// if later you do more with this class.
/*
create: function create() {
return new MyTooltip();
}
*/
}
});
Возьмите любое из решений, которые следуют частному или привилегированному образцу Крокфорда. Например:
function Foo(x) {
var y = 5;
var bar = function() {
return y * x;
};
this.public = function(z) {
return bar() + x * z;
};
}
В любом случае, когда злоумышленник не имеет права "выполнить" в контексте JS, у него нет возможности получить доступ к каким-либо "открытым" или "закрытым" полям или методам. Если у злоумышленника есть такой доступ, он может выполнить следующую однострочную строку:
eval("Foo = " + Foo.toString().replace(
/{/, "{ this.eval = function(code) { return eval(code); }; "
));
Обратите внимание, что приведенный выше код является общим для всех конструкторов-типов-конфиденциальности. Он потерпит неудачу с некоторыми решениями здесь, но должно быть ясно, что почти все решения, основанные на замыкании, могут быть разбиты таким образом с разными replace()
параметры.
После этого выполняется любой объект, созданный с new Foo()
будет иметь eval
метод, который можно вызвать для возврата или изменения значений или методов, определенных в замыкании конструктора, например:
f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");
Единственная проблема, с которой я могу столкнуться, заключается в том, что она не будет работать в тех случаях, когда существует только один экземпляр, и он создается при загрузке. Но тогда нет никакой причины фактически определять прототип, и в этом случае злоумышленник может просто воссоздать объект вместо конструктора, если у него есть способ передачи тех же параметров (например, они являются постоянными или вычисляются из доступных значений).
На мой взгляд, это в значительной степени делает решение Крокфорда бесполезным. Поскольку "конфиденциальность" легко нарушается, недостатки его решения (сниженная читаемость и удобство обслуживания, сниженная производительность, увеличенная память) делают метод, основанный на прототипах "без конфиденциальности", лучшим выбором.
Я обычно использую ведущие подчеркивания, чтобы отметить __private
а также _protected
методы и поля (стиль Perl), но идея конфиденциальности в JavaScript просто показывает, как это неправильно понимаемый язык.
Поэтому я не согласен с Крокфордом, за исключением его первого предложения.
Так как же получить настоящую конфиденциальность в JS? Поместите все, что требуется для приватности на стороне сервера, и используйте JS для выполнения вызовов AJAX.
Если вам нужен полный спектр открытых и закрытых функций с возможностью доступа к закрытым функциям для открытых функций, создайте код для такого объекта:
function MyObject(arg1, arg2, ...) {
//constructor code using constructor arguments...
//create/access public variables as
// this.var1 = foo;
//private variables
var v1;
var v2;
//private functions
function privateOne() {
}
function privateTwon() {
}
//public functions
MyObject.prototype.publicOne = function () {
};
MyObject.prototype.publicTwo = function () {
};
}
Шаблон модуля в большинстве случаев правильный. Но если у вас есть тысячи экземпляров, классы сохраняют память. Если сохранение памяти является проблемой, и ваши объекты содержат небольшое количество личных данных, но имеют много открытых функций, то вы захотите, чтобы все открытые функции жили в.prototype для экономии памяти.
Вот что я придумал:
var MyClass = (function () {
var secret = {}; // You can only getPriv() if you know this
function MyClass() {
var that = this, priv = {
foo: 0 // ... and other private values
};
that.getPriv = function (proof) {
return (proof === secret) && priv;
};
}
MyClass.prototype.inc = function () {
var priv = this.getPriv(secret);
priv.foo += 1;
return priv.foo;
};
return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2
Предмет priv
содержит частные свойства. Это доступно через публичную функцию getPriv()
, но эта функция возвращает false
если вы не передадите secret
, и это известно только внутри основного замыкания.
Вот что мне больше всего понравилось в отношении приватных / публичных методов / членов и создания экземпляров в javascript:
вот статья: http://www.sefol.com/?p=1090
и вот пример:
var Person = (function () {
//Immediately returns an anonymous function which builds our modules
return function (name, location) {
alert("createPerson called with " + name);
var localPrivateVar = name;
var localPublicVar = "A public variable";
var localPublicFunction = function () {
alert("PUBLIC Func called, private var is :" + localPrivateVar)
};
var localPrivateFunction = function () {
alert("PRIVATE Func called ")
};
var setName = function (name) {
localPrivateVar = name;
}
return {
publicVar: localPublicVar,
location: location,
publicFunction: localPublicFunction,
setName: setName
}
}
})();
//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");
//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");
//Prints "ben"
x.publicFunction();
//Prints "candide"
y.publicFunction();
//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");
//Shouldn't have changed this : prints "candide"
y.publicFunction();
//Should have changed this : prints "Ben 2"
x.publicFunction();
Оберните весь код в анонимную функцию: тогда все функции будут частными, ТОЛЬКО функции, прикрепленные к window
объект:
(function(w,nameSpacePrivate){
w.Person=function(name){
this.name=name;
return this;
};
w.Person.prototype.profilePublic=function(){
return nameSpacePrivate.profile.call(this);
};
nameSpacePrivate.profile=function(){
return 'My name is '+this.name;
};
})(window,{});
Использовать этот:
var abdennour=new Person('Abdennour');
abdennour.profilePublic();
FIDDLE
var TestClass = function( ) {
var privateProperty = 42;
function privateMethod( ) {
alert( "privateMethod, " + privateProperty );
}
this.public = {
constructor: TestClass,
publicProperty: 88,
publicMethod: function( ) {
alert( "publicMethod" );
privateMethod( );
}
};
};
TestClass.prototype = new TestClass( ).public;
var myTestClass = new TestClass( );
alert( myTestClass.publicProperty );
myTestClass.publicMethod( );
alert( myTestClass.privateMethod || "no privateMethod" );
Похоже на georgebrock, но немного менее многословно (ИМХО) Есть какие-то проблемы с этим? (Я нигде не видел)
редактировать: я понял, что это довольно бесполезно, поскольку каждая независимая реализация имеет свою собственную копию открытых методов, что подрывает использование прототипа.
Апофеоз шаблона модуля: выявление шаблона модуля
Маленькое аккуратное продолжение очень прочного рисунка.
Как насчет этого?
var Restaurant = (function() {
var _id = 0;
var privateVars = [];
function Restaurant(name) {
this.id = ++_id;
this.name = name;
privateVars[this.id] = {
cooked: []
};
}
Restaurant.prototype.cook = function (food) {
privateVars[this.id].cooked.push(food);
}
return Restaurant;
})();
Поиск закрытой переменной невозможен за пределами непосредственной функции. Нет дублирования функций, экономия памяти.
Недостатком является то, что поиск частных переменных является неуклюжим privateVars[this.id].cooked
смешно набирать. Существует также дополнительная переменная "id".
Я предпочитаю хранить личные данные в связанном WeakMap
, Это позволяет вам хранить ваши открытые методы на прототипе, к которому они относятся. Это, кажется, самый эффективный способ справиться с этой проблемой для большого количества объектов.
const data = new WeakMap();
function Foo(value) {
data.set(this, {value});
}
// public method accessing private value
Foo.prototype.accessValue = function() {
return data.get(this).value;
}
// private 'method' accessing private value
function accessValue(foo) {
return data.get(foo).value;
}
export {Foo};
2021 ЗДЕСЬ!
Этот полифилл эффективно скрывает ваши частные свойства и методы, возвращающие undefined, когда вы пытаетесь прочитать свое частное свойство, и TypeError, когда вы пытаетесь выполнить свой частный метод, тем самым эффективно делая их оба ЧАСТНЫМИ снаружи, но предоставляя вам доступ к ним с помощью ваших общедоступных методов. .
Если вы проверите это, то увидите, что это очень легко реализовать. По большей части вам не нужно делать ничего необычного, например, использовать прокси-объекты, функции подчеркивания (_myprivate), геттеры или сеттеры. Ничего подобного. Единственное, что требуется, - это разместить в своем конструкторе такой фрагмент кода, который предназначен для того, чтобы вы могли открыть свой общедоступный интерфейс внешнему миру.
((self) => ({
pubProp: self.pubProp,
// More public properties to export HERE
// ...
pubMethod: self.pubMethod.bind(self)
// More public mehods to export HERE
// Be sure bind each of them to self!!!
// ...
}))(self);
В приведенном выше коде происходит волшебство. Это IIFE, который возвращает объект только с теми свойствами и методами, которые вы хотите предоставить и привязанными к контексту объекта, который был создан первым.
Вы по-прежнему можете получить доступ к своим скрытым свойствам и методам, но только через свои общедоступные методы, как и должно быть в ООП.
Считайте эту часть кода своим module.exports
Кстати, это без использования последнего дополнения ES6 "#" к языку.
Уродливое решение, но оно работает:
function Class(cb) {
const self = {};
const constructor = (fn) => {
func = fn;
};
const addPrivate = (fnName, obj) => {
self[fnName] = obj;
}
const addPublic = (fnName, obj) => {
this[fnName] = obj;
self[fnName] = obj;
func.prototype[fnName] = obj;
}
cb(constructor, addPrivate, addPublic, self);
return func;
}
const test = new Class((constructor, private, public, self) => {
constructor(function (test) {
console.log(test)
});
public('test', 'yay');
private('qwe', 'nay');
private('no', () => {
return 'hello'
})
public('asd', () => {
return 'this is public'
})
public('hello', () => {
return self.qwe + self.no() + self.asd()
})
})
const asd = new test('qweqwe');
console.log(asd.hello());
Старый вопрос, но это довольно простая задача, которую можно правильно решить с помощью основного JS... без абстракции класса ES6. На самом деле, насколько я могу судить, абстракция класса даже не решает эту проблему.
Мы можем выполнить эту работу как с помощью старой доброй функции конструктора, так и, что еще лучше, с помощью. Сначала займемся конструктором. По сути, это будет решение, аналогичное ответу Джорджброка, который подвергается критике, потому что все рестораны, созданные
Restaurant
конструктор будет иметь такие же частные методы. Я постараюсь преодолеть это ограничение.
Теперь очевидно, что мы не можем получить доступ
menu
извне, но мы можем легко переименовать
name
собственность ресторана.
Это также можно сделать с помощью
Object.create()
в этом случае мы пропускаем функцию конструктора и просто делаем как
var rest = Object.create(prototypeFactory(menu))
и добавьте свойство name в
rest
объект впоследствии как
rest.name = name
.
Это то, что я разработал:
Требуется один класс кода сахара, который вы можете найти здесь. Также поддерживает защищенные, наследования, виртуальные, статические вещи...
;( function class_Restaurant( namespace )
{
'use strict';
if( namespace[ "Restaurant" ] ) return // protect against double inclusions
namespace.Restaurant = Restaurant
var Static = TidBits.OoJs.setupClass( namespace, "Restaurant" )
// constructor
//
function Restaurant()
{
this.toilets = 3
this.Private( private_stuff )
return this.Public( buy_food, use_restroom )
}
function private_stuff(){ console.log( "There are", this.toilets, "toilets available") }
function buy_food (){ return "food" }
function use_restroom (){ this.private_stuff() }
})( window )
var chinese = new Restaurant
console.log( chinese.buy_food() ); // output: food
console.log( chinese.use_restroom() ); // output: There are 3 toilets available
console.log( chinese.toilets ); // output: undefined
console.log( chinese.private_stuff() ); // output: undefined
// and throws: TypeError: Object #<Restaurant> has no method 'private_stuff'
Я знаю, что уже слишком поздно, но как насчет этого?
var obj = function(){
var pr = "private";
var prt = Object.getPrototypeOf(this);
if(!prt.hasOwnProperty("showPrivate")){
prt.showPrivate = function(){
console.log(pr);
}
}
}
var i = new obj();
i.showPrivate();
console.log(i.hasOwnProperty("pr"));
В общем, я временно добавил приватный объект _. Вы должны открыть конфиденциальность в "Power-constructor" для метода. Если вы вызовете метод из прототипа, вы сможете перезаписать метод prototype
Сделайте публичный метод доступным в "Power-constructor": (ctx - контекст объекта)
ctx.test = GD.Fabric.open('test', GD.Test.prototype, ctx, _); // is a private object
Теперь у меня есть эта openPrivacy:
GD.Fabric.openPrivacy = function(func, clss, ctx, _) { return function() { ctx._ = _; var res = clss[func].apply(ctx, arguments); ctx._ = null; return res; }; };
Class({
Namespace:ABC,
Name:"ClassL2",
Bases:[ABC.ClassTop],
Private:{
m_var:2
},
Protected:{
proval:2,
fight:Property(function(){
this.m_var--;
console.log("ClassL2::fight (m_var)" +this.m_var);
},[Property.Type.Virtual])
},
Public:{
Fight:function(){
console.log("ClassL2::Fight (m_var)"+this.m_var);
this.fight();
}
}
});
Я создал новый инструмент, который позволит вам иметь настоящие личные методы на прототипе https://github.com/TremayneChrist/ProtectJS
Пример:
var MyObject = (function () {
// Create the object
function MyObject() {}
// Add methods to the prototype
MyObject.prototype = {
// This is our public method
public: function () {
console.log('PUBLIC method has been called');
},
// This is our private method, using (_)
_private: function () {
console.log('PRIVATE method has been called');
}
}
return protect(MyObject);
})();
// Create an instance of the object
var mo = new MyObject();
// Call its methods
mo.public(); // Pass
mo._private(); // Fail
На этот вопрос уже есть много ответов, но ничто не соответствовало моим потребностям. Поэтому я придумала собственное решение, надеюсь, оно кому-нибудь пригодится:
function calledPrivate(){
var stack = new Error().stack.toString().split("\n");
function getClass(line){
var i = line.indexOf(" ");
var i2 = line.indexOf(".");
return line.substring(i,i2);
}
return getClass(stack[2])==getClass(stack[3]);
}
class Obj{
privateMethode(){
if(calledPrivate()){
console.log("your code goes here");
}
}
publicMethode(){
this.privateMethode();
}
}
var obj = new Obj();
obj.publicMethode(); //logs "your code goes here"
obj.privateMethode(); //does nothing
Как вы можете видеть, эта система работает при использовании этого типа классов в JavaScript. Насколько я понял, ни один из методов, упомянутых выше, не сделал.