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
как a частный метод, так что оба они верны?
Я читал запись Дуга Крокфорда несколько раз, но не похоже, что "частные" методы могут быть вызваны публичными методами, а "привилегированные" методы могут быть вызваны извне.
29 ответов:
вы можете это сделать, но недостатком является то, что он не может быть частью прототипа:
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(); } }
вы можете имитировать частные методы следующим образом:
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
С помощью функции самостоятельного вызова и вызова
JavaScript используется прототипы и не имеет классов (или методов, если на то пошло), таких как объектно-ориентированные языки. Разработчик JavaScript должен думать в JavaScript.
Википедии цитата:
в отличие от многих объектно-ориентированных языках, нет никакого различия между определение функции и определение метода. Скорее, различие происходит во время вызова функции; когда функция вызывается как метод для объекта функция local 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
The вызов функции позволяет вызвать закрытую функцию с соответствующим контекстом (
this
).
проще с Узел.js
если вы используете узел.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 с оператором привязки
оператор связать
::
это ECMAScript предложение и выполнены в Вавилоне (этап 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
в таких ситуациях, когда у вас есть публичный 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
вот класс, который я создал, чтобы понять, что Дуглас Крокфорд предложил на своем сайте частные члены в JavaScript
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 }
Я вызвал это: EDIT: на самом деле, кто-то связался с идентичным решением. Да!
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')
Я надеюсь, это поможет кому-то лучше понять эту тему
все это закрытие будет стоить вам. Убедитесь, что вы проверяете последствия скорости, особенно в IE. Вы обнаружите, что вам лучше с Соглашением об именах. Есть еще много корпоративных веб-пользователей, которые вынуждены использовать IE6...
лично я предпочитаю следующий шаблон для создания классов в 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();
см. также эта скрипка.
Возьмите любое из решений, которые следуют за Крокфордом частная или привелигированный узор. Например:
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.
апофеоз шаблона модуля:Раскрывающий Модуль Pattern
аккуратное небольшое расширение для очень надежного шаблона.
Если вы хотите полный спектр публичных и частных функций с возможностью доступа к частным функциям для публичных функций, код макета для такого объекта:
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 () { }; }
Как насчет этого?
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".
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, но немного менее многословно (IMHO) Есть проблемы с этим способом? (Я его нигде не видел)
edit: я понял, что это бесполезно, так как каждый независимый экземпляр имеет свою собственную копию публичных методов, тем самым подрывая использование прототипа.
шаблон модуля является правильным в большинстве случаев. Но если у вас есть тысячи экземпляров, классы экономят память. Если сохранение памяти является проблемой, и ваши объекты содержат небольшое количество частных данных, но имеют много публичных функций, то вы хотите, чтобы все публичные функции жили в них .прототип для сохранения памяти.
вот что я придумал:
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. Но он также придумал новое недоразумение, "то".
Так почему же он использует "это = это"? Это не имеет никакого отношения к частным функциям вообще. Это имеет отношение к внутренним функциям!
потому что согласно Крокфорду это багги код:
Function Foo( ) { this.bar = 0; var foobar=function( ) { alert(this.bar); } }
поэтому он предложил делая это:
Function Foo( ) { this.bar = 0; that = this; var foobar=function( ) { alert(that.bar); } }
EDIT
Ах, вот в чем все дело: что означает 'var that = this;' в JavaScript?
Так кроки был действительно не прав с его объяснение....но прямо с его кодом, так что он все еще отличный парень. :))
В общем я добавил частный объект _ временно к объекту. Вы должны открыть конфиденциальность exlipcitly в" Power-constructor " для метода. Если вы вызываете метод из прототипа, вы будете иметь возможность перезаписать прототип-метод
сделать общедоступный метод доступным в "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; }; };
Это то, что я разработал:
нужен один класс из сахара код вы можете найти здесь. Также поддерживает защищенный, наследование, виртуальный, статический материал...
;( 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'
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
вы должны поставить закрытие вокруг вашего фактического конструктора-функции, где вы можете определить свои частные методы. Чтобы изменить данные экземпляров с помощью этих частных методов, вы должны дать им "это" с ними, либо в качестве аргумента функции, либо путем вызова этой функции .применить (это):
var Restaurant = (function(){ var private_buy_food = function(that){ that.data.soldFood = true; } var private_take_a_shit = function(){ this.data.isdirty = true; } // New Closure function restaurant() { this.data = { isdirty : false, soldFood: false, }; } restaurant.prototype.buy_food = function() { private_buy_food(this); } restaurant.prototype.use_restroom = function() { private_take_a_shit.call(this); } return restaurant; })() // TEST: var McDonalds = new Restaurant(); McDonalds.buy_food(); McDonalds.use_restroom(); console.log(McDonalds); console.log(McDonalds.__proto__);
вот что мне понравилось больше всего-до сих пор в отношении частных/публичных методов/членов и создания в 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();
Я знаю, что уже слишком поздно, но как насчет этого?
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"));
на этот вопрос уже есть много ответов, но ничто не соответствовало моим потребностям. Поэтому я придумал свое собственное решение, я надеюсь, что это полезно для кого-то:
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. Насколько я понял, ни один из методов, прокомментированных выше, не сделал.
посмотреть ответ для чистого и простого решения "класса" с частным и публичным интерфейсом и поддержкой композиции
Я предпочитаю хранить личные данные в связанном
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};
Не будьте так многословны. Это Javascript. Используйте Соглашение Об Именах.
после нескольких лет работы в классах es6 я недавно начал работать над проектом es5 (используя requireJS, который уже очень многословен). Я был снова и снова все стратегии, упомянутые здесь, и все это в основном сводится к используйте соглашение об именах:
- Javascript не имеет ключевых слов области, таких как
private
. Другие разработчики, входящие в Javascript будет знать это заранее. Поэтому простого соглашения об именовании более чем достаточно. Простое соглашение об именовании префикса с подчеркиванием решает проблему как частных свойств, так и частных методов.- давайте воспользуемся прототипом по причинам скорости, но давайте не будем больше многословными, чем это. Давайте постараемся, чтобы "класс" es5 выглядел как можно ближе к тому, что мы могли бы ожидать в других внутренних языках (и рассматривать каждый файл как класс, даже если нам это не нужно возвращает экземпляр).
- давайте продемонстрируем более реалистичную ситуацию с модулем (мы будем использовать старый es5 и старый requireJs).
my-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(); } */ } });