I'm new to javascript namespaces, and I found myself kinda deep within a namespace, but unable to find a way to navigate from within the namespace to another object in the same general namespace. It's best described by the code below:
$.fileUploading = {
images: {
settings: {
// How do you do this?
bing_bong: find.a.way.to.functionOne
},
functionOne: function() { return "Rock!"; }
}
}
Is there a way to do that?
Because namespaces are just properties on objects, there's no way to find out what object a property belongs to, from the property. A simple reason is that an identical property can appear in multiple objects.
Namespaces are supposed to be stable and constant, so there's nothing wrong with referencing the entire thing. However, if you need to access the same names a ton of times, you could make it a bit easier for yourself by assigning it to a variable.
var my_ns = $.fileUploading;
This would work:
$.fileUploading = {
images: {
settings: {},
functionOne: function() { return "Rock!"; }
}
};
$.fileUploading.images.settings.bing_bong = $.fileUploading.images.functionOne;
This also:
function f() { return "Rock!"; }
$.fileUploading = {
images: {
settings: {
// How do you do this?
bing_bong: f
},
functionOne: f
}
};
(function(){
var yourNameSpace={
publicProp1:publicFn1,
publicProp2:publicFn2,
publicProp3:publicFn3
};
window.yourNameSpace = yourNameSpace;
//private variable
var _privateVar1,_privateVar2,_privateVar3;
//privatefns
function _privateFn1(){}
function _privateFn2(){}
function _privateFn3(){}
function _privateFn4(){}
//public functions can access private fns
function publicFn1(){}
function publicFn2(){}
function publicFn3(){}
}(undefined);
Related
When creating an object to use JS in an OO manner, is there any difference within a JS engine between (with the exception of being able to define a constructor:
var Uploader = Uploader || {};
and
var Uploader = function() {
}
and
function Uploader() {
}
Especially when later, you wish to do something along the lines of
Uploader.DOM = {
Create: function(file) {
}
};
Is it all down to personal preference? Or is there a real difference?
Objects:
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
}
}
In MyObj.find function this keyword will point to MyObj (which somewhat resembles how this works in languages those have classes). You can use this functionality to do mix-ins:
var MyObj2 = {
myArr: [4,2,6]
}
MyObj2.find = MyObj.find;
In MyObj2.find function this keyword will point to MyObj2.
Also objects support getters and setters (works on IE9+ and all good browsers):
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
},
get maxValue() {
return Math.max.apply(null, this.myArr);// maxValue is calculated on the fly
},
a_: null,
get a () {
return this.a_;
},
set a (val) {
//fire a change event, do input validation
this.a_ = val;
}
}
Now max value in the array can be accessed like this: MyObj.maxValue. I also added a property a_. It can't be named the same as its getter and setter so appended an underscore. Appending or prepending underscores is a naming convention for private variables which should not be accessed directly.
var qwe = MyObj.a // get a_
MyObj.a = 'something'; //set a_
Functions:
var u = new Uploader(); // will throw an exception
var Uploader = function() { }
Uploader is defined in runtime here. It does not exist yet when I try to instantiate it.
var u = new Uploader(); //will work
function Uploader() {}
Uploader is defined in compilation time here so it will work.
Functions can be used with revealing pattern to conceal some members. Functions don't support getters and setters but you can put objects inside functions.
function myFunc() {
function privateFunc() {};
function publicFunc() {};
var obj = {
//members, getters, setters
};
return {
publicFunc: publicFunc,
obj: obj
}
}
You can call muFunc.publicFunc() outside of myFunc because it is returned. But you can not use privateFunc outside because it is not returned.
Revealing pattern functions are not meant to be instantiated usually. This is because when you instantiate it everything inside will be copied to a new instance. So it will use up more memory than if you would add functions using prototype.
myFunc.prototype.someFunc = function() {};
Like this all instances of myFunc will share the same instance of someFunc.
Conclusion: with functions you can simulate a private access modifier but in objects the this keyword acts somewhat similar of what you'd expect in a language that have classes. But you always can use call, apply and bind to change the context (i.e. what 'this' keyword will be) of the function.
Basically what I am trying to do, is to provide access to "private" functions/variables for an anonymous function. I need some opinions about two ways I achieve this and possible better alternatives to these approaches. Fiddle
Observe the following snippet.
function Something()
{
/*private*/ var _someVariable = 1;
/*private*/ function _someFunction() {
alert('_someFunction');
}
/*public*/this.SomeDelegate1 = function(codeblock) {
var members = $.extend({
_someVariable : _someVariable,
_someFunction:_someFunction
}, this);
codeblock.apply(members);
}
/*public*/this.SomeDelegate2 = function(codeblock) {
var caller = eval('(' + codeblock + ')');
caller.apply(this);
}
}
In SomeDelegate1, I convert my private members to instance members and pass it as context to the
anonymous function like seen below.
var someInstance = new Something();
someInstance.SomeDelegate1(
function() {
this._someFunction();
alert(this._someVariable);
}
);
I like the fact that one can specify which members you would like to expose, but it can potentially get quite clunky e.g. when you need to update "private" variables for example.
I can obviously write all members as instance members, but I would rather prefer them to stay "private", only allowing access within scope of the callback function.
In SomeDelegate2, I use an eval (yes I am aware of all the evils and witchcraft associated with this).
var someInstance = new Something();
someInstance.SomeDelegate2(
function() {
_someFunction();
alert(_someVariable);
}
);
Since I am injecting code into the function, the "privately" scoped members are automatically available, so I don't need to do any copying of members etc and not a lot of work needs to be done otherwise.
Is there fundamental problems with this approach?
Do you have better alternatives/approaches to achieve this?
As I said in my comment, I would make everything public and prefix "private" property names with an underscore. This is how I would restructure your code:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Something = defclass({
constructor: function () {
this._someVariable = 1;
},
_someFunction: function () {
alert("someFunction");
},
someDelegate1: function (f) {
f.apply(this);
},
someDelegate2: function (f) {
f.call(this, this._someVariable, this._someFunction);
}
});
var someInstance = new Something;
someInstance.someDelegate1(function () {
this._someFunction();
alert(this._someVariable);
});
someInstance.someDelegate2(function (someVariable, someFunction) {
someFunction();
alert(someVariable);
});
However that's just my opinion. I don't really see the point of having private variables. Even if somebody messes with your private variables, it's their problem and not yours. It'll break their code and not yours.
I was just not sure how to search this out despite many tries, so forgive me if this has been answered before.
The question is simple: can I create an instance of class window.A.class() as window.B?
To clarify, I have an object literal holding all my data for a browser game:
var gameName = {
environment: function() {
this.place = "...";
// ...
// ...
},
game: function() {
this.player = function() {
// ...
}
}
// and so on...
}
Could I create a window-level gameName.environment() instance with var A = new gameName.environment()? Are there any restrictions to creating an object-bound class's instance outside the class' parent object?
It doesn't really matter in this case how/where a function is defined. Consider these two examples:
function Foo() {}
var obj = {
bar: Foo
};
and
var obj = {
bar: function () { }
};
As far as the function and the object are concerned, those two examples are equivalent. So no, there is no problem calling a function assigned to an object property with new. All you need is a reference to the function, it doesn't matter how you get that reference.
You could do
var Environment = gameName.environment;
var A = new Environment();
if you like that better, but that's totally unnecessary.
Say I have the following modules, split across multiple files both capable of extending skillet:
File1.js:
(function(){
var privateVar1 = 0;
var privateFunction1 = function() {
//function definiton
};
skillet.fry() = function() {
//fry it
//matchbox.light();
};
})(window.skillet = window.skillet || {});
File2.js:
(function(){
var privateVar2 = 0;
var privateFunction2 = function() {
//some private function
};
skillet.grillIt = function() {
//grill It
//matchbox.strike(); <-- Shared with File1.js
};
})(window.skillet = window.skillet || {});
Is it possible to have a shared variable/object like matchbox be sharable by the two modules without being bound to window.matchbox or window.skillet.matchbox? I.e. the visibility of matchbox should only be to File1.js and File2.js and must not be accessible elsewhere. I doubt if it's possible, but is there a way to achieve such a behavior in JavaScript? If not, what's the best practice to use in this regard?
(It's more like having a shared event-bus among a set of related modules without exposing that bus globally)
Nope.
"private" variables work in JS only because of the scope that the function was declared in. There is no way to share that scope with a function declared in an entirely different scope. Scope is an unchangeable property of functions, once they are created.
This is why this sort of thing is usually done with _foo style properties.
skillet._matchbox = { strike: function() { ... } };
The underscore prefix is convention for "internal" and serves as a hint not to mess with it.
You could also get creative with how you pass matchbox around though, though in all cases it will mean providing a way to get matchbox out it's original scope. Like perhaps, makes a skillet.extend method that passes the matchbox to it's argument?
(function() {
var matchbox = { strike: function() { ... } }
window.skillet = {
extend: function(fn) {
fn(matchbox);
}
};
})();
skillet.extend(function(matchbox) {
var privateVar2 = 0;
var privateFunction2 = function() {};
skillet.grillIt = function() {
//grill It
matchbox.strike();
};
}
Which allows you to use matchbox outside it's original scope in a controlled way. But it also allows anyone to get matchbox that maybe shouldn't.
var stolenMatchbox;
skillet.extend(function(matchbox) {
stolenMatchbox = matchbox;
});
while (stolenMatchbox.count > 0) { stolenMatchbox.strike(); }
alert("Now you are outta matches, sucker!");
Since you are already dividing your code into multiple files, you may look into using a module loader like require.js. You could define a third module for the matchbox and then pass it in as an argument to the two skillets in your example above. With this approach, you won't have to globally expose the matchbox via the window.
File1.js with require.js would look like this:
define(['matchbox'], function(matchbox){
(function(){
var privateVar1 = 0;
var privateFunction1 = function() {
//function definiton
};
skillet.fry() = function() {
//fry it
matchbox.light();
};
})(window.skillet = window.skillet || {});
});
matchbox.js would look something like this:
define([], function() {
function light() {
//light implementation
}
function strike() {
//strike implementation
}
return {
light: light,
strike: strike
}
}
I'm writing a JavaScript library in which I want some methods and properties public and other private. The following seems a great way of doing this whilst wrapping everything up into a single object.
(function (window) {
var Thing = function() {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
}
}();
window.Thing = Thing;
})(window);
Thing.method();
Which is great. (Mostly grabbed from here).
However, I'd still like to be able to use the constructor of Thing to pass in some arguments.
Is there anyway I can provide a constructor in the return statement, or use prototype to override the constructor? So I can call:
Thing(stuff);
Right now, if I try that it causes:
Uncaught TypeError: Property 'Thing' of object [object DOMWindow] is not a function
Which makes sense as it's not returning itself, but ideally it'd be possible to call a constructor.
OR, is this just baaaad and I should steer clear of some or all of this?
To accomplish what you are asking, do something like this:
(function (window) {
var thingMaker= function(stuff) {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
alertStuff:function() {
alert(stuff);
}
}
};
window.thingMaker= thingMaker;
})(window);
var myThing = window.thingMaker(stuff);
myThing.alertStuff()
More information can be found by searching the googlenets for Douglas Crockford. Some great and very informative videos by him are available on yui theater. But I would have to ask, why create another framework when there are already so many great ones out there (jquery,prototype,yui,dojo to name a few)
Thing is already created, so you are always going to be too late to call a 'constructor'.
You could pass variables in like this:
(function (window, var1, var2) {
var Thing = function() {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
}
}();
window.Thing = Thing;
})(window, var1, var2);
Thing is an Object with one method called method:
{
// public method
method:function() {
alert(variable);
}
}
Thing.method(); // alerts "value"
You could return instead:
function () {
alert(arguments)
}
Then
Thing(6,5,4); // alerts 6,5,4